小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Swift 項(xiàng)目兼容 Objective-C 問題匯總

 昵稱2735774 2015-06-24

版權(quán)申明:作者 一葉 已將本文在微信公眾平臺(tái)的發(fā)表權(quán)「獨(dú)家代理」給 iOS 開發(fā)(iOSDevTips)微信公共賬號(hào)。本文的所有打賞歸一葉所有。

作者介紹:一葉,四年 iOS 開發(fā),曾就職盛大文學(xué),現(xiàn)工作于奇點(diǎn)國(guó)際,熱愛移動(dòng)互聯(lián)網(wǎng),內(nèi)存分析及性能優(yōu)化經(jīng)驗(yàn)豐富,擅長(zhǎng)重構(gòu)、接口設(shè)計(jì)、框架搭建,歡迎訪問博客 http://

一、解決問題

Swift 項(xiàng)目需要使用封裝好的 Objective-c 組件、第三方類庫(kù),蘋果提供的解決方案能夠處理日常大部分需求,但還不能稱之為完美,混編過程中會(huì)遇到很多問題。本文將 Swift 兼容 Objective-c 的問題匯總,以幫助大家更好的使用 Swift,內(nèi)容列表如下:

1. Swift 調(diào)用 Objective-c 代碼2. Objective-c 調(diào)用 Swift 代碼3. Swift 兼容 Xib/Storyboard4. Objective-c 巧妙調(diào)用不兼容的 Swift 方法5. 多 Target 編譯錯(cuò)誤解決6. 第三方類庫(kù)支持

二、基礎(chǔ)混合編程

Swift 與 Objective-c 的代碼相互調(diào)用,并不像 Objective-c 與 C/C++ 那樣方便,需要做一些額外的配置工作。無(wú)論是 Swift 調(diào)用 Objective-c 還是 Objective-c 調(diào)用 Swift,Xcode 在處理上都需要兩個(gè)步驟:

2.1 Swift 調(diào)用 Objective-c 代碼

Xcode 對(duì)于 Swift 調(diào)用 Objective-c 代碼,除宏定義外,其它支持相對(duì)完善。

2.1.1 使用 Objetvie-c 的第一步,

告訴 Xcode、哪些 Objective-c 類要使用,新建 .h 頭文件,文件名可以任意取,建議采用 “ 項(xiàng)目名-Bridging-Header.h” 命令格式。

Tips

Swift 之 IOS 項(xiàng)目,在 Xcode6 創(chuàng)建類文件,默認(rèn)會(huì)自動(dòng)選擇 OS X 標(biāo)簽下的文件,這時(shí) 一定要選擇 iOS 標(biāo)簽 下的文件,否則會(huì)出現(xiàn)語(yǔ)法智能提示不起作用,嚴(yán)重時(shí)會(huì)導(dǎo)致打包出錯(cuò)。

2.1.2 第二步,Target 配置,使創(chuàng)建的頭文件生效

設(shè)置 Objective-C Bridging Header 時(shí),路徑要配置正確,例如:創(chuàng)建的名為 “ILSwift-Bridging-Header.h” 文件,存于 ILSwift 項(xiàng)目文件夾的根目錄下,寫法如下:

ILSwift/ILSwift-Bridging-Header.h

當(dāng)然,在新項(xiàng)目中,直接創(chuàng)建一個(gè) Objective-c 類,Xcode 會(huì)提示:

直接選擇 Yes 即可,如果不小心點(diǎn)了其它按鈕,可以按照上面的步驟一步一步添加。

2.2 Objective-c 調(diào)用 Swift 代碼

2.2.1 Objective-c 調(diào)用 Swift 代碼兩個(gè)步驟

第一步告訴 Xcode 哪些類需要使用 (繼承自 NSObject 的類自動(dòng)處理,不需要此步驟),通過關(guān)鍵字 @objc(className) 來標(biāo)記

import UIKit@objc(ILWriteBySwift)class ILWriteBySwift {   var name: String!   class func newInstance() -> ILWriteBySwift {       return ILWriteBySwift()   }}

第二步引入頭文件,Xcode 頭文件的命名規(guī)則為

$(SWIFT_MODULE_NAME)-Swift.h

示例如下:

#import 'ILSwift-Swift.h'
Tips

不清楚 SWIFT_MODULE_NAME 可通過以下步驟查看

2.2.2 找不到 $(SWIFT_MODULE_NAME)-Swift.h

  1. 遇到此問題可按以下步驟做常規(guī)性檢查

    1. 確定導(dǎo)入 SWIFT_MODULE_NAME)-Swift.h 頭文件的文件名正確
      2.SWIFT_MODULE_NAME)-Swift.h 在 clean 后沒有重新構(gòu)建,執(zhí)行 Xcode->Product->Build

  2. 頭文件循環(huán)

在混合編程的項(xiàng)目中,由于兩種語(yǔ)言的同時(shí)使用,經(jīng)常會(huì)出現(xiàn)以下需求:在 Swift 項(xiàng)目中需要使用 Objectvie-c 寫的 A 類,而 A 類又會(huì)用到 Swift 的一些功能,頭文件的循環(huán),導(dǎo)致編譯器不能正確構(gòu)建 $(SWIFT_MODULE_NAME)-Swift.h,遇到此問題時(shí),在 .h 文件做如下處理

// 刪除以下頭文件//#import 'ILSwift-Swift.h'// 通過代碼導(dǎo)入類@class ILSwiftBean;

在 Objevtive-c 的 .m 文件最上面,添加

#import 'ILSwift-Swift.h'

出現(xiàn) Use of undecalared identifier 錯(cuò)誤或者找不到方法,如下:

引起的原因有以下幾種可能:

1. 使用的 Swift 類不是繼承自 NSObject,加入關(guān)鍵字即可2.SWIFT_MODULE_NAME)-Swift.h 沒有實(shí)時(shí)更新,Xcode->Product->Build3. 此 Swift 文件中使用了 Objective-c 不支持的類型或者語(yǔ)法,如 private

出現(xiàn) 部分方法找不到 的問題,Xcode 無(wú)智能提示:

此方法使用了 Objective-c 不支持的類型或者語(yǔ)法

蘋果官方給出的不支持轉(zhuǎn)換的類型

Generics

Tuples

Enumerations defined in Swift

Structures defined in Swift

Top-level functions defined in Swift

Global variables defined in Swift

Typealiases defined in Swift

Swift-style variadics

Nested types

Curried functions

三、Xib/StoryBoard 支持

Swift 項(xiàng)目在使用 Xib/StoryBoard 時(shí),會(huì)遇到兩種不同的問題

1.Xib:不加載視圖內(nèi)容2.Storyboard:找不到類文件

3.1 Xib 不加載視圖內(nèi)容

在創(chuàng)建 UIViewController 時(shí),默認(rèn)選中 Xib 文件,在 Xib 與類文件名一致時(shí),可通過以下代碼實(shí)例化:

let controller = ILViewController()

運(yùn)行,界面上空無(wú)一物,Xib 沒有被加載。解決辦法,在類的前面加上 @objc(類名),例如:

import UIKit@objc(ILViewController)class ILViewController: UIViewController {}

Tips:

StoryBoard 中創(chuàng)建的 UIViewController,不需要 @objc(類名) 也能夠保持兼容

3.2 Storyboard 找不到類文件

Swift 語(yǔ)言引入了 Module 概念,在通過關(guān)鍵字 @objc(類名) 做轉(zhuǎn)換的時(shí)候,由于 Storboard 沒有及時(shí)更新 Module 屬性,會(huì)導(dǎo)致如下兩種類型錯(cuò)誤:

3.2.1 用 @objc(類名) 標(biāo)記的 Swift 類或者 Objective-c 類可能出現(xiàn)錯(cuò)誤:

2015-06-02 11:27:42.626 ILSwift[2431:379047] Unknown class _TtC7ILSwift33ILNotFindSwiftTagByObjcController in Interface Builder file.

解決辦法,按下圖,選中 Module 中的空白,直接回車

3.2.2 無(wú) @objc(類名) 標(biāo)記的 Swift 類

2015-06-02 11:36:29.788 ILSwift[2719:417490] Unknown class ILNotFindSwiftController in Interface Builder file.

解決辦法,按下圖,選擇正確的 Module

  1. 產(chǎn)生上面錯(cuò)誤的原因:
    在設(shè)置好 Storyboard 后,直接在類文件中,添加或者刪除 @objc(類名) 關(guān)鍵字,導(dǎo)致 Storyboard 中 Module 屬性沒有自動(dòng)更新,所以一個(gè)更通用的解決辦法是,讓 Storyboard 自動(dòng)更新 Module, 如下:

3.3 錯(cuò)誤模擬 Demo 下載

為了能夠讓大家更清楚的了解解決流程,將上面的錯(cuò)誤進(jìn)行了模擬,想動(dòng)手嘗試解決以上問題的同學(xué)可以直接下載 demo

四、Objective-c 巧妙調(diào)用不兼容的 Swift 方法

在 Objective-c 中調(diào)用 Swift 類中的方法時(shí),由于部分 Swift 語(yǔ)法不支持轉(zhuǎn)換,會(huì)遇到無(wú)法找到對(duì)應(yīng)方法的情況,如下:

import UIKitenum HTTPState {   case Succed, Failed, NetworkError, ServerError, Others}class ILHTTPRequest: NSObject {   class func requestLogin(userName: String, password: String, callback: (state: HTTPState) -> (Void)) {       dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in           NSThread.sleepForTimeInterval(3)           dispatch_async(dispatch_get_main_queue(), { () -> Void in               callback(state: HTTPState.Succed)           })       })   }}

對(duì)應(yīng)的 $(SWIFT_MODULE_NAME)-Swift.h 文件為:

SWIFT_CLASS('_TtC12ILSwiftTests13ILHTTPRequest')@interface ILHTTPRequest : NSObject- (SWIFT_NULLABILITY(nonnull) instancetype)init OBJC_DESIGNATED_INITIALIZER;@end

從上面的頭文件中可以看出,方法 requestLogin 使用了不支持的 Swift 枚舉,轉(zhuǎn)換時(shí)方法被自動(dòng)忽略掉,有以下兩種辦法,可以巧妙解決類似問題:

4.1 用支持的 Swift 語(yǔ)法包裝

在 Swift 文件中,添加一個(gè)可兼容包裝方法 wrapRequestLogin, 注意此方法中不能使用不兼容的類型或者語(yǔ)法

import UIKitenum HTTPState: Int {   case Succed = 0, Failed = 1, NetworkError = 2, ServerError = 3, Others = 4}class ILHTTPRequest: NSObject {   class func requestLogin(userName: String, password: String, callback: (state: HTTPState) -> (Void)) {       dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in           NSThread.sleepForTimeInterval(3)           dispatch_async(dispatch_get_main_queue(), { () -> Void in               callback(state: HTTPState.Succed)           })       })   }   class func wrapRequestLogin(userName: String, password: String, callback: (state: Int) -> (Void)) {       self.requestLogin(userName, password: password) { (state) -> (Void) in           callback(state: state.rawValue)       }   }}

對(duì)應(yīng)的 $(SWIFT_MODULE_NAME)-Swift.h 文件為:

SWIFT_CLASS('_TtC12ILSwiftTests13ILHTTPRequest')@interface ILHTTPRequest : NSObject+ (void)wrapRequestLogin:(NSString * __nonnull)userName password:(NSString * __nonnull)password callback:(void (^ __nonnull)(NSInteger))callback;- (SWIFT_NULLABILITY(nonnull) instancetype)init OBJC_DESIGNATED_INITIALIZER;@end

此時(shí),我們可以在 Objective-c 中直接使用包裝后的方法 wrapRequestLogin

4.2 巧妙使用繼承

使用繼承可以支持所有的 Swift 類型,主要的功能在 Objective-c 中實(shí)現(xiàn),不支持的語(yǔ)法在 Swift 文件中調(diào)用,例如,ILLoginSuperController 做為父類

@interface ILLoginSuperController : UIViewController@property (weak, nonatomic) IBOutlet UITextField *userNameField;@property (weak, nonatomic) IBOutlet UITextField *passwordField;- (IBAction)loginButtonPressed:(id)sender;@end////////////////////////////////////////////////////////////////@implementation ILLoginSuperController- (IBAction)loginButtonPressed:(id)sender{}@end

創(chuàng)建 Swift 文件,繼承自 ILLoginSuperController,在此 Swift 文件中調(diào)用那些不支持的語(yǔ)法

import UIKitclass ILLoginController: ILLoginSuperController {   override func loginButtonPressed(sender: AnyObject!) {       ILHTTPRequest.requestLogin(self.userNameField.text, password: self.passwordField.text) { (state) -> (Void) in           // 具體業(yè)務(wù)邏輯       }   }}

五、多 Target 編譯錯(cuò)誤解決

在使用多 Target 時(shí),會(huì)出現(xiàn)一些編譯錯(cuò)誤

5.1 Use of undeclared type

此類錯(cuò)誤,是因?yàn)楫?dāng)前運(yùn)行的 Target 找不到必須編譯文件。將文件添加到 Target 即可,如下支持 ILSwiftTests Target,選中 ILSwiftTests 前的復(fù)選框即可

5.2 does not have a member named

此類錯(cuò)誤可能由于如下兩種原因引起,解決辦法同上:

1. 此方法來自父類,父類文件沒有加入到當(dāng)前 Target2. 此方法來自擴(kuò)展,擴(kuò)展沒有加入到當(dāng)前 Target

Tips

如果檢查發(fā)現(xiàn),所有的類文件都已經(jīng)準(zhǔn)確添加到 Target 中,但編譯還是不通過,此時(shí)著重檢查橋接文件是否正確設(shè)置,是否將相應(yīng)的頭文件加入到了橋接文件中。如無(wú)特別要求,建議將所有 Target 的橋接文件全都指向同一文件。關(guān)于橋接文件的設(shè)置,請(qǐng)參考 2.1

六、第三方類庫(kù)支持

Swift 項(xiàng)目取消了預(yù)編譯文件,一些第三方 Objective-c 庫(kù)沒有導(dǎo)入必要框架 (如 UIKit) 引起編譯錯(cuò)誤

6.1 Cocoapods 找不到 .o 文件

在使用了 Cocoapods 項(xiàng)目中,會(huì)出現(xiàn)部分類庫(kù)的 .o 文件找不到,導(dǎo)致此種錯(cuò)誤主要是以下兩種問題:

1. 類庫(kù)本身存在編譯錯(cuò)誤2.Swift 沒有預(yù)編譯,UIKit 等沒有導(dǎo)入

將此庫(kù)文件中的代碼文件直接加到項(xiàng)目中,編譯,解決錯(cuò)誤

6.2 JSONModel 支持

在 Swift 中可以使用 JSONModel 部分簡(jiǎn)單功能,一些復(fù)雜的數(shù)據(jù)模型建議使用 Objevtive-c

import UIKit@objc(ILLoginBean)public class ILLoginBean: JSONModel {   var userAvatarURL: NSString?   var userPhone: NSString!   var uid: NSString!}

Tips

在 Swift 使用 JSONModel 框架時(shí),字段只能是 NSFoundation 中的支持類型,Swift 下新添加的 String、Int、Array 等都不能使用

6.3 友盟統(tǒng)計(jì)

Swift 項(xiàng)目中引入友盟統(tǒng)計(jì) SDK 會(huì)出現(xiàn) referenced from 錯(cuò)誤:

解決辦法,找到 Other Linker Flags,添加 -lz

七、綜述

現(xiàn)在大部分成熟的第三方框架都是使用 Objective-c 寫的,開發(fā)時(shí)不可避免的涉及到兩種語(yǔ)言的混合編程,期間會(huì)遇到很多奇怪的問題。因?yàn)槲粗庞刑剿鞯膬r(jià)值,Swift 的簡(jiǎn)潔快速,能夠極大的推進(jìn)開發(fā)進(jìn)度。所以從今天開始,大膽的開始嘗試。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多