Swift 3.0, много шума, а что на деле?

6830b3127c894d93b031dd903c6fb653.png

В начале мая на просторах интернета разработчики языка объявили, что начинают подготовку к релизу 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 версией языка. Коллеги из стабильных языков:

5aa9a800f9fe498c834ed2176a027ec9.gif

Вот так оказывается и живем. Но свитерам сфивтерам в этом плане повезло, потому что депенденси менеджеры (cocoapods, carthage) всегда подтягивают исходники проектов, а не бинарники, поэтому проблем с ABI совместимостью как таковых нет. Но, видимо, пока стоит воздержаться от написания проприетарных либ на сфивте и выкладывать их в паблик в виде бинарников. Да, ABI обещают добавить только к Swift 4.0.

Посмотрим на изменения в API

c3cf6d72d0f0463db50780f4dffc4a56.jpg

Даже метод 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 и синтаксиса замыканий/лямбд. В общем:

b54b76f6446c486bafcde2eb19132d3a.jpg

Полезные ссылки:

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, придать ему более сфивтовый стиль.

© Habrahabr.ru