从OC到Swift(一)

开篇

在简单的学习了swift语法之后,开始在项目里使用。很多东西都是别人铺好路,自己只是套用写UI而已。这里先简单过渡一下OC-Swift,后续再深入研究Swift相关知识。

Swift与OC如何互相调用

大部分项目应该都是要从OC过渡到Swift,这就避免不了混编,这里涉及到两个桥接头文件:

1. Swift调用OC {targetName}-Bridging-Header.h

作用:Swift可调用OC,在此文件中import OC的头文件

在OC工程中创建swift文件时会有此提示,点击create Xcode会帮我们生产此文件。

image.png

并且在Targets-->Build Settings-->Swift Compiler - General-->Objective-C Bridging Header有配置路径。如果工程里没有此文件,我们可以手动创建,并且在这里配置一下,不过注意的是文件名字必须为上述格式{targetName}-Bridging-Header.h
image.png

2. OC调用Swift 一般为{targetName}-swift.h

在上面图中我们看到Objective-C Generated Interface Header Name 这里也有一个配置的文件路径,这里就是让OC可与调用Swift。需要调用swift的地方,import这个文件就可以。
名字为什们说一般为{targetName}-swift.h呢?当targetName中存在-这种情况,需要变_。 例如targetNameOC-Swift,这个头文件的名字应该是OC_Swift-Swift.h。这个文件内是swift编译生成的对应OC代码。
这个文件在工程内不能直接看到,编译后,可以通过Command+单击该文件名,就会看到具体生成的代码。

需要注意的是:
  • 在OC里如果想要调用Swift,需要在被访问的类,属性,方法前面加上@objc,并且如果是类,需要继承NSObject,否则编译也会报错。
    @objc class TestSwiftClass: NSObject { }
  • 这就又有问题了,如果一个类特别复杂都需要暴露给OC,那不是得写好多@objc?这时候可以使用@objcMembers, 这样类、类中的所有属性、方法都暴露给OC可以直接调用。
    @objcMembers class Car: NSObject { }
  • 我们还可以给swift属性、方法重新定义供OC使用的名字
@objc(realName)
var name: String; 
@objc(ocRun)
func run() {
}

以上整体下来示例:

//swift中写法
@objcMembers class TestSwiftClass: NSObject {
    @objc(realName)
    var name: String;
    var age: Int;
    init(name:String, age:Int) {
        self.name = name
        self.age = age
    }
    @objc(ocRun)
    func run() {
        
    }
}
//OC中调用
- (void)viewDidLoad {
    [super viewDidLoad];

    TestSwiftClass *obj = [[TestSwiftClass alloc]initWithName:@"zhangsan" age:12];
    obj.age = 11;
    obj.realName = @"ZhangSan";
    [obj ocRun];
}
  • 我们上面会发现swif中定义的init方法init(name:String, age:Int),而OC里面调用还是我们熟悉的样子TestSwiftClass *obj = [[TestSwiftClass alloc]initWithName:@"zhangsan" age:12];
    而且OC里面的方法 - (instancetype)initWithTitle:(NSString *)title;到Swift中调用的时候是let obj = TestOCClass(title: "title")
    这里是xcode帮我做了优化,生成对应风格的代码。
这里有个坑,就是你可能会发现在swift中无法调用一些OC的单例创建方法,比如 + (instancetype)manager, 或者+(instancetype)shareManager。后来发现需要定义一些标准名字比如default singleton shared 。不过这个问题应该在只存在某几个版本的Xcode中,目前发现Xcode11.3没有这个问题

以上大概就已经做好混编的基础了。

Selector的使用

在OC里面我们经常使用@selector(name),在swift里面只是把@替换#,例:#selector(name)

  • 注意的是,必须是被@objcMembers或@objc修饰的方法才可以定义选择器。
    为什么呢?我们可以想一下@selector(name)是依赖OC的runtime,纯swift是没有runtime的,所以既然要使用方法选择器,说明需要用到runtime,所以需要通过关键字桥接到OC。当然在swift里面也可以调用perform(#selector(name))

String的区别

我们发现swift中的String在OC中会自动转换为NSString。但是Swift中的String的用法确与OC相差很大。在系统学习之前,我两个月都没用明白(但是不能承认自己笨。嗯!咳)。
关于字符串拼接之类的就不多说了,主要说一下关于String的Index。
String的下标(Index)并不是int类型,而是String.Index,Index是个结构体


image.png

虽然他不是整形,但是他一样代表着位置。关于String类型的一些方法,.startIndex/.endIndex!,例:name.startIndex/name.endIndex代表是起始位置(第一个字符的位置)/最后位置(最后一个字符的下一位)
关于String的一些插入删除方法:

//插入
var str = "a-b"
// 插入单个字符,最后一个位置插入‘-’,结果:a-b-
str.insert("-", at: str.endIndex)
// 插入字符串使用contentsOf:末尾插入c-d,结果:a-b-c-d
str.insert(contentsOf: "c-d", at: str.endIndex)
// after:str.startIndex,在第一个字符的后一位,结果:a666-b-c-d
str.insert(contentsOf: "666", at: str.index(after: str.startIndex))
// before:str.endIndex,在末尾的前一位,也就是最后一个字符的位置插入,从插入位置起,原字符都顺位后移,结果:a666-b-c-888d
str.insert(contentsOf: "888", at: str.index(before: str.endIndex))
// offsetBy:可以指定偏移量,从开始向后偏移3,也就是第三个6的位置,插入后,原字符顺位后移,结果  a66hello6-b-c-888d
str.insert(contentsOf: "hello", at: str.index(str.startIndex, offsetBy: 3))

//删除
//删除第一个'-' 结果:a66hello6b-c-888d
str.remove(at: str.firstIndex(of: "-")!)
//删除所有,符合闭包条件的所有值。结果ahellob-c-888d
str.removeAll { $0 == "6" }

还有其他的关于range的方法,就不在这罗列了,明白了上面这些关于String.Index的使用,其他的基本一样了。

Substring

String可以通过下标、 prefix、 suffix等截取子串,但是子串类型不是String,而是Substring。String本身就是个结构体,不能被继承。Substring也就不是什么子类之类的。他一样也是个结构体。

  • Substring 是字符串的一部分,和父字符串共享同一块内存空间,并且记录了自己的开始和结束位置。
  • String 和 Substring 都声明实现了 StringProtocol。StringProtocol 包含了一个字符串的基本属性和功能。
  • Substring发生修改 或者 转为String时,会分配新的内存存储字符串数据
    具体细节,大家自行Google吧。

你可能感兴趣的:(从OC到Swift(一))