
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)**来标记
@R_301_5565@UIKit@objc(ILWriteBySwift)classILWriteBySwift{varname:String!classfuncnewInstance()->ILWriteBySwift{returnILWriteBySwift()}} 第二步引入头文件,Xcode头文件的命名规则为
$(SWIFT_MODulE_name)-Swift.h
示例如下:
#@R_301_5565@"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文件做如下处理
//删除以下头文件//#@R_301_5565@"ILSwift-Swift.h"//通过代码导入类@classILSwiftBean;
在Objevtive-c的.m文件最上面,添加
#@R_301_5565@"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不支持的类型或者语法
苹果官方给出的不支持转换的类型
Generics
@H_419_180@Tuples
@H_419_180@Enumerations defined in Swift
@H_419_180@Structures defined in Swift
@H_419_180@top-level functions defined in Swift
@H_419_180@Global variables defined in Swift
@H_419_180@Typealiases defined in Swift
@H_419_180@Swift-style variadics
@H_419_180@nested types
@H_419_180@CurrIEd functions
Swift项目在使用Xib/StoryBoard时,会遇到两种不同的问题
1.Xib:不加载视图内容
2.Storyboard:找不到类文件
###3.1 Xib不加载视图内容
在创建UIVIEwController时,默认选中Xib文件,在Xib与类文件名一致时,可通过以下代码实例化:
letcontroller=ILVIEwController()
运行,界面上空无一物,Xib没有被加载。解决办法,在类的前面加上**@objc(类名)**,例如:
@R_301_5565@UIKit@objc(ILVIEwController)classILVIEwController:UIVIEwController{} 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语法不支持转换,会遇到无法找到对应方法的情况,如下:
@R_301_5565@UIKitenumhttpState{caseSucced,Failed,NetworkError,ServerError,Others}classILhttpRequest:NSObject{classfuncrequestLogin(username:String,password:String,callback:(state:httpState)->(VoID)){dispatch_async(dispatch_get_global_queue(0,0),{()->VoIDinNSThread.sleepForTimeInterval(3)dispatch_async(dispatch_get_main_queue(),{()->VoIDincallback(state:httpState.Succed)})})}} 对应的**$(SWIFT_MODulE_name)-Swift.h**文件为:
SWIFT_CLASS("_TtC12ILSwiftTests13ILhttpRequest")@interfaceILhttpRequest:NSObject-(SWIFT_NulLABIliTY(nonnull)instancetype)initOBJC_DESIGNATED_INITIAliZER;@end 从上面的头文件中可以看出,方法**requestLogin**使用了不支持的Swift枚举,转换时方法被自动忽略掉,有以下两种办法,可以巧妙解决类似问题:
4.1 用支持的Swift语法包装
在Swift文件中,添加一个可兼容包装方法**wrapRequestLogin**,注意此方法中不能使用不兼容的类型或者语法
@R_301_5565@UIKitenumhttpState:Int{caseSucced=0,Failed=1,NetworkError=2,ServerError=3,Others=4}classILhttpRequest:NSObject{classfuncrequestLogin(username:String,{()->VoIDincallback(state:httpState.Succed)})})}classfuncwrapRequestLogin(username:String,callback:(state:Int)->(VoID)){self.requestLogin(username,password:password){(state)->(VoID)incallback(state:state.rawValue)}}} 对应的**$(SWIFT_MODulE_name)-Swift.h**文件为:
SWIFT_CLASS("_TtC12ILSwiftTests13ILhttpRequest")@interfaceILhttpRequest:NSObject+(voID)wrapRequestLogin:(Nsstring*__nonnull)usernamepassword:(Nsstring*__nonnull)passwordcallback:(voID(^__nonnull)(NSInteger))callback;-(SWIFT_NulLABIliTY(nonnull)instancetype)initOBJC_DESIGNATED_INITIAliZER;@end 此时,我们可以在Objective-c中直接使用包装后的方法**wrapRequestLogin**
4.2 巧妙使用继承
使用继承可以支持所有的Swift类型,主要的功能在Objective-c中实现,不支持的语法在Swift文件中调用,例如,**ILLoginSuperController**做为父类
@interfaceILLoginSuperController:UIVIEwController@property(weak,nonatomic)IBOutletUITextFIEld*usernameFIEld;@property(weak,nonatomic)IBOutletUITextFIEld*passwordFIEld;-(IBAction)loginbuttonpressed:(ID)sender;@end////////////////////////////////////////////////////////////////@implementationILLoginSuperController-(IBAction)loginbuttonpressed:(ID)sender{}@end```创建Swift文件,继承自**ILLoginSuperController**,在此Swift文件中调用那些不支持的语法```ruby@R_301_5565@UIKitclassILLoginController:ILLoginSuperController{overrIDefuncloginbuttonpressed(sender:AnyObject!){ILhttpRequest.requestLogin(self.usernameFIEld.text,password:self.passwordFIEld.text){(state)->(VoID)in//具体业务逻辑}}} 五、多Target编译错误解决 在使用多Target时,会出现一些编译错误
5.1 Use of undeclared type此类错误,是因为当前运行的Target找不到必须编译文件。将文件添加到Target即可,如下支持**ILSwiftTests** Target,选中**ILSwiftTests**前的复选框即可
此类错误可能由于如下两种原因引起,解决办法同上:
Tips1.此方法来自父类,父类文件没有加入到当前Target
2.此方法来自扩展,扩展没有加入到当前Target
如果检查发现,所有的类文件都已经准确添加到Target中,但编译还是不通过,此时着重检查桥接文件是否正确设置,是否将相应的头文件加入到了桥接文件中。如无特别要求,建议将所有Target的桥接文件全都指向同一文件。关于桥接文件的设置,请参考**2.1**
六、第三方类库支持Swift项目取消了预编译文件,一些第三方Objective-c库没有导入必要框架(如UIKit)引起编译错误
6.1 Cocoapods找不到.o文件在使用了Cocoapods项目中,会出现部分类库的.o文件找不到,导致此种错误主要是以下两种问题:
1.类库本身存在编译错误
2.Swift没有预编译,UIKit等没有导入
将此库文件中的代码文件直接加到项目中,编译,解决错误
6.2 JsONModel支持在Swift中可以使用JsONModel部分简单功能,一些复杂的数据模型建议使用Objevtive-c
@R_301_5565@UIKit@objc(ILLoginBean)publicclassILLoginBean:JsONModel{varuserAvatarURL:Nsstring?varuserPhone:Nsstring!varuID:Nsstring!} Tips 在Swift使用JsONModel框架时,字段只能是NSFoundation中的支持类型,Swift下新添加的String、Int、Array等都不能使用
6.3 友盟统计Swift项目中引入友盟统计SDK会出现**referenced from**错误:
解决办法,找到**Other linker Flags**,添加**-lz**
七、综述现在大部分成熟的第三方框架都是使用Objective-c写的,开发时不可避免的涉及到两种语言的混合编程,期间会遇到很多奇怪的问题。因为未知才有探索的价值,Swift的简洁快速,能够极大的推进开发进度。所以从今天开始,大胆的开始尝试
总结我有一杯洒,可以慰风尖,哈哈~~哈~
以上是内存溢出为你收集整理的Swift项目兼容Objective-c问题汇总全部内容,希望文章能够帮你解决Swift项目兼容Objective-c问题汇总所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)