Swift 3 新特性和迁移详解

写在前面

  • Swift 3.0 正式版发布了差很少快一个月了,断断续续的把手上和 Swift 相关的迁移到了Swift 3.0。因此写点小总结。git

背景

代码量(4万行)

  • 首先,我是今年年初才开始入手 Swift 的。加上 Swift 的 ABI 和 API 一直不稳定,因此没有在项目中大范围的使用,因此此次迁移的代码量很少,大概在4万行左右。github

迁移时间(一天左右)

  • 迁移时间上的话,大概是花了1天左右。两个混编项目,一个 Swift 为主的项目。期中 Swift 为主的项目 花了大概大半天时间,两个混编代码量差很少,可是一个花了小半天,还有一个差很少只花了半个小时(缘由先留个悬念~)。json

准备

在开发最初开发选择 Swift 的时候的不少决策也让我此次少了不少工做量。swift

界面用 xib 而不用纯代码

  • 阴差阳错的,和 Swift 相关的大部分界面都是用xib 画的。而这个 xib 在此次迁移中获得了很大的优点,xib 和 SB 的代码不适配 Swift 3。想当初要是使用代码写的 UI 的话,此次迁移改动估计会多不少吧。api

关于第三方库的选择:

  • 对于一个项目来讲,三方库彷佛成了一道必选菜,可是如何去选择这道菜呢?markdown

  • 对于三方库,当初的选择是,能用 OC 就尽可能用 OC。 毕竟能够OC 能够无缝衔接到 Swift,并且还相对稳定。闭包

  • 在选择 Swift 相关的三方库时,我尽可能值选择使用者比较多的库,例如AlamofireSnapKingfisherFabric等,由于使用者比较多,开发者会更愿意去维护,而不至于跳票。因此不会存在如今许多小伙伴面临的问题,想迁移,可是有些库没有更新。至少对于我来讲,当我想迁移的时候,全部和 Swift 相关的三方库都已经迁移到了 3.0 了。app

得益于上面两点,在迁移过程当中少了很多工做量。????dom

知识储备升级

迁移中的问题

Any && AnyObject

  • 我想在作迁移和作完迁移的同窗改的最多的一个就是  as AnyObjct? 吧?

  • 至少对于我来讲是的。

  • 和这个相关的基本是集合类型。在 Swift 2 中咱们一个用 [AnyObject] 来存听任何变量,甚至于存放struct类型的StringArray 等。可是按道理 Swift 的 AnyObject 指的是类,而 Any 才是包括structclassfunc 等全部类型。可是为什么 Struct 能够放入 [AnyObject] 呢?在  Swift 2 的时候会针对StringInt 等 Struct 进行一个 Implicit Bridging Conversions。而到了 Swift 3 则进行了一个**Fully eliminate implicit bridging conversions from Swift**改动。

  • 固然在个人项目中[AnyObject]实际上是小事,最麻烦的就是 [String:AnyObject]。由于当初写项目的时候,仍是处于 OC To Swift 的阶段因此对于 Dictionary ,基本采用了 [String:AnyObject], 因此在修改的时候,在不少地方为了这个修改。

    • 起初,我是照着 Xcode 的提示,在 Dictionary 后面的 value 后面加了一个 as AnyObjct?

    • 后来渐渐的发现我作了一件很傻比的事情,其实我只要把 [String:AnyObject] 改成 [String:Any] 就能够了。????

  • 这也就是为何在第一混编的项目中我花了那么多时间去修改代码了!得益于混编的第二个项目学习了 Yep 的思路,是把 [String:AnyObject] 命名为一个叫作 JSONDictionary 的类型。因此在 Any && AnyObect 这个事情上,就花了一点点时间。

// Swift 2
 var json = [String:AnyObect]()
json["key1"] = 1 
json["key2"] = "2" 

// to Swift 3 Step 1
 var json = [String:AnyObect]()
json["key1"] = 1 as AnyObject?
json["key2"] = "2" as AnyObject?

// to Swift 3 Step 2
 var json = [String:Any]()
json["key1"] = 1 
json["key2"] = "2"

// Swift 2 
public typealias JSONDictionary = [String: AnyObject]
// To Swift 3 Step 2
public typealias JSONDictionary = [String: Any]

Alamofire 等三方库支持 iOS8

  • 虽说我使用的三方库都在第一时间将库升级到了 Swift 3 ,可是期中 Alamofire 和 Snap 两个库最低适配只支持到了 iOS 9,为了不和产品撕逼,不得不想办法解决这个适配问题。下面以 Alamofire  为例

  • 其实三方库么,不必定只用 Cocoapods 的。因此打算下载代码而后直接撸源码。

  • Alamofire的 Xcode 修改成最低适配 8.0,而后编译查找不经过的函数,并删除。(其实这些函数都是 iOS 9 新加的函数,因此删除不影响什么。)

  • 大概花了 半个小时左右就能够删完了,而后直接拖到项目中就能够了~

  • Snap 其实只要拖进去就行了,暂时不须要修改什么。

// 其实都是 !os(watchOS) 这个宏下面的
#if !os(watchOS)

@discardableResult
public func stream(withHostName hostName: String, port: Int) -> StreamRequest {
    return SessionManager.default.stream(withHostName: hostName, port: port)
}

@discardableResult
public func stream(with netService: NetService) -> StreamRequest {
    return SessionManager.default.stream(with: netService)
}

#endif

@escaping

  • 这个是我在适配中最蛋疼的坑

  • 首先在看swift-evolution只是了解到@escaping 必须显示声明。可是不知道@escaping的闭包,在函数体内没法再修改。

let pedonmeter:CMPedometer = CMPedometer()

    func getPedometerDataFromDate(_ datet:Date?, withHandler handler: @escaping (CMPedometerData?, Error?) -> ()){


        // 编译错误
        pedonmeter.queryPedometerDataFromDate(startTime, toDate:endTime, withHandler: { (pedometerData:CMPedometerData?, error:NSError?) -> Void in

            guard let pedometerData = pedometerData else { return }
            handler(pedometerData, error)

            // 作一些事情

        })
        // 最后逼不得已只能不修改了,函数外面就作一些事情了
        pedonmeter.queryPedometerData(from: startTime, to: endTime, withHandler:  handler as! CMPedometerHandler)

    }

Result of call to 'funtion' is unused

  • 这其实不是一个 编译错误,可是这个警告最开始让我有点懵逼.返回值不用难道要我都修改一下?

  • 最开始其实我是这么修改的 let _ = funtion(),可是后面在看SE-0047的时候发现@discardableResult也是能够达到这个效果的。

Date && NSDate

  • 由于有个项目中使用的 DateTools 这个工具。它有一个 NSDate + Tools 的分类。

  • 可是在写 Swift 3 的过程当中我发现若是变量是 Date 类型的没法使用NSDate + Tools 这个类型,必须显示声明date as NSDate 这样才能调用分类的一些个方法。

  • 这个让使用 OC 的库的时候会感受十分不舒服,毕竟不少 NS 的前缀去掉了。全部都显示声明太不友好了。

CAAnimationDelegate

  • 这个其实好像是 Xcode 8 的修改。由于以前CAAnimationDelegate 是一个分类。大概声明以下:

@interface NSObject (CAAnimationDelegate)- (void)animationDidStart:(CAAnimation *)anim;
- 
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;@end
  • 以前是在 vc 中只要重写一下 animationDidStart 函数就能够了。可是新的不行,起初觉得是 Swift 3 的变化,可是实际上是 Xcode 8 中的修改。将 CAAnimationDelegate 变成了一个协议。我感受这个修改是为了适配   Swift 3 ?变化以下:

@protocol CAAnimationDelegate @optional- (void)animationDidStart:(CAAnimation *)anim;
- 
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;@end

由于宽度时间比较长,其余的暂时想不到了。未完待续吧...

其余

总结

  • 总的说来此次迁移没有想象中的那么痛苦,虽然提案的改动很大,可是得益于 Xcode 8 的迁移工具,此次迁移花费时间很少,固然也有可能和个人代码量有关系~

  • 在迁移完以后,再看代码,会发现 Swift 更加的优雅了,至少相比于 2 来讲好了不少,至于好在哪里?你本身写写不就知道了咯。

  • 最后,终于能够把 Xocde 7 卸载,不再用担忧两个一块儿开无脑闪退了!!!

  • 最后对于明年的 Swift 4 只想说 快来吧~分分钟把你解决!

  • 其实适配之路才刚刚开始,由于 Xcode 8 自动转的代码并无很好的 Swift 3 化。目前只是说在 Swift 3 能够编译经过了而已~

更多

工做之余,写了点笔记,若是须要能够在个人 GitHub 看



文章转自  Damonwong的简书
 
其余值得参考文献收藏:
相关文章
相关标签/搜索