Post on 12-Apr-2017
LET’S MIGRATE TO 3.0COCOAHEADS NANTES
David Bonnet - @iGranDav
19 January 2017
A LITTLE BIT OF HISTORY…
▸ From Swift 1.x to Swift 2.x
▸ Just remember ErrorType and throwable types
▸ Swift 3.0 is the first community version !
🎉 " ‣ it also breaks code ! 😅
⚠STILL NOT ABI STABLE !
Everything needs to be migrated
LET’S DO IT SOFTLYSWIFT 2.3
LET’S DO IT SOFTLY - SWIFT 2.3
A LIGHTWEIGHT UPDATE
▸ Only takes advantage of Nullability Checking on Objective-C Interoperability
// Swift 2.2 let image = CIImage(MTLTexture: texture, options: options) let extent = image.extent // this code can lead to a crash
// Swift 3.0 if let image = CIImage(MTLTexture: texture, options: options) { … }
▸ This can help you migrate quickly to the SDK 10 on a big base code %
5
LET’S DO IT SOFTLY - SWIFT 2.3
A TEMPORARY SOLUTION
▸ Xcode loses code sense (even more than usual)
▸ Sometimes completion code is absent / No code coloration when lost
▸ When showing real-time errors in source code, Xcode can get lost
▸ this is valid swift 2.3 code ! and it builds 🤕
▸ fixed in latest Xcode 8.2.1
▸ Xcode 8.2.x is the last version to support it! 😈
6
OK NOW FOR REALSWIFT 3.0
APPLE SOLUTIONLET’S MIGRATE - SWIFT 3.0
LET’S MIGRATE - SWIFT 3.0
APPLE SOLUTION - MIGRATION ASSISTANT
9
LET’S MIGRATE - SWIFT 3.0
APPLE SOLUTION - MIGRATION ASSISTANT IN REAL LIFE
10
😱Using Xcode 8.0
AN APPROACHLET’S MIGRATE - SWIFT 3.0
LET’S MIGRATE - SWIFT 3.0
1. MIGRATE YOUR DEPENDENCIES - COCOAPODS / CARTHAGE
▸ Long live Objective-C! 👻
▸ Almost nothing to do here…
▸ Some authors have annotated their libraries: better swift interoperability!
▸ Others have created a brand new swift version:
▸ MMDrawerController has been converted to DrawerController drawerController?.openDrawerGestureModeMask = MMOpenDrawerGestureMode.None [X] ’None' has been renamed to 'none'
12
https://github.com/mutualmobile/MMDrawerController/issues/476
drawerController?.openDrawerGestureModeMask = MMOpenDrawerGestureMode.none [X] 'none' is unavailable: use [] to construct an empty option set
LET’S MIGRATE - SWIFT 3.0
1. MIGRATE YOUR DEPENDENCIES - COCOAPODS / CARTHAGE
▸ ⚠ update your libraries means update also their APIs or introduce new features! extension Results {
func toArray() -> [T] { return self.map {$0} } }
extension RealmSwift.List {
func toArray() -> [T] { return self.map {$0} } }
13
=>//New definition in RxRealm extension List: NotificationEmitter { public typealias ElementType = Element public func toArray() -> [Element] { return Array(self) } }
14
▸ Migrate your code template before the migration!
▸ SwiftGen - https://github.com/AliSoftware/SwiftGen
-t swift3
LET’S MIGRATE - SWIFT 3.0
2. USING A CODE GENERATOR?
#!/bin/sh swiftgen strings
15
▸ Use a linter? Disable it during the migration.
▸ SwiftLint - https://github.com/realm/SwiftLint
1. Launch the migration assistant on your targets only
2. Analyse each source file:
1. Fix it if needed 😅
2. Uncheck from migration when it’s a third party file 😓
3. Do not hesitate to pass the migrator several times
LET’S MIGRATE - SWIFT 3.0
3. SOME OTHER THINGS
REAL WORLD PROBLEMSSHARING ISSUES AND FIXING THEM +
17
▸ To avoid renaming all your APIs calls:
▸ _ is automatically added, you probably want to name them properly
func updateIdentityWithName(_ name: String, firstname: String) throws
▸ Some Foundation objects with deleted NS prefix are casted to conform to new APIs
let url = NSURL(string: "http://someurl.com" ) URLComponents(url: url as URL, resolvingAgainstBaseURL: false)
REAL WORLD PROBLEMS
BEWARE SOME CHANGES ARE MADE AUTOMATICALLY
SE-0046
if let url = URL(string: "http://someurl.com" ) { URLComponents(url: url, resolvingAgainstBaseURL: false)
}
func updateIdentity(name: String, firstname: String) throws
18
▸ A cast to AnyObject is frequently added although new APIs accept Any
▸ Convert your JSON objects to [String: Any]
▸ ⚠ Some types becomes values types!
▸ public struct Date versus open class NSDate
▸ But it can simplify the reading:
▸ (x as NSDate).earlierDate(y) can be changed to x < y ? x : y
REAL WORLD PROBLEMS
BEWARE SOME CHANGES ARE MADE AUTOMATICALLY
https://developer.apple.com/swift/blog/?id=39
19
▸ Your potential if let or guard let on absoluteString will not be removed, it’s your job 🙂
▸ Tip: If you absolutely need to keep your code block you can use a do statement
REAL WORLD PROBLEMS
SOME APIS DO NOT RETURN OPTIONALS ANYMORE
open class NSURL { open var absoluteString: String? { get }
}
public struct URL { public var absoluteString: String { get }
}versus
do { //your code here
}
REAL WORLD PROBLEMS
OPTIONAL COMPARATORS DISAPPEARED
20
// FIXME: comparison operators with optionals were removed from the Swift Standard Libary. // Consider refactoring the code to use the non-optional operators. fileprivate func > <T: Comparable>(lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case let (l?, r?): return l > r default: return rhs < lhs } }
21
▸ Dispatch APIs are not correctly migrated (at least at that time using Xcode 8.0)
DispatchQueue.global(qos: .background).async { //do some work
}
DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 1) { //do some work in 1s from now
}
▸ dispatch_once doesn’t exist anymore 😢
▸ Use lazily initialised globals or static properties 😎
REAL WORLD PROBLEMS
GRAND CENTRAL DISPATCH
SE-0044 & SE-0088
22
▸ Remember Nullability Checking integrated into Swift 2.3
▸ ImplicitlyUnwrappedOptionals are considered like optionals now, but not all the time 😅
REAL WORLD PROBLEMS
OBJECTIVE-C INTEROPERABILITY
https://www.natashatherobot.com/swift-3-implicitly-unwrapped-optionals/
because File > New Project is a rare thing
func valueUp(value: Int!) { // oldValue is an Int? // since value doesn't need to be type checked let oldValue = value // Int? // newValue is an Int, // since value was forced to unwrap // b/c it had to be type checked to do the addition let newValue = value + 1 // Int
[…] } valueUp(value: 10)
23
▸ Swift 3 renamed a lot of objective-c based APIs automatically "
▸ Legacy swift annotations are still available
▸ nullability / generics
▸ NS_SWIFT_NAME / NS_REFINED_FOR_SWIFT / NS_SWIFT_UNAVAILABLE
▸ New annotations available
▸ NS_NOESCAPE to annotate your objective-c blocks (eg. @noespace)
▸ NSEXTENSIBLESTRING_ENUM to convert a string based obj-c enum to a struct
REAL WORLD PROBLEMS
OBJECTIVE-C INTEROPERABILITY
https://realm.io/news/altconf-nikita-lutsenko-objc-swift-interoperability/
because File > New Project is a rare thing
24
▸ I had to convert manually CGFloat.max to CGFloat.greatestFiniteMagnetude
▸ OptionSet are not converted as expected for default values :
▸ UIControlState() instead of .normal : it works but less readable
▸ Visibility changes : private becomes fileprivate etc…
▸ ⚠ Be aware of open versus public on your libraries
REAL WORLD PROBLEMS
SOME RANDOM NOTES
SE-0067
25
▸ map or flatmap returns LazyCollection types now :
▸ let list = Array(myLazyCollection) if you really need a Collection
▸ New compiler : new warnings like unused results 👾
▸ You can add _ to discard it: _ = foo()
▸ returned result is secondary: @discardableResult on the function can also avoid this warning
REAL WORLD PROBLEMS
SOME RANDOM NOTES
SE-0067
QUESTION TIMETHANKS FOR YOUR ATTENTION 😀
27
▸ A (mostly) comprehensive list of Swift 3.0 and 2.3 changes
▸ https://buildingvts.com/a-mostly-comprehensive-list-of-swift-3-0-and-2-3-changes-193b904bb5b1
▸ Swift migration guide
▸ https://swift.org/migration-guide/
▸ WWDC 2016 - Session 402 : What’s new in swift
▸ https://developer.apple.com/videos/play/wwdc2016/402/
▸ AltConf - Advanced ObjC <-> Swift Interoperability
▸ https://realm.io/news/altconf-nikita-lutsenko-objc-swift-interoperability/
LET’S MIGRATE TO 3.0
REFERENCES
David Bonnet - @iGranDavdavid.bonnet@cocoaheads.fr