Swift与Objective-C的兼容“黑魔法”:@objc和Dynamic

  虽然说 Swift 语言的初衷是希望能摆脱 Objective-C 的沉重的历史包袱和约束,但是不可否认的是经过了二十多年的洗礼,Cocoa 框架早就烙上了不可磨灭的 Objective-C 的印记。无数的第三方库是用 Objective-C 写成的,这些积累无论是谁都不能小觑。因此,在最初的版本中,Swift 不得不考虑与 Objective-C 的兼容。

  Apple 采取的做法是允许我们在同一个项目中同时使用 Swift 和 Objective-C 来进行开发。其实一个项目中的 Objective-C 文件和 Swift 文件是处于两个不同世界中的,为了让它们能相互联通,我们需要添加一些桥梁。

  首先通过添加 {product-module-name}-Bridging-Header.h 文件,并在其中填写想要使用的头文件名称,我们就可以很容易地在 Swift 中使用 Objective-C 代码了。Xcode 为了简化这个设定,甚至在 Swift 项目中第一次导入 Objective-C 文件时会主动弹框进行询问是否要自动创建这个文件,可以说是非常方便。

  但是如果想要在 Objective-C 中使用 Swift 的类型的时候,事情就复杂一些。如果是来自外部的框架,那么这个框架与 Objective-C 项目肯定不是处在同一个 target 中的,我们需要对外部的 Swift module 进行导入。这个其实和使用 Objective-C 的原来的 Framework 是一样的,对于一个项目来说,外界框架是由 Swift 写的还是 Objective-C 写的,两者并没有太大区别。我们通过使用 2013 年新引入的 @import 来引入 module:

@import MySwiftKit; 

之后就可以正常使用这个 Swift 写的框架了。

  如果想要在 Objective-C 里使用的是同一个项目中的 Swift 的源文件的话,可以直接导入自动生成的头文件 {product-module-name}-Swift.h 来完成。比如项目的 target 叫做 MyApp 的话,我们就需要在 Objective-C 文件中写

#import "MyApp-Swift.h" 

  但这只是故事的开始。Objective-C 和 Swift 在底层使用的是两套完全不同的机制,Cocoa 中的 Objective-C 对象是基于运行时的,它从骨子里遵循了 KVC (Key-Value Coding,通过类似字典的方式存储对象信息) 以及动态派发 (Dynamic Dispatch,在运行调用时再决定实际调用的具体实现)。而 Swift 为了追求性能,如果没有特殊需要的话,是不会在运行时再来决定这些的。也就是说,Swift 类型的成员或者方法在编译时就已经决定,而运行时便不再需要经过一次查找,而可以直接使用。

  显而易见,这带来的问题是如果我们要使用 Objective-C 的代码或者特性来调用纯 Swift 的类型时候,我们会因为找不到所需要的这些运行时信息,而导致失败。解决起来也很简单,在 Swift 类型文件中,我们可以将需要暴露给 Objective-C 使用的任何地方 (包括类,属性和方法等) 的声明前面加上 @objc 修饰符。注意这个步骤只需要对那些不是继承自 NSObject 的类型进行,如果你用 Swift 写的 class 是继承自 NSObject 的话,Swift 会默认自动为所有的非 private 的类和成员加上 @objc。这就是说,对一个 NSObject 的子类,你只需要导入相应的头文件就可以在 Objective-C 里使用这个类了。

  @objc 修饰符的另一个作用是为 Objective-C 侧重新声明方法或者变量的名字。虽然绝大部分时候自动转换的方法名已经足够好用 (比如会将 Swift 中类似 init(name: String) 的方法转换成 -initWithName:(NSString *)name 这样),但是有时候我们还是期望 Objective-C 里使用和 Swift 中不一样的方法名或者类的名字,比如 Swift 里这样的一个类:

class 我的类 {
    func 打招呼(名字: String) {
        println("哈喽,\(名字)")
    }
}  

我的类().打招呼("小明") 

  Objective-C 的话是无法使用中文来进行调用的,因此我们必须使用 @objc 将其转为 ASCII 才能在 Objective-C 里访问:

@objc(MyClass)
class 我的类 {
    @objc(greeting:)
    func 打招呼(名字: String) {
        println("哈喽,\(名字)")
    }
} 

  我们在 Objective-C 里就能调用 [[MyClass new] greeting:@"XiaoMing"] 这样的代码了 (虽然比起原来一点都不好玩了)。另外,正如上面所说的以及在 Selector 一节中所提到的,即使是 NSObject 的子类,Swift 也不会在被标记为 private 的方法或成员上自动加 @objc。如果我们需要使用这些内容的动态特性的话,我们需要手动给它们加上 @objc 修饰。

  添加 @objc 修饰符并不意味着这个方法或者属性会变成动态派发,Swift 依然可能会将其优化为静态调用。如果你需要和 Objective-C 里动态调用时相同的运行时特性的话,你需要使用的修饰符是 dynamic。一般情况下在做 app 开发时应该用不上,但是在施展一些像动态替换方法或者运行时再决定实现这样的 "黑魔法" 的时候,我们就需要用到 dynamic 修饰符了。在之后的 KVO 一节中,我们还会提到一个关于使用 dynamic 的实例。

时间: 2024-10-29 16:50:26

Swift与Objective-C的兼容“黑魔法”:@objc和Dynamic的相关文章

IOS-Swift、Objective-C、C++混合编程

1.Objective-C调用C++代码 后缀为m文件的是Objective-C的执行文件,而后缀为mm文件的是Objective-C++文件. 直接在Objective-C中是无法调用C++代码的,所以如果需要在Objective-C调用C++语言就需要直接将后缀m文件改为mm,然后就可以调用C++代码了. Objective-C兼容C,Objective-C++兼容C.C++. 接下来是在OC工程中创建C++文件,并调用C++的代码: 然后在OC文件中直接用C++的语法调用C++,所以前提是

Swift和Objective-C如何兼顾?且看@objc和Dynamic(转)

2015-02-05 00:18 王巍 http://swifter.tips/ 字号:T | T Objective-C经过了二十多年的洗礼,Cocoa框架早就烙上了不可磨灭的印记.无数的第三方库是用Objective-C写成的,这些积累无论是谁都不能小觑.因此,在最初的版本中,Swift不得不考虑与Objective-C的兼容. AD:干货来了,不要等!WOT2015 北京站演讲PPT开放下载! 虽然说 Swift 语言的初衷是希望能摆脱 Objective-C 的沉重的历史包袱和约束,但是

Swift学习之每日一tip (7) @objc

今天隔壁老王突然问起我,Swift里面的@objc是个神马玩意儿?于是就有了今天的这个tip. 那么话说回来,既然说到@objc,就不得不扯一扯Swift和Objective-C之间不得不说的一些事啦^_^ Objective-C和Swift混合开发 Swift 语言的初衷是希望能摆脱 Objective-C 的沉重的历史包袱和约束,但是不可否认的是经过了二十多年的洗礼,Cocoa 框架早就烙上了不可磨灭的 Objective-C 的印记.无数的第三方库是用 Objective-C 写成的,这些

Swift调用Objective C的FrameWork

很多Github的库经过很多年的发展,源码都是OC写的,,所以,用Swift调用OC的库就是开发中难免遇到的的一个问题,本文以AFNetworking为例,讲解如何跨语言调用. 第一步 创建一个空的工程  注意,语言选择Swift 第二步,创建bridging-header 这个文件的作用,就是把OC的接口暴露给Swift.有两种方式  方式一  创建一个OC文件,然后点击确定    弹出是否要创建Bridging-Header,点击确定,这样会生成三个文件,其中的一个就是我们要用的SwiftU

使用swift语言进行IOS应用开发

在Swift中能够直接使用Objective-C语言提供的api (包括系统框架与自己的定制代码),也能够在Objective-C中使用Swift提供的类和api ,还能够在一个工程中同时混合使用Swift 和Objective-C两种语言,两种语言之间能够互通和互用. 任意Objective-C的框架或C库(包括所有的Objective-C系统框架,例如Foundation.UIKit.SpriteKit以及系统提供的公共c库)作为模块被直接导入Swift 供Swift语言使用. 例如为了使用

iOS开发系列--Swift进阶

概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用Swift进行iOS开发还是不够的.在这篇文章中将继续介绍一些Swift开发中一些不常关注但是又必备的知识点,以便对Swift有进一步的了解. 访问控制 和其他高级语言一样Swift中也增加了访问控制,在Swift中提供了private.internal.public三种访问级别,但是不同的是Swift中的访问

Using Swift with Cocoa and Objective-C--Mix and Match

Swift与Objective-C的兼容能力允许你在同一个工程中同时使用两种语言.你可以用这种叫做“mix and match”的特性来开发基于混合语言的应用.使用Swfit的最新特性--“mix and match”,你可以实现应用的一部分功能,并无缝地并入已有的Objective-C的代码中. Mix and Match 概述 Swift与Objective-C文件可以在一个工程中并存,不管这个工程原本是基于Objective-C还是Swift.你可以直接往现有工程中简单地添加另一种语言的文

Swift进阶

概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用Swift进行iOS开发还是不够的.在这篇文章中将继续介绍一些Swift开发中一些不常关注但是又必备的知识点,以便对Swift有进一步的了解. 访问控制 和其他高级语言一样Swift中也增加了访问控制,在Swift中提供了private.internal.public三种访问级别,但是不同的是Swift中的访问

Swift 进阶

iOS开发系列--Swift进阶 2015-09-21 00:01 by KenshinCui, 3072 阅读, 12 评论, 收藏, 编辑 概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用Swift进行iOS开发还是不够的.在这篇文章中将继续介绍一些Swift开发中一些不常关注但是又必备的知识点,以便对Swift有进一步的了解. 访问控制 Swift命名