swift3.0和Objective-C的交互需要注意这些

前言:

swift3.0出来后, 可以看到改变很大, 和cocoa, Foundation...的交互也变得更方便了, 同时swift编写的应用适配到iOS7, 所以, 我们可以相信: 在未来使用swift的情况会逐渐增加了, 同时会涉及到oc和swift在项目中并存的情况, 这里我重新读了官方的'Using swift with Cocoa and Objective-C(swift3)'的文档, 记录了一些个人觉得比较常用的笔记, 请大家选择性阅读(里面的代码 均来自文档)

  1. oc的初始化方法在swift中被引为
    init(...) --- 如果初始化不会失败
    init?(...) --- 如果初始化可能失败
    init!(...) --- 否则
  • oc中的property里的(getter==, setter==)将会被swift忽略
  • id对应Anyobject 但是所有的Anyobject在swift中是可选值, 如果之前的值为可选值, 在被设置为Anyobject后就是多重可选值了
  • oc中的属性被标记为
    nullable -> 在swift中相当于 ?
    nonnull -> 在swift中相当于 非可选属性
    未标记 -> 在swift中相当于 !
  • oc中的轻量级泛型也是对应与swift中的泛型
    @property NSArray<NSDate *> *dates
    对应于 var dates: [Date]
  • swift 中的闭包默认捕获变量的方式相当于 oc中block中捕获被标记为 __block的变量方式 -> 就是说 闭包捕获到的是变量的指针
  • swift中只要不是在多线程中, 建议使用[unowned self]来避免循环引用, 多线程中, 建议使用[weak self]
  • == 操作符相当于oc中的isEqual: --- 即比较内容是否相等
    === 相当于oc中的指针比较
  • 继承自NSObject的子类如果重写了isEquals: 方法, 应当提供 hash 这个属性
  • 不能在oc中继承swift的class
  • 如果在swift中遇到oc中不支持的命名 可以利用 @objc(name)为他(属性 枚举, 方法名...)名个别名
  • @nonobjc 用来标记oc中不支持的
  • dynamic 将属性或者方法标记为dynamic就是告诉编译器把它当作oc里的属性或方法来使用(runtime),
    当需要使用 KVO 或者 runtime的时候需要这样处理
  • 当使用oc的 perform(selector, with:)方法的时候 会返回一个可选值(指向AnyObject的指针)
    但是使用perform(:on:with:waitUntilDone:modes:) and perform(:with:afterDelay:)不会返回可选值
  • 使用 #keyPath() 可以转换为string, #keyPath(class.property) == "property"
    可用于KVC 例如person.value(forKey: #keyPath(Person.name)) = person.name
    但是测试了下不能修改swift中的只读属性 不知道有什么方便的用处
  • NSClassFromString("MyFramework.MyClass")
  • @IBDesignable 用在class(UIView的子类)声明的前面, 然后就可以在storyBoard中的inspector编辑它
    @IBInspectable 用在(UIView的子类)的属性前面, 然后就可以在storyBoard中的inspector编辑它 ,就想系统提供的可以设置颜色,字体...
  • swift中的属性默认是strong类型, 只有可选类型才能被标记为weak
    oc中的 copy属性 转换为swift中的@NSCopying 必须遵守NSCoding协议
  • 使用Core Data的时候所有的属性和方法需要标记为 @NSManaged
  • 文档中指出"The corresponding reference types can be accessed with their original NS class name prefix."
    但是beta版本中不能很好的使用NS开头的
  • 在oc和swift的桥接类型之间 直接使用 as 可以相互转换
  • 因为swift中的String和NSString使用的编码方式不一样,
    所以在swift中要对string使用索引的时候 不能直接使用 Int 或者NSRange
    需要使用String.Index and Range<String.Index>
  • swift会将Double, Int, Bool, Uint, Float和NSNumber桥接, 所以可以直接将
    这些类型的值使用 as NSNumber转换为NSNumber, 但是逆向进行是得到的可选值 as?
  • Foundation 和Core Foundation 之间的类型有toll-free bridge('免费桥')
  • Foundation中的常量, 在swift中被换为类嵌套的枚举
    NSJSONReadingOptions ----- >> JSONSerialization.ReadingOption
  • swift中使用 Core Foundation
    • 如果使用swift处理过的函数不用我们手动管理内存分配
    • 否则需要我们处理
    • 区分的方式: 当返回值是 Unmanaged<Instance>的时候说明需要我们处理
    • 处理方法: 在使用返回的值之前调用他对应的takeUnretainedValue() 或
      takeRetainedValue()即可
    • 例如let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
  • swift中Core Foundation里的类型 Ref后缀被去掉了 例如 CFTypeRef -> CFType
  • 在oc的方法 使用 NS_SWIFT_NOTHROW , 将不会使用swift的异常抛出机制
  • swift中直接使用 is 来实现oc中isKindOfClass: 的功能
  • swift中使用kvo的条件: 1.必须继承自NSObject 2. 被观察的属性 要被标记为 dynamic
  • swift 中的单例很简单:
class Singleton {
   static let sharedInstance = Singleton()
} 
或者
class Singleton {
   static let sharedInstance: Singleton = {
       let instance = Singleton()
       // setup code
       return instance
   }()
}
  • swift和C的交互: c的函数在swift中均为全局函数
  • 使用CF_SWIFT_NAME 这个宏可以将c中的属性或者函数转换为swift中
    eg:
Color ColorCreateWithCMYK(float c, float m, float y, float k) CF_SWIFT_NAME(Color.init(c:m:y:k:));  
对应为swift中
extension Color {
    init(c: Float, m: Float, y: Float, k: Float)
}
  • c语言中的枚举 如果使用了NS_ENUM定义, 则在swift中被处理为对应的枚举
    如果没有使用NS_ENUM定义, 则被处理为结构体
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
   UITableViewCellStyleDefault,
   UITableViewCellStyleValue1,
   UITableViewCellStyleValue2,
   UITableViewCellStyleSubtitle
};
//对应与
enum UITableViewCellStyle: Int {
    case `default`
    case value1
    case value2
    case subtitle
}
typedef enum {
   MessageDispositionUnread = 0,
   MessageDispositionRead = 1,
   MessageDispositionDeleted = -1,
} MessageDisposition;
对应与
struct MessageDisposition: RawRepresentable, Equatable {}
var MessageDispositionUnread: MessageDisposition { get }
var MessageDispositionRead: MessageDisposition { get }
var MessageDispositionDeleted: MessageDisposition { get }
  • c中的被NS_OPTIONS修饰的枚举, 在swift中是OptionSet类型, -> 即可以使用数组方式选多个值
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
        UIViewAutoresizingNone                 = 0,
        UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
        UIViewAutoresizingFlexibleWidth        = 1 << 1,
        UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
        UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
        UIViewAutoresizingFlexibleHeight       = 1 << 4,
        UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
对应与
public struct UIViewAutoresizing : OptionSet {
    public init(rawValue: UInt)
    
    public static var flexibleLeftMargin: UIViewAutoresizing { get }
    public static var flexibleWidth: UIViewAutoresizing { get }
    public static var flexibleRightMargin: UIViewAutoresizing { get }
    public static var flexibleTopMargin: UIViewAutoresizing { get }
    public static var flexibleHeight: UIViewAutoresizing { get }
    public static var flexibleBottomMargin: UIViewAutoresizing { get }
}
在swift中直接使用  let resize = [. flexibleLeftMargin, . flexibleWidth...]
  • 在swift中全局变量和存储属性都被保证只初始化一次,
    • 所以用来当作OC里面的#define定义的常量
    • 同时swift全局函数可以当作OC里#define定义的复杂宏(类似函数)
  • swift中的条件编译 自定义编译符的方法(例如: DEBUG_LOGGING)
    • 首先在project 的设置里面设置swift -D DEBUG_LOGGING to set the DEBUG_LOGGING
    • 然后使用 #if DEBUG_LOGGING // 操作 #endif
#if arch(arm) || arch(arm64)
#if swift(>=3.0)
print("Using Swift 3 ARM code")
    #else
    print("Using Swift 2.2 ARM code")
#endif
#elseif arch(x86_64)
print("Using 64-bit x86 code.)
    #else
    print("Using general code.")
#endif
  • swift中使用指针的方式
    • 使用inout方式 &变量
    • 使用UnsafePointer<Type> 或者UnsafeMutablePointer<Type>
例如这个函数接受的参数可以传许多种
let x: Float = 0
func takesAPointer(_ p: UnsafePointer<Float>!) {
    // ...
}
takesAPointer(&x)
takesAPointer([0.0,1.0])
  • 在swift中申明oc中的包含可选实现方法的协议时需要在协议和方法前都标记objc
@objc public protocol MySwiftProtocol {
// 必须实现
    func requiredMethod()
    
    @objc optional func optionalMethod()
}
  • 将oc的方法或者属性使用NS_SWIFT_NAME()可以为他们在swift中命一个别名
  • 将oc的方法或使用 NS_SWIFT_UNAVAILABLE()可以让他在swift中不可用
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容