Swift 3.0, много шума, а что на деле?
В начале мая на просторах интернета разработчики языка объявили, что начинают подготовку к релизу 3.0 версию языка. Разработка 3.0 идет в мастер ветке, по релизам, можно понять, что 3-го мая был релиз Swift 2.2.1. Затем в мастер начали вливать изменения касательно 3-ей версии языка. 9-го мая уже появился первый developer релиз из того же мастера, который можно накатить на последний xcode через установщик из swift.org/download/#snapshots, который включается через Preferences → Components → Toolchains.
Немного общей информации о будущем релизе
Примерно во время первого dev релиза Swift 3.0, разработчики заявили, что, к сожалению, не успевают реализовать ABI совместимость в 3.0 версии. Давайте разбираться, что это вообще значит, ибо я сам первый раз эти три буквы увидел вместе.
ABI это application binary interface, грубо говоря это совместимость бинарников разных версий между собой, можно привести аналогию с привычным нам API совместимостью, когда API 1.0 совместим с 2.0, но изменения, сделанные в 3.0, уже будут несовместимы с первой версией, поэтому при использовани API 3.0 нужно будет править код (в случае с ABI не править код, а пересобирать бинарник).
На самом деле, как оказалось для меня открытием, Swift еще никогда не имел ABI компатибили. Это говорит о том, что либа, собраная на Swift 2.0 уже не будет резолвиться с 2.2 версией языка. Коллеги из стабильных языков:
Вот так оказывается и живем. Но свитерам сфивтерам в этом плане повезло, потому что депенденси менеджеры (cocoapods, carthage) всегда подтягивают исходники проектов, а не бинарники, поэтому проблем с ABI совместимостью как таковых нет. Но, видимо, пока стоит воздержаться от написания проприетарных либ на сфивте и выкладывать их в паблик в виде бинарников. Да, ABI обещают добавить только к Swift 4.0.
Посмотрим на изменения в API
Даже метод didFinishLaunching подсвечивается варнингом, так как у него поменялась сигнатруа, сейчас он стал
/// swift 3
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]? = [:]) -> Bool {}
/// swift 2
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {}
Варнинги должны быть легко пофикшены тулзой для миграции на Swift 3.0 в Xcode в будущем.
Посмотрим на изменения в стандартной библиотеке Swift и в Foundation
ErrorType поменяли на ErrorProtocol
/// swift 3
enum MyError: ErrorProtocol {
case Success
case Fail(ErrorProtocol)
}
/// swift 2
enum MyError: ErrorType {
case Success
case Fail(ErrorType)
}
Изменения для Array
/// swift 3
sort() // сортирует сам себя
sorted() // сортирует и возвращает новый отсортированный массив не изменяя порядок в старом
/// swift 2
sortInPlace() // сортирует сам себя
sort() // сортирует и возвращает новый отсортированный массив не изменяя порядок в старом
то есть метод sort стал мутабельным, убрали sortInPlace и добавили sorted.
/// swift 3
reversed()
append(contentsOf: [T])
insert(T, at: Int)
joined(separator: String)
/// swift 2
reverse()
appendContentsOf([T])
insert(T, atIndex: Int)
joinWithSeparator(String)
Также убрали многие конструкторы и переименовали другие методы.
Изменения для String
/// swift 3
"3.0".components(separatedBy: ".")
"3.0".substring(to: 1)
"3.0".substring(from: 1)
"".data(using: NSUTF8StringEncoding)
"2.0".replacingOccurrences(of: "2", with: "3")
"".uppercased()
"".lowercased()
"3.0".contains(".")
"3.".appending("0")
("dir1" as NSString).appendingPathComponent("dir2")
" 3.0 ".trimmingCharacters(in: .whitespaces())
"".write(toFile: "/..", atomically: true, encoding: NSUTF8StringEncoding)
/// swift 2
"3.0".componentsSeparatedByString(".")
"3.0".substringToIndex(1)
"3.0".substringFromIndex(1)
"3.0".dataUsingEncoding(NSUTF8StringEncoding)
"2.0".stringByReplacingOccurrencesOfString("2", withString: "3")
"".uppercaseString
"".lowercaseString
"3.0".containsString(".")
"3.0".appendContentsOf(".release")
("dir1" as NSString).stringByAppendingPathComponent("dir2")
"3.0".stringByTrimmingCharactersInSet(.whitespaceCharacterSet())
"3.0".writeToFile("/..", atomically: true, encoding: NSUTF8StringEncoding)
Кейсы для enum сейчас в ловер кейсе
/// swift 3
UIInterfaceOrientation.portrait
Optional.some("")
Optional.none
/// swift 2
UIInterfaceOrientation.Portrait
Optional.Some("")
Optional.None
Изменения в UIKit
/// swift 3
let vc = UIViewController()
vc.present(some, animated: true, completion: nil)
vc.dismiss(animated: true, completion: nil)
vc.prepare(for: segue sender: button)
UIColor.white()
UIColor.blue()
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 100, y: 100))
// добавился знак _ в начале первого параметра + сократили имя аргумента функции, из-за чего будут варниги в проекте
func tableView(_ tableView: UITableView, numberOfSections section: Int) -> Int { return 0 }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell { return UITableViewCell() }
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: NSIndexPath) { }
/// swift 2
let vc = UIViewController()
vc.presentViewController(some, animated: true, completion: nil)
vc.dismissViewControllerAnimated(true, completion: nil)
vc.prepareForSegue(segue, sender: button)
UIColor.whiteColor()
UIColor.blueColor()
let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 0, y: 0))
path.addLineToPoint(CGPoint(x: 100, y: 100))
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 }
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { return UITableViewCell() }
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { }
Еще изменения
/// swift 3
NSData(contentsOf: "")
UIApplication.shared()
NSUserDefaults.standard().set("value", forKey: "key")
NSFileManager.default().fileExists(atPath: "/...")
NSBundle.main()
/// swift 2
NSData(contentsOfURL: "/")
UIApplication.sharedApplication()
NSUserDefaults.standardUserDefaults().setObject("value", forKey: "key")
NSFileManager.defaultManager().fileExistsAtPath("/")
NSBundle.mainBundle()
Вот так провели swiftification, в общем пострадал весь апи, а не только стандартная библиотека. Но стоит признаться, читабельность действительно стала лучше. Релиз Swift 3.0 намечен на осень. ABI compatibility запланирована в 4.0. Чего-то нового в Swift не стоит ожидать на WWDC 2016.
Встает вопрос, так что же всё таки выбрать на новый проект? Я голосую за Swift, с ним разработка идет намного быстрее и безопаснее ввиду очень строгой типизаций и рюшечек ввиде Optional и синтаксиса замыканий/лямбд. В общем:
Полезные ссылки:
https://swift.org/blog/
https://www.hackingwithswift.com/swift3
https://github.com/apple/swift-evolution
http://www.bensnider.com/abi-compatibility-whoopdty-do-what-does-it-all-mean.html
update
Стоит добавить, что разработчики Swift перелопатили весь API, чтобы сделать его как и задумывалось с первых дней языка, просто поддержка совместимости с Objective-C сделала своё дело и поломала первоначальный API дизайн. Планируется, что Swift будет работать на многих платформах, включая FreeBSD, Raspberry Pi, Android, Windows. Видимо, именно в версии 3.0 решили сделать полную переработку API, придать ему более сфивтовый стиль.