程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Objective-C 與 Swift 混編之路

Objective-C 與 Swift 混編之路

編輯:關於C語言

Objective-C 與 Swift 混編之路


 

重要資料

Using Swift with Cocoa and Objective-C 官方文檔

為什麼要混編?

語言發展趨勢(TIOBE),Swift 排行持續上升, OC 排行呈重力下降 項目正常迭代需要
很多第三方庫仍然使用 OC 實現 項目中原來已經用 OC 實現的模塊如果使用 Swift 重寫,代價稍大 我們需要在項目中使用 Swift 才能真正碰到問題,解決問題

注:不是為了混編而混編。混編只是在對開發資源、項目管理和技術發展趨勢進行綜合衡量之後做出的比較合理的選擇。

如何開始混編?

步驟

創建工程,Language 選擇 Swift 或 Objective-C 都可以。

這裡寫圖片描述

創建 Swift 文件並添加 bridging header 文件

這裡寫圖片描述

添加 Swift 文件時 Xcode 會自動提示你添加 bridging header 文件,選擇 Yes 即可

進行兩處關鍵設置

這裡寫圖片描述
這裡寫圖片描述

這兩處設置 Xcode 默認都會設置好,可以把 Objective-C Bridging Header 和 Objective-C Generated Interface Header Name 改成自己想設置的名字。

至此Swift 與 Objective-C 混編的環境就算配置完成了。

XXX-Bridging-Header.h

如果需要在 Swift 中使用 OC 的代碼或者庫,只需要在這個文件中 import 相應代碼或者庫的頭文件即可。

XXX-Swift.h

和 XXX-Bridging-Header.h 不同,XXX-Swift.h 文件不會出現在項目中,而是由 Xcode 自動生成,你可以在類似如下的路徑下找到相應項目的 XXX-Swift.h 文件:(PS:演講時沒有寫到PPT裡面,實在抱歉)

/Users/perry/Library/Developer/Xcode/DerivedData/XXX-bhlzdinkujybftbjmgwjwclndmss/Build/Intermediates/XXX.build/Debug-iphonesimulator/XXX.build/Objects-normal/x86_64/XXX-Swift.h

如果需要在 OC 中使用 Swift 代碼,在使用的文件中 #import XXX-Swift.h (PS:其他一些在 OC 中使用 Swift 代碼的注意事項會在後面詳細說明)

查看 XXX-Swift.h 文件中的代碼:

這裡寫圖片描述

不難發現這個文件中的內容其實是將 Swift 中的代碼轉換成了 OC 的代碼。

注:如果對項目進行清理操作,這個文件也會被刪除,而且在重新構建的過程中,只有在所有的 Swift 代碼都編譯通過的情況下才會重新生成這個文件。

結合框架的混編

這裡寫圖片描述

踩坑時間

OC 中的復雜宏

這裡寫圖片描述

Swift 編譯器不包含預處理器。取而代之的是,它充分利用了編譯時屬性,生成配置,和語言特性來完成相同的功能。所以對於上述類似的宏定義,建議用方法重新封裝一次使用。

OC 中的宏和 Swift 中的類同名

因為 Swift 不能使用 #define,而 OC 可以,所以你可能會在 OC 中定義一個和 Swift 中類同名字的宏,如果你從來沒有在 OC 中使用 Swift 代碼提供的功能(也就是從來沒有 #import XXX-Swift.h),編譯時不會有任何問題,但是如果一旦使用了,就會報如下的錯誤:

這裡寫圖片描述

這裡是因為我使用 #define MView (@MView)MView 定義成了 NSString 類型的宏,而在 Swift 中 MViewUIView 的子類,在 #import MDemo-Swift.h 之後, MView 就被重復定義了,從而導致錯誤。

更新:如果 OC 中的類和 Swift 中的類同名,也符合上述情況。

Swift 使用 OC 中的枚舉

如果只是單純使用值,可以直接使用枚舉 如果需要對枚舉值進行運算,則需要使用 .value

OC 使用 Swift 中的枚舉

需要在 Swift 的枚舉定義前加 @objc 修飾符 枚舉的類型必須是 Int

@objc / dynamic / NS*

如果 Swift 類需要在 OC 中使用,建議繼承 NS* 系列的類 如果 Swift 類中的成員或者方法需要在 OC 中使用,使用 @objc 修飾符 如果 Swift 類中的成員需要支持 KVC/KVO,使用 dynamic 修飾符

IBOutlet vs IBOutletCollection

Swift 中沒有 IBOutletCollection ,而是如下的方式實現 IBOutletCollection

@IBOutlet var labels: [UILabel]!

這個 IBOutlet 在 xib/Storyboard 中的情況如下:

這裡寫圖片描述

需要注意的是:和 OC 的 IBOutletCollection 不同,labels 中的元素不一定是按照 black,white,blue,green 的順序排列!

重復包含

OC 中可能會碰到 A 類頭文件需要包含 B 類頭文件,B 類頭文件同時也需要包含 A 類頭文件的情況,這個時候用 @class 即可解決問題。但是當 OC 中的 A 類頭文件需要包含 XXX-Swift.h,而 XXX-Bridging-Header.h 中又 import A類頭文件,這個時候就比較尴尬了。看下面的例子:

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

上面例子的情況是這樣的:

首先,我們有兩個 Swift 類 MManagerMData。 一個 OC 類 ViewController

然後,MManager 類中的一個方法需要傳入 ViewController 類實例的句柄,然後把一個 MData 類實例賦值給 ViewController 類實例中的成員變量 mData(這個 mData 的類型是 MData )。

在這種場景下,就會出現重復包含,因為已經有了 MManager 類中的一個方法需要傳入 ViewController 類實例的句柄 這樣一個條件,所以我們必須在 XXX-Bridging-Header.h#import ViewController.h,這樣我們就只能通過在 ViewController.m 文件中去 #import XXX-Swift.h 的方式來避免重復包含。此時我們需要將成員變量 mData 定義為 id 類型,當在ViewController.m 文件中具體用的時候再將其強制轉換為 MData 類型。如下:

這裡寫圖片描述

這裡寫圖片描述

即可解決重復包含的問題。

這樣的處理方式存在的問題是成員變量 mData 可以接受任何類型,所以我們在使用的時候要判斷一下 mData 是否是我們需要的數據類型,這裡我們介紹一下怎麼判斷 Swift 的 AnyObject 和 OC 的 id 是什麼類型:

OC:

if ([self.mData isKindOfClass:[MData class]]) { // 如果 self.mData 不是 MData 類型,判斷不成功
}

Swift:

if let data = self.mData as? MData { // 如果 self.mData 不是 MData 類型,判斷不成功
}

properties

如果 OC 的類導入到 Swift 中使用,類的 properties 會有如下變化:

Swift 中的屬性都是 noatomic 的,所以 OC 類中的 atomic 將會失效 OC 類中重寫的 getter/setter 方法都將失效

Hello! Swift 2

var -> let

相比 Swift 1.2,Swift 2 強制要求將在本方法體中值不會改變的量聲明為常量,所以在編寫 Swift 1.2 的代碼時,可以提前注意這一點,從而減小轉換成本。

println

Swift 2 中這個方法被刪除,不要使用。

do/while -> repeat/while

因為有變化,所以建議用 for / for…in 代替

面向協議編程

從 Swift 2 開始,我們可以對協議進行擴展,從此正式開啟了 Swift 的面向協議編程時代。因為目前還沒有在項目中具體使用,所以研究不是很深,大家可以參考下面三篇譯文:

Swift 2:面向協議編程

如何正確使用協議

Swift 2.0 中的面向協議的MVVM

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved