swift与OC相互引用的问题
原文地址:http://00red.com/blog/2015/06/02/swift-objectivec-compatible/
注:转载此文用于自己记录学习之用,非商用!
一、解决问题Swift项目需要使用封装好的Objective-c组件、第三方类库,苹果提供的解决方案能够处理日常大部分需求,但还不能称之为完美,混编过程中会遇到很多问题。本文将Swift兼容Objective-c的问题汇总,以帮助大家更好的使用Swift,内容列表如下: 1. Swift调用Objective-c代码 2. Objective-c调用Swift代码 3. Swift兼容Xib/Storyboard 4. Objective-c巧妙调用不兼容的Swift方法 5. 多Target编译错误解决 6. 第三方类库支持 二、基础混合编程Swift与Objective-c的代码相互调用,并不像Objective-c与C/C++那样方便,需要做一些额外的配置工作。无论是Swift调用Objective-c还是Objective-c调用Swift,Xcode在处理上都需要两个步骤: 2.1 Swift调用Objective-c代码Xcode对于Swift调用Objective-c代码,除宏定义外,其它支持相对完善。 2.1.1 使用Objetvie-c的第一步,告诉Xcode、哪些Objective-c类要使用,新建.h头文件,文件名可以任意取,建议采用“项目名-Bridging-Header.h”命令格式。 TipsSwift之IOS项目,在Xcode6创建类文件,默认会自动选择OS X标签下的文件,这时一定要选择iOS标签下的文件,否则会出现语法智能提示不起作用,严重时会导致打包出错。 2.1.2 第二步,Target配置,使创建的头文件生效设置Objective-C Bridging Header时,路径要配置正确,例如:创建的名为“ILSwift-Bridging-Header.h”文件,存于ILSwift项目文件夹的根目录下,写法如下: ILSwift/ILSwift-Bridging-Header.h 当然,在新项目中,直接创建一个Objective-c类,Xcode会提示: 直接选择Yes即可,如果不小心点了其它按钮,可以按照上面的步骤一步一步添加。2.2 Objective-c调用Swift代码2.2.1 Objective-c调用Swift代码两个步骤第一步告诉Xcode哪些类需要使用(继承自NSObject的类自动处理,不需要此步骤),通过关键字@objc(className)来标记
第二步引入头文件,Xcode头文件的命名规则为 $(SWIFT_MODULE_NAME)-Swift.h 示例如下: #import "ILSwift-Swift.h" Tips不清楚SWIFT_MODULE_NAME可通过以下步骤查看 2.2.2找不到$(SWIFT_MODULE_NAME)-Swift.h1.遇到此问题可按以下步骤做常规性检查1.确定导入SWIFT_MODULE_NAME)-Swift.h头文件的文件名正确 2.SWIFT_MODULE_NAME)-Swift.h在clean后没有重新构建,执行Xcode->Product->Build 2.头文件循环 在混合编程的项目中,由于两种语言的同时使用,经常会出现以下需求:在Swift项目中需要使用Objectvie-c写的A类,而A类又会用到Swift的一些功能,头文件的循环,导致编译器不能正确构建$(SWIFT_MODULE_NAME)-Swift.h,遇到此问题时,在.h文件做如下处理
在Objevtive-c的.m文件最上面,添加 #import "ILSwift-Swift.h" 出现Use of undecalared identifier错误或者找不到方法,如下: 引起的原因有以下几种可能:1.使用的Swift类不是继承自NSObject,加入关键字即可 2.SWIFT_MODULE_NAME)-Swift.h没有实时更新,Xcode->Product->Build 3.此Swift文件中使用了Objective-c不支持的类型或者语法,如private 出现部分方法找不到的问题,Xcode无智能提示: 此方法使用了Objective-c不支持的类型或者语法 苹果官方给出的不支持转换的类型
三、Xib/StoryBoard支持Swift项目在使用Xib/StoryBoard时,会遇到两种不同的问题 1.Xib:不加载视图内容 2.Storyboard:找不到类文件 3.1 Xib不加载视图内容在创建UIViewController时,默认选中Xib文件,在Xib与类文件名一致时,可通过以下代码实例化:
运行,界面上空无一物,Xib没有被加载。解决办法,在类的前面加上@objc(类名),例如:
Tips:StoryBoard中创建的UIViewController,不需要@objc(类名)也能够保持兼容 3.2 Storyboard找不到类文件Swift语言引入了Module概念,在通过关键字@objc(类名)做转换的时候,由于Storboard没有及时更新Module属性,会导致如下两种类型错误: 3.2.1 用@objc(类名)标记的Swift类或者Objective-c类可能出现错误:2015-06-02 11:27:42.626 ILSwift[2431:379047] Unknown class _TtC7ILSwift33ILNotFindSwiftTagByObjcController in Interface Builder file. 解决办法,按下图,选中Module中的空白,直接回车 3.2.2 无@objc(类名)标记的Swift类2015-06-02 11:36:29.788 ILSwift[2719:417490] Unknown class ILNotFindSwiftController in Interface Builder file. 解决办法,按下图,选择正确的Module 3.产生上面错误的原因:在设置好Storyboard后,直接在类文件中,添加或者删除@objc(类名)关键字,导致Storyboard中 Module属性没有自动更新,所以一个更通用的解决办法是,让Storyboard自动更新Module,如下: 3.3 错误模拟Demo下载为了能够让大家更清楚的了解解决流程,将上面的错误进行了模拟,想动手尝试解决以上问题的同学可以直接下载demo 四、Objective-c巧妙调用不兼容的Swift方法在Objective-c中调用Swift类中的方法时,由于部分Swift语法不支持转换,会遇到无法找到对应方法的情况,如下:
对应的$(SWIFT_MODULE_NAME)-Swift.h文件为: 从上面的头文件中可以看出,方法requestLogin使用了不支持的Swift枚举,转换时方法被自动忽略掉,有以下两种办法,可以巧妙解决类似问题: 4.1 用支持的Swift语法包装在Swift文件中,添加一个可兼容包装方法wrapRequestLogin,注意此方法中不能使用不兼容的类型或者语法
1 2 3 4 5 |
"_TtC12ILSwiftTests13ILHTTPRequest") @interface ILHTTPRequest : NSObject + (void)wrapRequestLogin:(NSString * __nonnull)userName password:(NSString * __nonnull)password callback:(void (^ __nonnull)(NSInteger))callback; - (SWIFT_NULLABILITY(nonnull) instancetype) 此时,我们可以在Objective-c中直接使用包装后的方法wrapRequestLogin |