Swift OC 混编

Swift接入

OC use Swift method

  1. 将Swift导入OC
#import "ProductModuleName-Swift.h"

ProductModuleName-Swift.h文件中包含了.swift文件中的声明等。

  1. Include Swift Classes Using Forward Declarations
@class MySwiftClass; // in .h

#import "ProductModuleName-Swift.h" // in .m
  1. 使用@objc暴露函数给OC 或者 使用@objcMembers暴露整个类给OC

  2. 如果是在开发一个library, 大概率CocoaPods已经为你生成了ProductModuleName-Swift.h文件, 你使用的时候手动import这个文件:#import <MyOpenSDK/MyOpen-Swift.h>

Swift use OC method

  1. 创建桥接头文件 首次添加Swift时会提示增加bridging header
  2. 转化宏定义

Swift只支持简单的数值宏定义,函数式等复杂的宏定义不支持,需要一个中间类转化一下,创建一个中间类 KBSwiftConstant.swift, 如下:

+ (CGFloat)ScreenWidth{
    return SCREEN_WIDTH;
}

Swift中不建议使用宏,简单的可以使用let,复杂的宏可以使用静态函数内联函数generics等。

Attention

  1. bridging header分模块
  2. class delete 关键字
  3. 没有nullable修饰符的OC属性会默认转化为swift的隐式可选型(!),系统不会提示加?解包,解包时需注意,如果属性值可能为空,需要在属性末尾加?,例如:self.property?.property
  4. 初始化方法
    • 初始化函数需要使每个属性都有初始值,optional类型自动初始值为nil
    • 不自动集成父类构造函数,原因为子类集成父类的构造函数容易导致初始化不全面,即不符合条件(1)
    • 执行顺序规范
    • convinence init
  5. Swift不识别OC自动生成的setter方法,直接对属性赋值,即可调用到setter方法
  6. 单例, 仅在定义全局变量时将其构造器标志为 private,即可自动使用 dispatch_once 进行初始化,保证原子性

先给自己的属性赋值再super.init(),

  • 等于init方法一进来就已经有self了
  • 这也是为什么不需要返self的原因
class childClass: fatherClass {
    var childProperty:Any?
    init(childProperty:Any?){
        self.childProperty = childProperty
        super.init()
        self.fatherProperty = ...
    }
}

自定义初始化参数,需要符合以下原则:

  • convinence init函数中需调用当前类中其他初始化函数
  • designated init函数中需调用父类的designated init函数
  • convinence init需要最终调用到designated init函数
class MyManager {
    // 全局变量
    static let shared = MyManager(string: someString)
    let string: String
    private init(string: String) {
        self.string = string
    }
}
// 使用方法:
MyManager.shared.method()

Enums

OC只认Swift里定义的Int类型枚举, 并且扩展的属性, 方法, 及associate data等都无法读取(定义的时候就报错了). 并且需要标识上@objc

case login(username: String, password: String)
// 更简单的(但就丧失了可读性):
case login(String, String)

这种枚举, 在取数值的时候以下两种写法都可以:

case let .login(username, password):
case .login(username: let username, password: let password):
// 没有名字的, 就要在switch的时候自行解包:
// 1. 比每一个形参都加let要简洁很多, 但比直接把let提取到最外面的写法是一样的
// 2. 在case的时候自定义形参名, 意思是编辑的时候是没有智能提示的(反而会瞎提示)
case let (username, password):
case .login(let username, let password):

而OC里的枚举, 会根据写法在Swift里映射成不同的类型, 参考这篇笔记混编中的枚举