Swift和OC混编中的一些注意事项及问题

Swift和OC混编中的一些注意事项及问题

混编头文件的导入

Swift引用OC

在桥接文件中导入OC头文件即可 #import “xxx.h”

注意事项:

  • OC中的类直接或间接继承制NSObject

  • 暴露给Swift的所有属性和函数前面都要加上 @objc

OC引用Swift

导入头文件 #import "项目名-Swift.h"(此文件由系统生成,如果用户自定义可以再 build settings 中的 packaging -> Product Modular Name中找到)

oc类在使用swift类时,该swift类必须继承于oc类

swift中没有宏,可以使用全局常量、全局函数代替部分宏

swift中是不能使用宏定义语法,但是因为命名空间的缘故,在其中,我们将原本oc中不需要接受参数的宏,定义成let常量或枚举,将需要接受参数的宏定义成函数。 ⚠️横屏后kScreenHeight及kScreenWidth是不会变化的,因为是常量,只会赋值一次。OC中则会实时变化,因为不是赋值,是宏替换。 ⚠️ 这里定义的常量oc中并不能使用,可以定义一个类,然后将所有的全局变量和常量改成这个类的属性。

如oc的宏:

1
2
 #define kScreenHeight     [UIScreen mainScreen].bounds.size.height
 #define kScreenWidth      [UIScreen mainScreen].bounds.size.width

在swift中定义为全局常量:

1
2
let kSCREEN_HEIGHT = UIScreen.main.bounds.height
let kSCREEN_WIDTH = UIScreen.main.bounds.width

swift枚举类型在oc中使用

如果需要在oc类中使用时只能使用带@objc的枚举,带@objc的枚举必须时Int类型,否则会报错。

1
2
3
4
5
6
@objc enum Direction: Int {
    case Up
    case Down
    case Left
    case Right
}

只有像上面定义的Swift枚举才能在oc类中使用。

swift中使用oc的NS_OPTIONS类型枚举

swift中没有“ ”,如,下面写法是错误的
1
let options : NSStringDrawingOptions = .UsesLineFragmentOrigin | .UsesFontLeading

可以直接写成

1
let options : NSStringDrawingOptions = [.UsesLineFragmentOrigin, .UsesFontLeading]

注:swift中与NS_OPTIONS相似的是struck实现 OptionSet 协议。

oc使用swift定义的协议

如果要在oc中使用swift定义的协议,则需要加上@objc,且如果是不必实现的函数,函数前要加上 @objc optional。

1
2
3
4
@objc protocol AlertViewProtocol {
    func submit(_ row: Int) //必须实现的协议
    @objc optional func cancel() //不必实现的协议
}

其他swift中有而oc中没有的

  1. 元组:对于oc可能用到的:方法,返回不能是元组,参数能不能是元组。属性不能是元组。
  2. 范型(Generics)范型
  3. Swift 中定义的结构体(Structures defined in Swift)不能在oc中使用,OC中必须继承NSObject(OC不能使用Swift结构体)
  4. Swift 中定义的高阶函数(比如filter, map等)
  5. Swift 中定义的全局变量(Global variables defined in Swift)
  6. Swift 中定义的类型别名(Typealiases defined in Swift)
  7. Swift风格可变参数(Swift-style variadics)
  8. 嵌套类型(Nested types)
  9. 柯里化函数(Curried functions)

这里稍微解释一下柯里化在计算机科学中,柯里化(Currying),又译为卡瑞化或加里化,是把接收多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数,并返回接受剩余的参数而且返回结果的新函数的技术, 简而言之其实质就是闭包的概念,如下两个函数

1
2
3
4
5
6
7
8
9
10
11
//原始换函数
func add(_ a:Int, b:Int) -> Int {
    return a + b
}

//柯里化
func add(_ a:Int) -> (Int)->Int {
    return { b in
        return a + b
    }
}

调用方式如下:

1
2
3
add(1, b: 2)

add(1)(2)

常见问题:

swift类可以继承oc类,oc类不能继承swift类

1. Swift通过cocoapods导入OC的三方框架, 在Swift中找不到这个类

  • 1.Target -> Search paths -> User Header Search Paths

  • 2.新增一个值 ${SRCROOT} , 并且选择 Recursive (意思是在根目录递归查找)

2.在OC引用Swift文件时, 导入 项目名-Swift.h 文件时, 报找不到文件的错

原因: 桥接文件的路径没有配置正确:

  • 1.Build Settings -> 搜索 Bridging -> Objective-C Bridging Header -> 配置路径

  • 2.配置路径的方法: 项目名/桥接文件的名称 (如果桥接文件有多层物理目录, 就是 项目名/物理目录/桥接文件的名称)