Swift和Objective-C相互調用

在Swift 中使用Objective-C

官方文檔

橋接文件

橋接文件是一個在Swift中調用OC類或方法的通道卿城。Swift在同模塊內(nèi)文件是可以相互調用的(不能模塊之間調用是需要引入模塊的)贴汪,但是OC文件是需要引入頭文件才能使用溉知。

在Swift中首次創(chuàng)建OC文件的時候纳寂,xcode會彈出一個窗口优构,詢問是否要創(chuàng)建橋接文件。橋接文件默認的命名為 “項目名-Bridging-Header.h”芙沥。只需要將OC 的頭文件在橋接文件中#import一下就可以在Swift中使用玫膀。

如果在詢問是否創(chuàng)建橋接文件的時候,沒有選擇創(chuàng)建斯辰,或者不小心將橋接文件刪除了舶担,我們也可以在 Targets-->Build Settings-->Swift Compiler - General-->Objective-C Bridging Header中 手動配置。創(chuàng)建一個頭文件椒涯,文件的命名可以按照自己習慣命名柄沮,并不一定需要按照默認橋接文件的命名方式,創(chuàng)建完成后只需要在Targets-->Build Settings-->Swift Compiler - General-->Objective-C Bridging Header中 配置橋接頭文件的路徑就可以了废岂。

NS_ASSUME_NONNULL_BEGIN 和 NS_ASSUME_NONNULL_END的作用

在Swift中祖搓,變量是有可選(optional)和非可選(non-optional)之分的,但是在OC中并沒有對一個變量是否是nil進行區(qū)分湖苞,這就造成一個問題拯欧,在 Swift與Objective-C混編時,Swift編譯器并不知道一個Objective-C對象到底是optional還是non-optional财骨,這種情況下镐作,編譯器會默認的將OC對象當成是非可選。

為了解決這個問題隆箩,蘋果在Xcode 6.3引入了一個Objective-C的新特性:nullability annotations该贾。這一新特性的核心是兩個新的類型注釋: __nullable__nonnull 。從字面上我們可以猜到捌臊,__nullable表示對象可以是NULLnil杨蛋,而__nonnull表示對象不應該為空。當我們不遵循這一規(guī)則時,編譯器就會給出警告逞力。

但是每個屬性或者方法返回值或者參數(shù)都去指定是否nullable曙寡,實在是太繁瑣了,NS_ASSUME_NONNULL_BEGIN 和 NS_ASSUME_NONNULL_END就是為了簡化這種操作而誕生的寇荧,在這兩個宏之間的代碼举庶,所有簡單指針對象都被假定為nonnull,因此我們只需要去指定那些nullable的指針揩抡。

//Person.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject
@property(nonatomic,copy,nullable)NSString *name;
@property(nonatomic,copy)NSString *sex;
-(instancetype)initWithName:(NSString *)name sex:(NSString *)sex;
@end

NS_ASSUME_NONNULL_END
  
//Person.m 
#import "Person.h"

@implementation Person
-(instancetype)initWithName:(NSString *)name sex:(NSString *)sex{
    if (self = [super init]) {
        self.name = name;
        self.sex = sex;
    }
    return self;
}
@end  
let per = Person.init(name: "小明", sex: "男")
print(per.name)
print(per.sex)

//輸出:
//Optional("小明")
//男

Swift 中如何使用C++

在OC文件是直接可以使用C語言的户侥,使用C++,只需要將.m文件后綴名改為.mm就可以使用C++的語法了捅膘。

在Swift中也是可以使用C語言的添祸,具體使用Swift和C語言的混合使用

但是對與C++的使用相對就麻煩很多,一般采用OC對象包裹的形式去使用C++的對象寻仗。在Swift項目中OC頭文件中是不能引入C++的,否則的會報file not found 的錯誤凡壤,我們需要在.mm文件中使用C++對象

在Objective-C中使用Swift

官方文檔

相對與在Swift 中使用Objective-C來說署尤,在Objective-C中使用Swift要復雜很多。

如何將Swift文件引入到OC項目中

第一次在OC項目中創(chuàng)建Swift文件時亚侠,xcode也是會提醒創(chuàng)建橋接文件的曹体,這個文件的作用也是給Swift文件中調用OC使用的.

  1. 在OC文件中使用當前項目的Swift文件

    我們可以在 Targets-->Build Settings-->Swift Compiler - General-->Objective-C Generated Interface Header Name 看到我們需要在OC中將引入Swift內(nèi)容的頭文件。這個文件默認是 **"項目名-Swift.h" ** ,這個頭文件也可以改成我們自定義的名稱硝烂。只需要在OC中#import這個頭文件就可以了箕别。這種方式是

    #import "ProductModuleName-Swift.h"
    
  1. 在OC文件中使用當前其他Framework中的Swift文件

    ProductModuleName-Swift.h和上面的一樣,只需要在前面加上個項目名就可以使用其他framework中的swift文件

    #import <ProductName/ProductModuleName-Swift.h>
    

在OC使用Swift需要注意什么

Objective-C 對象是基于運行時的滞谢,在運行調用時再決定實際調用的具體實現(xiàn)串稀。而 Swift 為了追求性能,通常情況下是不會在運行時再來決定這些的狮杨。也就是說母截,Swift 類型的成員或者方法在編譯時就已經(jīng)決定,而運行時便不再需要經(jīng)過一次查找橄教。Objective-C 中所有類都繼承自NSObject清寇,為了能在OC中調用 Swift 中的類,Swift也必須繼承NSObject护蝶。

首先我們需要先了解@objc华烟、@objcMembers和dynamic這三個關鍵字的含義

@objc Swift @objc 關鍵字文檔
  • @objc修飾符是用來暴露接口給 Objective-C 的運行時(類、協(xié)議持灰、屬性和方法等盔夜。@nonobjc修飾符不暴露接給 Objective-C 的運行時,通常可以是使用了@objcMembers修飾了類比吭,但是某些方法不想在OC中使用

  • 添加@objc修飾符并不意味著這個方法或者屬性會采用 Objective-C 的方式變成動態(tài)派發(fā)绽族,Swift 依然可能會將其優(yōu)化為靜態(tài)調用

  • @objc 修飾符的隱式添加的情況

    1. 覆重寫一個@objc聲明的計算屬性或者方法

      import Foundation
      
      class Person: NSObject {
          @objc var name :String{
              return "小明"
          }
          @objc var sex:String = "男"
          
          @objc func demo(){
              
          }
      }
      
      class Student: Person {
          override var name: String{
              return ""
          }
          //Cannot override with a stored property 'sex'
          //子類不能重寫父類的存儲屬性
          //override var sex: String = "男"
          
          override func demo() {
              
          }
      }
      
    2. 實現(xiàn)一個使用@objc修飾協(xié)議

      @objc protocol MyProtocol {
          func myFun()
      }
      
      
      class Person: MyProtocol {
          func myFun() {
              
          }
      }
      
    3. 當屬性聲明為@IBAction或者@IBOutlet

    4. 當屬性聲明為@NSManaged

    5. @objcMembers 修飾的類,它和它子類的屬性方法擴展都會隱式的添加上@objc

      @objcMembers
      class MyClass : NSObject {
        func foo() { }             // implicitly @objc
      
        func bar() -> (Int, Int)   // not @objc, because tuple returns
            // aren't representable in Objective-C
      }
      
      extension MyClass {
        func baz() { }   // implicitly @objc
      }
      
      class MySubClass : MyClass {
        func wibble() { }   // implicitly @objc
      }
      
      extension MySubClass {
        func wobble() { }   // implicitly @objc
      }
      

下面的這些情況將不在隱式添加@objc (Swift4以后)

  • 需要特別指明dynamic不再隱式添加@objc
class MyClass {
  dynamic func foo() { }       // error: 'dynamic' method must be '@objc'
  @objc dynamic func bar() { } // okay
}
  • NSObject的子類將不再隱式添加@objc
class MyClass : NSObject {
  func foo() { } //在OC不能使用
}

即遵循 Swift API Design Guidelines 的代碼將使用的Swift名稱衩藤,這些名稱通常會轉換為非常差的Objective-C名稱吧慢,從而違反了針對Objective-C Coding Guidelines for Cocoa.

class MyNumber : NSObject {
  init(_ int: Int) { }
  init(_ double: Double) { } // error: initializer 'init' with Objective-C selector 'init:' 
      // conflicts with previous declaration with the same Objective-C selector
}

class MyNumber : NSObject {
  @objc(initWithInteger:) init(_ int: Int) { }
  @objc(initWithDouble:) init(_ double: Double) { }
}

@objc(Student)// Only classes that inherit from NSObject can be declared @objc
class Person: NSObject {
}

class Person: NSObject {
    @objc(age) var name = ""
}     
@objcMembers

@objcMembers只能用來修飾類。使用@objcMembers修飾的類赏表,系統(tǒng)會在自動給這個類的所有方法添加@objc检诗,暴露給OC。

dynamic (使用dynamic修飾的屬性,在Swift4之后是不會自動添加上@objc的)

dynamic修飾的屬性和方法是告訴編譯器使用動態(tài)分發(fā)而不是靜態(tài)分發(fā)瓢剿,使用動態(tài)分發(fā)逢慌,您可以更好的與OC中runtime的一些特性(如CoreData,KVC/KVO)進行交互间狂。

在Swift中使用KVO

class Person: NSObject {
    @objc dynamic var name = "" //@objc在Swift4之后必須要添加
    func demo() {
        addObserver(self, forKeyPath: #keyPath(Person.name), options: [.initial,.new], context: nil)
    }
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末攻泼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鉴象,更是在濱河造成了極大的恐慌忙菠,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纺弊,死亡現(xiàn)場離奇詭異牛欢,居然都是意外死亡,警方通過查閱死者的電腦和手機淆游,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門傍睹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人犹菱,你說我怎么就攤上這事拾稳。” “怎么了已亥?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵熊赖,是天一觀的道長。 經(jīng)常有香客問我虑椎,道長震鹉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任捆姜,我火速辦了婚禮传趾,結果婚禮上,老公的妹妹穿的比我還像新娘泥技。我一直安慰自己浆兰,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著簸呈,像睡著了一般榕订。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜕便,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天劫恒,我揣著相機與錄音,去河邊找鬼轿腺。 笑死两嘴,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的族壳。 我是一名探鬼主播憔辫,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼仿荆!你這毒婦竟也來了贰您?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤赖歌,失蹤者是張志新(化名)和其女友劉穎枉圃,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庐冯,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年坎穿,在試婚紗的時候發(fā)現(xiàn)自己被綠了展父。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡玲昧,死狀恐怖栖茉,靈堂內(nèi)的尸體忽然破棺而出膝昆,到底是詐尸還是另有隱情塑崖,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布套耕,位于F島的核電站尘应,受9級特大地震影響惶凝,放射性物質發(fā)生泄漏。R本人自食惡果不足惜犬钢,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一苍鲜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玷犹,春花似錦混滔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽油湖。三九已至,卻和暖如春领跛,著一層夾襖步出監(jiān)牢的瞬間乏德,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工隔节, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鹅经,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓怎诫,卻偏偏與公主長得像瘾晃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子幻妓,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353