美文网首页
(WWDC) Swift 和 Objective-C 的互操作性

(WWDC) Swift 和 Objective-C 的互操作性

作者: FicowShen | 来源:发表于2019-05-29 12:05 被阅读0次



    Xcode根据Objective-C代码自动生成的Swift代码

    内容概览

    • Swift 与 Objective-C 交互
    • 错误处理
    • 为空性标注
    • 轻量级泛型
    • Kindof 类型
    • 总结

    Swift 与 Objective-C 交互

    Swift方法什么时候暴露给Objective-C?

    NSObject基类
    • 方法的访问控制不是 private级别
    class MyController : UIViewController {
      private func refresh() {
        // ...
      }
    }
    
    • 没有使用Swift特性
    class MyController : UIViewController {
      func refresh() -> (Int, String)? {
        // ...
        return (status, response)
      }
    }
    
    非NSObject基类
    • 在遵守 NSObjectProtocol 协议时,标注 @objc
    class MyController : UIWebViewDelegate {
        func webViewDidStartLoad(v: UIWebView) {
            // ...
        }
    }
    

    不过,这种情况发生时,Xcode会给出警告。

    显式地标记
    • 标记 @IBOutlet, @IBAction, @NSManaged等属性, 以支持 Interface Builder、Core Data
    class MyController : UIViewController {
        @IBAction private func refresh() {
            // ...
        }
    }
    
    • 标记 dynamic 修饰符,以支持Objective-C的Runtime,表示当前值可能在运行时被KVO更新
    class MyController : UIViewController {
      dynamic private var title: String? {
        get { /* ... */ }
        set { /* ... */ }
      }
    }
    
    • 标记 @objc 修饰符,直接暴露给Objective-C
    class MyController : UIViewController {
        @objc private func refresh() {
            // ...
        }
    }
    



    标记 @objc后,将无法使用Swift特性


    Selector 冲突



    Objective-C根据方法的名称区分方法,而不是方法的签名。
    所以,在Swift中定义的同名方法如果需要暴露给Objective-C时,有可能会遭遇错误提示。



    对于这个问题,有两种解决方案:

    • 使用@objc属性对暴露给Objective-C的方法进行重命名
    • 使用@nonobjc属性,禁止将方法暴露给Objective-C


    函数指针



    函数指针在C语言中被用作回调。但是,C语言中的函数指针不能捕获状态。

    这里的self不能被C语言中的函数指针捕获,所以需要其他的地方来存储self,以供后期使用。



    苹果在Swift 2.0中引入了@convention(c)属性来解决这个问题。


    错误处理

    常见的 Objective-C 错误处理方式 和 Swift 异常。

    返回类型的差别

    Objective-C 中的 id 被翻译为 Swift 中的 AnyObject

    Objective-C 中的 BOOL 被翻译为 Swift 中的 Void

    闭包的使用

    Objective-C 中的 NSError * 被翻译为 Swift 中的 NSError?


    在 Objective-C 中处理 Swift 方法抛出的错误



    定义以下方法和错误类型:

    在 Objective-C 中调用:



    在编译时,Swift 会定义 Objective-C 需要使用的部分:


    处理Cocoa中的错误



    感谢苹果工程师的辛勤付出,Cocoa中的很多错误类型在Swift中已经可用。



    已在Swift中可用的比较常见的Cocoa错误类型:

    NSCocoaError 
    NSURLError 
    AVError 
    CKErrorCode 
    CLError 
    GKErrorCode 
    HMErrorCode 
    POSIXError 
    WKErrorCode 
    WatchKitErrorCode
    

    为空性标注

    请观察 UIView 在 Objective-C 中的定义:

    当被转换为 Swift 1.0 的代码时,结果如下:

    在转换的过程中,有很多信息是丢失了的。比如:哪些变量可以为nil
    庆幸的是,Swift 1.1 中便解决了这个问题。



    原来,苹果在 Objective-C 中引入了 nullable, nonnull, null_unspecified等修饰符来解决以上问题



    标明 Objective-C/C 指针是否可以为nil,可以:

    • 更好地表达 API 的意图
    • 改善编译器的静态检查
    • 提高 API 在 Swift 中的易用性



    很快,在苹果的 SDK 中遍布了这些修饰符。
    编译器可以抛出相关的警告,便于开发者及时发现这些问题。



    更新后的 SDK 代码:



    可以发现,苹果使用 NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END,假设标记区域为 nonnull

    审计区域对一些指针做出了假设:

    • 单个层级的指针被假设为 nonnull
    • NSError** 每个指针层级都是 nullable

    然后对 nullablenull_unspecified 的情况进行单独标记


    C 指针
    • 以双下划线为前缀的为空性修饰符可以随处使用
    • 为空性修饰符放在指针符号后



    这里有一个细节值得注意:

    外层指针为 __nullable,*values 可以为 null。如果 numValues 为0, 你就可以传入 null。

    内层指针为 __nonnull,**values 不可以为 null。你必须传入一个非 null 的数组,用于创建 CFArray。



    最后,为空性修饰符已经遍布苹果的 SDK ,建议你也使用它们来改善你的 Objective-C API。


    轻量级泛型



    以下 Objective-C 中的数组没有标明元素类型,对应的 Swift 代码也没有标明元素类型。



    如果使用带有类型的集合,可以

    • 提高 API 的表达力
    • 使集合更易用
    • 改善编译器的静态检查



    使用方法:

    • 在 < > 中指定参数类型
    • 参数类型可以在这个类中尽情使用

    在 Categories 和 Extensions 中也可以使用



    这个特性支持向后兼容:

    • 不需要改变运行时
    • 对代码生成无任何影响

    如果你不需要类型时,也可以很容易地去除它。


    Kindof 类型



    来观察一个问题:

    编译器并不知道 view.subviews[0] 是一个 Button。

    id 是很弱的API协议



    以上代码可以将 NSApp 定义为 id 类型。



    以上代码可以将 NSApp 定义为 __kindof UIApplication * 类型。



    使用__kindof 可以很方便地转换父类和子类。



    还可以允许向子类发送消息



    __kindof其实是更实用的id类型

    使用 id 约束返回值 使用 __kindof 约束返回值 使用 __kindof 约束集合的元素类型
    什么时候在API中使用 id



    多数惯用情况下,id 可以被更准确的类型替代:

    • 返回 self 的方法可以使用 instancetype
    • 多数集合使用场景可以对元素类型进行约束
    • __kindof X * 可以用来表达X类的子类
    • 对于遵守 SomeProtocol 协议的类型,使用 id<SomeProtocol>



    只在你需要表示任何类型的对象时使用id。比如:


    总结



    Swift 和 Objective-C 共同进化以更好地协作

    • Xcode 可以让你在这两个语言的切换中游刃有余



    让你的 Objective-C 代码与时俱进

    • Objective-C 新特性可以提升API的表达力
    • 凭借更强的类型安全检查,你可以更快地发现问题所在
    • 让你的 Objective-C 代码接口在 Swift 中更优雅




    参考内容:
    Swift and Objective-C Interoperability




    转载请注明出处,谢谢~

    相关文章

      网友评论

          本文标题:(WWDC) Swift 和 Objective-C 的互操作性

          本文链接:https://www.haomeiwen.com/subject/hsmdtctx.html