Xcode8中Swift3.0适配问题

作者: 光无影 | 来源:发表于2016-09-20 13:12 被阅读9491次

写在前面

收到一些小伙伴的来信,觉得可能下边没有表达清楚,先把大家关心的要点在此进行总结,有兴趣的可以看看下边的研究过程,没兴趣的直接看这段即可。

  • Xcode8支持Swift2.3和Swift3.0两种语编译,但是在整个工程中只能使用一种语法。
  • 如果想用Swift2.3版本开发,当弹出是否迁移到Swift3.0的对话框一律选择Later。所有的target(包括自己创建的和Cocoapods自动生成的)的Use Legacy Swift Language Version选择Yes。
  • 如果想用Swift3.0版本开发,当迁移到Swift3.0的界面选择target时,只要选择自己创建的target即可,Cocoapods导入的第三方不要勾选。所有的target(包括自己创建的和Cocoapods自动生成的)的Use Legacy Swift Language Version选择No.
  • Alamofire最新正式版本(4.0.0)只支持Swift3.0,想用Swift2.3开发的请选择3.5.0版本;
  • SnapKit的最新正式版本(3.0.0)同时支持Swift2.3和Swift3.0,请根据需求选择Use Legacy Swift Language Version的选项。
  • ReactiveCocoa的最新正式版本(4.2.2)只支持Swift2.3,凡是用到这个框架的项目只能使用Swift2.3开发。所有target包括自己创建的和Cocoapods自动生成的)的Use Legacy Swift Language Version选择Yes。

探究过程

Xcode8发布了,随着Xcode8一起到来的还有Swift3.0。相信好多小伙伴已经兴冲冲的下载了Xcode8,并且打开了自己的Swift项目想要尽快将自己的项目切换到Swift3.0吧。

Tip:

首先郑重提示,如果是Swift的项目:

  1. Xcode不要覆盖安装,最好保留Xcode7和Xcode8两个开发工具;
  2. 请先备份自己的项目,请先备份自己的项目,请先备份自己的项目;
  3. 如果项目迁移到Swift3.0失败,请用Xcode7打开自己备份项目继续开发,凡是用Xcode8打开过的Swift项目,Xcode7打开都会报错。

我也是这么想的,用Xcode8打开自己的项目,首先提示我们Swift语法修改了,询问我们是否要迁移到Swift3.0,如图所示:

是否转变当前的Swift语法

当然选择Convert了,选择后,如图所示:

转换到哪个版本的Swift

选择转换到Swift3.0,一路Next之后,发现,发现依然报错,然后我就傻眼了。

依然报错

仔细观察错误信息,发现报错大部分集中在了第三方框架SnapKit中,难道是SnapKit不支持Swift3.0,我们在GitHub上看到:


SnapKit最新版本支持Swift3.0

难道是由于我们项目中的SnapKit不是最新版本导致的?
更新后依然报错,这就尴尬了,人家明明说支持了,但是项目中就报错,这是为什么?

这个时候我们应该去百度一下,发现好多人说要设置这个选项:

是否使用旧版本的Swift语言

设置之后,有些小伙伴可能就编译成功了,有些小伙伴可能依然编译出错。那么编译未成功如何解决呢?下面我们就来研究一下这个编译选项到底该怎么设置。

正常来说,我们可以随便改自己写的代码,但是对于第三方的代码,如果我使用Cocopods导入的,一般会在代码的右上角看到这个锁形标志:

lock

这个标志表示当前文件被锁住,你没有修改的权限。所以我们最好不要修改第三方中的代码。但是主要问题又出在第三方框架中,所以我们优先解决第三方框架的Swift3.0的适配。

SnapKit适配Swift3.0

既然SnapKit的作者说SnapKit已经支持Swift3.0了,那么我们就先来适配SnapKit,首先用Xcode8新建一个空项目,利用Cocoapods导入SnapKit.

Podfile

打开工程,依然弹出这个选项:


是否转换到Swift3.0

刚才选择了Convert依然报错,可见不靠谱,这次我们全部选择Later。

编译后,报错:

报错

错误提示我们依然是“Use Legacy Swift Language Version”这个选项的问题。
我们来看看这个选项怎么设置,如图所示:

设置SnapKit的编译选项

因为SnapKit已经支持了Swift3.0,所以我们选择No,不支持旧的Swift版本,即使用Swift3.0的语法。编译通过。我们再来看看我们写的代码生成的target的编译选项:

自己的target的编译选项

由于Xcode8新建的工程默认使用Swift3.0的语法,所以此处默认选择为No。

Tip:

如果要使用Swift2.3的语法,请指定SnapKit的版本号为:0.22.0

官方提示!

ReactiveCocoa适配Swift3.0

相信在好多人在Swift中使用了响应式编程,提到响应式编程,就不得不说说RAC了,RAC是一个重型的OC框架,但是为了在Swift中可以使用,作者提供了Swift的桥接文件,所以,在Swift项目中导入了RAC,都会包含一些Swift的文件,这些Swift的文件也需要适配。

GitHub上RAC的作者在readme中写到:

readme

RAC 5 支持Swift3.0.x,RAC 4支持Swift2.x。我们在Cocoapods中搜索ReactiveCocoa这个库:


pod search ReactiveCocoa

只找到了4.2.2版本的库,我不知道上边提到的RAC 5 和 RAC 4 分别指什么。只能先用这个版本了。同样的,新建一个工程:

默认使用Swift3.0

使用Cocoapods导入RAC:

Podfile

是否迁移到Swift3.0依然选择Later,编译,报错:

报错

和SnapKit的错误一样,同样的,我们去设置ReactiveCocoa的targetsh设置一下参数:


编译设置

和SnapKit同样设置为No,编译,报错。我们可以看到,安装ReactiveCocoa同时安装了一个Result,看看它的target设置:

Result的便已设置

设置的为Yes,那我们也把ReactiveCocoa的设置为Yes。编译,依然报错:

依然报错

我们尝试着把自己的target设置修改一下:

修改自己工程的target设置

编译成功。

同时导入SnapKit和RAC

现在分别导入SnapKit和RAC都编译成功了,但是可以看出SnapKit支持Swift3.0。RAC不支持。那么如果两个同时导入该选什么呢?

经过测试,如果同事导入两个框架,所有的target的设置都得选择Yes。(大家可以自己试一下,在此不做赘述。)

可以看到SnapKit既支持Swift3.0,也支持Swift2.3。那么它是如何做到的呢?通过查看源代码可以看到:

源代码示例

通过这样的宏来判断当前的Swift的编译版本来编译不同的代码段,从而实现兼容Swift2.3和Swift3.0。

Alamofire

经过测试,Alamofire的4.0.0版本仅支持iOS9+和Swift3.0.x,如果想使用Swift2.3开发的同学可以安装Alamofire的3.5.0版本,设置所有的Use Legacy Swift Language Version为Yes。

总结

  • target的Build Setting的Use Legacy Swift Language Version选项的作用是设置当前target对应的文件是采用Swift2.3的语法编译还是Swift3.0的语法编译。当选择为Yes时,采用Swift2.3的语法编译;当选择是No时,采用Swift3.0的语法编译。
  • 新建的项目中,编译设置的原则为:所有的第三方中只要有一个第三方使用了Swift2.3的语法,那么所有的target的编译设置都应为Yes。如果都支持Swift3.0的语法,那么就可以设置为No。并且不能选择Unspecified。
  • 当Use Legacy Swift Language Version的选项设置为Yes时候,我们的工程只能使用Swift2.3来进行开发,当然你也可以像SnapKit那样利用宏来判断当前Swift的编译版本来实现适配Swift3.0,这样当以后迁移到Swift3.0也方便一些。

思考

既然每个target有自己单独的编译设置,理论上应该在编译的时候按照各自的target的编译设置来按照不同的Swift的版本编译,这样我们就可以自己的代码使用3.0编写,第三方根据各自不同进行不同的编译设置。以后想要迁移到完全的Swift3.0也更容易一些。但是目前看来编译的时候是统一按照我们缩写的target来编译的,这样的话单独设置各自的target还有什么意义呢?或许还需要一些别的设置才可以实现各自独立编译?对此有了解的同学麻烦告知一下,在此先谢过了。

相关文章

网友评论

  • 国强在线:我pod进项目的第三方不太喜欢设定版本,这样的话,哪个第三方更新,我就及时跟进,要不然第三方最新特性不能及时了解。但是我在做demo,关于同时集成ReactiveCocoa和SnapKit的时候,如果不设定SnapKit的版本号为0.22.0,就不能设定Use Legacy Swift Language Version为YES,你说的全部设为YES我没操作出来。我用OC写的demo。
    光无影:1、个人觉得,一般来说,项目内需要稳定,所以,我pod进项目的都会指定版本。因为有些第三方的更新可能会涉及到接口的更新,不利于项目稳定;
    2、第三方框架关于Swift2.3和Swift3.0就是通过版本号来区分的,可以参照官方README,他们也会要求指定版本的;
    3、关于第三方的新特性的研究应该在自己写的demo里进行验证,直接在项目代码中调试新特性不是一个明智的选择;
    4、OC写的demo为什么要用Swift的第三方呢?用OC的不是更好么?
  • aa0063499e66:我新建项目的时候convert 怎么选择swift2.3 没有选择的选项了
    光无影:@嗯_9e1d Xcode8.2不支持吗?我知道8.3不支持。不过已经可以全部转到Swift3.0了。
    aa0063499e66:@光无影 Xcode8.2不支持选择2.3了
    光无影:@嗯_9e1d convert中选择跳过,在工程设置里边设置。
  • 郭鵬飛on:用 cocoapod 导入编译没问题,但是不能调用方法;有 demo 么?最新的
    光无影:@郭鵬飛on 什么意思,没看懂你的问题。
  • OnlyFunny:写的挺好的, 支持一下!!!
  • 心语风尚:没有使用cocoaPods 直接放工程的报错 Argument label ‘:’ 怎么解决
    光无影:呃,表示没看懂,给的信息太少了。
    心语风尚:@光无影 argument label(:)
    光无影:@心语风尚 报什么错?
  • 803af0793eab:顶一个,好文章
  • 小菜一:snapkit 3.0.0没search出来啊
  • HuyaRC:转发:
  • ChauvetMa:@楼主,楼主怎么解决Alamofire的问题呢,就是我想用3.0的语法,但是又不想抛弃iOS 8.0
    羞答答不肯把头抬:@ChauvetMa 问一下 oc项目中混编swift 其布局想用SnapKit 我在podfile中要怎么写呢
    ChauvetMa:@光无影 我现在就是用的混编。 :smiley:
    光无影:@ChauvetMa 那就用AFN这个框架,和Alamofire是同一个作者,但是是OC写的,可以不用考虑Swift的版本。
  • 含泪若笑:不好意思 我还有一个问题 如果我用第三方的库,他们是不是都需要升级到2.3啊 还是更低也可以
  • 含泪若笑:你好。楼主,我想问一下,convert的时候需要选择target,我该怎么选择呢,他会有一些默认给我打钩的,我要转成2.3的,那如果第三方库不是2.3呢?我该怎么转化,全选吗?还是?
    含泪若笑:@光无影 明白,我试试,有问题再问你
    光无影:@hanleirx 记住一个原则,第三方的框架我们最好只用,不要修改。所以convert的时候我们只选择自己的target就可以了。第三方框架需要更新到指定的版本即可。
  • 赵凡之:很多集成进去的pod,Use Legacy Swift Language Version 为 undefine,为避免每个都手动改,可以在Podfile中加:
    post_install do |installer|
    installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
    config.build_settings['SWIFT_VERSION'] = '3.0'
    end
    end
    end
    光无影:@国强在线 这个是Swift的项目的设置,你OC的项目不用设置吧?
    国强在线:['SWIFT_VERSION'] = '3.0'就是Use Legacy Swift Language Version = no;['SWIFT_VERSION'] = '2.3'就是yes。我用oc建的工程,两个全导入,不设定固定的第三方版本,写3.0运行不了。因为RAC不支持3.0;按照上文所说,只有有一个版本库不支持swift3.0,那么就要降低到支持2.3.所以是不是要将['SWIFT_VERSION'] = '3.0'改为['SWIFT_VERSION'] = '2.3'?
    光无影:@赵凡之 非常感谢,我一直在找这个。
  • 5f58da0ef984:RAC5目前没有提供官方pod 但是master分支已经支持swift3.0 需要使用RAC的可以手动替换一下 https://github.com/ReactiveCocoa/ReactiveCocoa/issues/3172
    5f58da0ef984:@光无影 是啊 还有一种稍微优雅点 使用carthage集成RAC 通过carthage可以clone并build最新代码 也可以支持Swift3 不过这个我没试过 看官方issue上有提到
    光无影:@TomatoPeter 如何手动替换?是指直接拖到项目中吗?
  • 3e8537017d04:看过写的最详细的一篇文章。你们项目有没有升级?是不是说把所有target的Use Legacy Swift Language Version设置为no原来的工程不用动,就能在xcode8上面跑起来?而且第三方库不支持3.0,自己代码可以升级,然后所有第三方用老版本就可以了?
    fanguohui:@光无影 项目是SDK是Swift3.0, 但是用cocopods集成的第三方库有Alamofire 和 SwiftJSON 都是基于Swift2.0, 修改第三方库的use legacy Swift为YES, 一个报错,一个不报错,是什么情况
    光无影:@ccsob 首先,设置了所有target的Use Legacy Swift Language Version设置为no,代表你要试用Swift3.0的语法来开发,所以我们自己所写的代码必须转换到3.0的语法,不可能不动。(Swift3.0的语法详见我的另一篇文章——Swift3.0语法变化)其次,只要有一个第三方的库不支持3.0,那么自己的代码也不能使用3.0的语法来开发,所以自己的代码也不能升级。最后,Xcode8支持2.3和3.0两种语法编译,所以只要设置正确,不用升级到3.0,在Xcode8上也是可以跑起来的。
  • 快乐的小马农:想的很棒 :+1:
  • Fire_day:写的不错,对我很有帮助,谢谢了!粉一个
  • 健了个平_24:请问 Function types cannot have argument label xxxxxx 这个错误怎么解决?貌似定义闭包为函数参数时就有这个错误提示
    随风风流:@光无影 是当函数中有闭包作为参数的时候:
    func loadData(completion: (result: [Int]) -> ()) -> () {
    completion([456])
    }
    会报错,要求在闭包的参数名result前面加下划线变成“_ result"。
    这样添加下划线之后,在其它地方调用函数闭包的参数不会自动填充了,需要手动填写,没有block那么好用了。
    健了个平_24:@光无影 请问截图怎么发给您呢
    光无影:@平健周 我们的项目暂时不能迁移到Swift3.0,所以没有遇到过这个问题。你可以提供一下截图,看我能不能帮你解决一下。
  • 49203f3ee3a4:你好,为什么自己的Target下没有找到 Use Legacy Swift Language Version的项。
    光无影:@yutianlong0086 本文只针对Swift项目或者使用了Swift的第三方,OC项目的确没有这个选项。Swift3.0对OC没有影响。
    49203f3ee3a4:@光无影 嗯,我的是OC项目,好像是没有这个项。 作者有空能尝试下这个库么,按照上面的处理方式还是会报错, DKImagePickerController,这个也支持3.0了。
    光无影:@yutianlong0086 没有找对地方吧,请按照文章中截图给出的步骤寻找。
  • ShiyongTan:如果我新创建的项目都是 3.0的, 按照你的方法做了一下, 我使用的库和你一样, 然后还有有问题:
    ld: /Users/dudu1/Library/Developer/Xcode/DerivedData/AIOwnerSwift-egmrhzjavuwupxczfybqbldhxppo/Build/Products/Debug-iphonesimulator/Alamofire.framework/Alamofire compiled with newer version of Swift language (3.0) than previous files (2.0) for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    使用的库还有一个ReactiveCocoa, 其他的没有了, 新创建的项目一编译就出错. 问一下, 你又遇到过这样的问题吗. ?
    光无影:@ShiyongTan 你的项目是Swift3.0的,但是要想用RAC只能用Swift2.3的语法。
    ShiyongTan:可是为什么我是al报错呢?
    光无影:@ShiyongTan 请认真阅读文中“ReactiveCocoa适配Swift3.0”部分,其中提到这个问题并给出了解决办法。目前来说,如果你想使用ReactiveCocoa这个框架的话,只能使用Swift2.3的语法。
  • 小白猿:写的不错啊晓珊
    小白猿:@光无影 这倒是没太注意
    光无影:@PQ小白猿 为啥你是2楼,1楼呢?

本文标题:Xcode8中Swift3.0适配问题

本文链接:https://www.haomeiwen.com/subject/catoettx.html