Swift混编

OC与Swift混编(基于Swift 4.1)

1、在OC项目中,新建一个swift文件后会提示要不要自动新建Bridging_Header,由于项目中存在多个target,自动新建会新建多个,所以不是很推荐这种方式,自己新建也很方便,新建header file后,在Build Settings -> Swift Compiler - general -> Objective-C Bridging Header中写入即可,然后在Objective-C Bridging Header的下方有一栏Objective-C Generated Interface Header Name是系统生成的文件,固定格式为项目名-Swift.h

  • Bridging_Header文件可以理解为swift版本的PCH文件,但只能给swift文件使用,由于swift文件无法直接importOC文件,混编时,需要在Bridging_Header中import好OC类;
  • 项目名-Swift.h这个文件是OC调用swift类需要用到的,同理上一条,OC中也是无法直接importswift的,但是可以import这个文件,并且项目名-Swift.h也是不需要我们自己维护,只要OC中import了该文件,就可以直接使用了,所以我是把项目名-Swift.h放在了OC的PCH中。

2、(重要)网上混编的文章都是通过demo来演示的,并没有实际项目中复杂且各种父类宏的使用,所以在说完第一点之后就直接开始编写了,并没有提到可能会遇到的坑,我虽然只修改了一个VC,但总结下来的话也有下面几点:

  • Bridging_Headerimport是没有提示的!!!
  • Bridging_Headerimport是不会加载被import文件中的其他类,如果用到需要另外再import
  • Bridging_Header中被import的OC文件一定要确保用到的类被正确import,否则会报文件未找到;
  • 由于Swift无法公用OC的宏定义,所以还要确保在Bridging_Header中被import的.h文件没有用到OC的宏定义,例如通用的block回调之类。

在写代码过程中,可能会遇到系统提示fix给参数添加了? ! ??之类的字符。

可选值

打包wrap(?)

表示有值或者为空。Eg: var name : String? 表示name可能有值也可能为空,可以理解为可选值类型是一个盒子,这个盒子有有值和无值两种情况,也就是可选值变量对有值或无值进行了打包操作。

var a :Int?
var b :Int

虽然都是Int类型,但实际上a和b是不一样的,a属于可选Int类型,b属于Int类型

  • eg:
var aaa: Int? = 30
print(aaa)

会报一个Expression implicitly coerced from 'Int?' to Any的警告,意思是把可选值类型隐式地强制转换成任意类型来处理,可修改为print(aaa as Any)消除警告。
但这并不好,因为还有隐患

print(aaa + 1)

这样更能直白的表示出可选值和非可选值的区别,会直接报错:Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?,提示没有对Int?进行解包unwrapped,且直接对可选类型做了加一操作,Swift是强类型语言,在编译阶段就为我们排除了很大一部分的类型不匹配的错误,例如OC中int和float类型相加并不会报错隐式类型转换,而在Swift中则不行,所以这里相当于是将可选值的盒子进行了加一的操作,而不是对可选值盒子中的内容进行加一,就报错了。

解包Unwarpping optionals

既然有打包,那么肯定就有解包,就是把值从盒子内取出来

  • 1、强制解包Force unwrapping(!)

针对上面的例子

print(aaa! + 1)

这样就解包了,变量名后的感叹号告诉编译器,我想看下盒子里面的内容并取出来里面的值,但是,使用强制解包应该谨慎的使用。
还是针对上面的例子,由于aaa被定义为可选值变量,在使用过程中可能会置换为nil

var aaa: Int? = 30
aaa = nil
print(aaa! + 1)

这样就会报错Fatal error: Unexpectedly found nil while unwrapping an Optional value,错误原因是对一个值为空的变量进行了解包,当然可以在每次解包的时候判断是否为nil,但这无疑是增加了自己的代码及工作量,并且如果万一忘记了的话,程序还是会崩溃。
所以对于强制解包,推荐是只有在确定不为空的情况下才使用的

  • 可选值绑定Optional binding(iflet)
var aaa: Int? = 30
aaa = nil
if let bbb = aaa {
    print(bbb + 1)
} else {
    print("no")
}

上面的代码使用了iflet表达式来进行了绑定,如果可选值内容不为空,那么就会被解包,并且let的常量名可定义为相同的,如:

var aaa: Int? = 30
aaa = nil
if let aaa = aaa {
    print(aaa + 1)
} else {
    print("no")
}
  • 空值合并Nil coalescing(??)
var aaa: Int? = 30
aaa = nil
var bbb = aaa ?? 20
print(bbb + 1)

这也是一种解包,叫做空合运算符,类似于三目运算符,上面??的意思表示如果aaa不为nil,那么就将aaa的值给bbb,否则将bbb赋值为20。

你可能感兴趣的:(Swift混编)