[iOS][Swift] Swift 3.0の変更点まとめ
今回の記事では、Swift3.0でどのような変更があるのか、現時点(2016/5/18)での情報を元にまとめてみました。
https://github.com/apple/swift-evolutionにはImplemented proposals for Swift 3として新機能/変更などの提案が載っています。
Swift3.0は Expected release date: Late 2016 (今年の後期に登場予定) なので、今からどんな変更があるのか予習しておくと良いかもしれません。
※ 尚、Accepted proposals which do not have a complete implementation(承認されたけど実装されていないよ?)の一覧にあるものに関しては、今回のリストから除外します。
翻訳ミスなど内容に不備がありましたら、ご指摘頂ければ幸いです。
一覧
Implemented proposals for Swift 3
SE-0002: Removing currying func declaration syntax
カリー化関数宣言構文を削除
func foo(x: Int)(y: Int)
の有効性は限定的で、実装が複雑になるから削除する必要があります。
サンプル
// Before: func curried(x: Int)(y: String) -> Float { return Float(x) + Float(y)! } // After: func curried(x: Int) -> (String) -> Float { return {(y: String) -> Float in return Float(x) + Float(y)! } }
SE-0003: Removing var from Function Parameters
関数のパラメータからvarを削除
関数のパラメータは、デフォルトでは変更出来ません。
func foo(i: Int) { i += 1 // NG } func foo(var i: Int) { i += 1 // OK(ただし呼び出し元は変更されない) }
func doSomethingWithVar(var i: Int) { i = 2 // 変更は出来るが、呼び出し元に影響が無い } func doSomethingWithInout(inout i: Int) { i = 2 // 呼び出し元も変更される } var x = 1 print(x) // 1 // varの時 doSomethingWithVar(x) print(x) // 1 // inoutの時 doSomethingWithInout(&x) print(x) // 2
varが、多くの場合、関数のパラメータとしてのinoutと混同されています。 そのため、関数のパラメータからvarが削除される様です。
サンプル
// Before: func foo(var i: Int) { } // After: func foo(i: Int) { var i = i }
SE-0004: Remove the ++ and -- operators
++ -- 演算子を削除
現在、以下の演算子があります。
let a = ++x let b = x++ let c = --x let d = x--
上記の ++ -- 演算子が削除されます。
サンプル
// Before: x++ // After: x += 1
SE-0005: Better Translation of Objective-C APIs Into Swift
Objective-CのAPIをSwift用に最適化
SwiftのAPI設計ガイドラインに合わせて、型、メソッド、プロパティ、などの名前が最適化される様です。
- swift_name属性の適用を一般化
- 冗長な型名を省略する
- デフォルト引数を追加
- 最初の引数のラベルを追加
- Booleanのプロパティの先頭にはisをつける
- Lowercase values
- compare(_:) -> NSComparisonResult
置き換えの例
UIBezierPath API in Swift 2
class UIBezierPath : NSObject, NSCopying, NSCoding { convenience init(ovalInRect: CGRect) func moveToPoint(_: CGPoint) func addLineToPoint(_: CGPoint) func addCurveToPoint(_: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint) func addQuadCurveToPoint(_: CGPoint, controlPoint: CGPoint) func appendPath(_: UIBezierPath) func bezierPathByReversingPath() -> UIBezierPath func applyTransform(_: CGAffineTransform) var empty: Bool { get } func containsPoint(_: CGPoint) -> Bool func fillWithBlendMode(_: CGBlendMode, alpha: CGFloat) func strokeWithBlendMode(_: CGBlendMode, alpha: CGFloat) func copyWithZone(_: NSZone) -> AnyObject func encodeWithCoder(_: NSCoder) }
UIBezierPath API in Swift 3
class UIBezierPath : NSObject, NSCopying, NSCoding { convenience init(ovalIn rect: CGRect) func move(to point: CGPoint) func addLine(to point: CGPoint) func addCurve(to endPoint: CGPoint, controlPoint1 controlPoint1: CGPoint, controlPoint2 controlPoint2: CGPoint) func addQuadCurve(to endPoint: CGPoint, controlPoint controlPoint: CGPoint) func append(_ bezierPath: UIBezierPath) func reversing() -> UIBezierPath func apply(_ transform: CGAffineTransform) var isEmpty: Bool { get } func contains(_ point: CGPoint) -> Bool func fill(_ blendMode: CGBlendMode, alpha alpha: CGFloat) func stroke(_ blendMode: CGBlendMode, alpha alpha: CGFloat) func copy(with zone: NSZone = nil) -> AnyObject func encode(with aCoder: NSCoder) }
SE-0006: Apply API Guidelines to the Standard Library
標準ライブラリへAPIのガイドラインを適用
全体の標準ライブラリを見直し、ガイドラインに従うために更新します。
提案内容(意訳)
- プロトコル名からタイプサフィックスを取り除きます
- generator概念は全てのAPIで抽象化されます
- Bitは削除されたからIntを使ってね
- 安全でないポインタ型からNo-argument initializersは削除されました。代わりにnilを使ってね
- PermutationGeneratorを削除しました
- MutableSliceableを削除しました。代わりにMutableCollection使ってね
- sort() => sorted(), sortInPlace() => sort().
- reverse() => reversed().
- enumerate() => enumerated().
- partition() APIが簡略化されたよ
- SequenceType.minElement() => .min(), .maxElement() => .max().
- 配列およびコレクションのアダプターのためのいくつかの初期化子を削除したよ。代わりに対応するアルゴリズムの関数やメソッドを呼びだしてね
- いくつかの関数のプロパティを逆?にしたよ
- String factory methodsでnul-terminated UTF-8 data (別名 C文字列) が初期化子になりました
SE-0007: Remove C-style for-loops with conditions and incrementers
C-Styleのfor文の削除
Swift3.0では -- と ++ が削除されるので、C-Style(for var i = 0 ; i < 10 ; i++ { })のようなループ文は無くなります。 新しいfor文は既にSwift 2.2に実装されていています。
サンプル
// Before: for var i = 0 ; i < 10 ; i++ { } // After: for i in 0..<10 { }
// Before: for var i = 0 ; i <= 10 ; i++ { } // After: for i in 0...<10 { }
SE-0008: Add a Lazy flatMap for Sequences of Optionals
オプショナル配列のためのLazyflatMapを追加
現在、Swiftの標準ライブラリでは2種類のflatMapがあります。
// オプショナルではない [1, 2, 3] .flatMap { n in n..<5 } // [1, 2, 3, 4, 2, 3, 4, 3, 4] // オプショナル (1...10) .flatMap { n in n % 2 == 0 ? n/2 : nil } // [1, 2, 3, 4, 5]
それがそれぞれで.lazyしたときの挙動が違うので治そうということみたいです。
[引用]Swiftに今後追加される言語仕様について調べてみた
[1, 2, 3] .lazy .flatMap { n in n..<5 } // LazyCollection<FlattenBidirectionalCollection<LazyMapCollection<Array<Int>, Range<Int>>>> (1...10) .lazy .flatMap { n in n % 2 == 0 ? n/2 : nil } // [1, 2, 3, 4, 5]
SE-0016: Adding initializers to Int and UInt to convert from UnsafePointer and UnsafeMutablePointer
UnsafePointerとUnsafeMutablePointerから変換するためのInt uintに初期化子を追加します
int、uintから安全で無い[Mutable]のポインタを作成出来るのと同様に、[Mutable]なポインタからもint、uintを作成出来ることが出来るはずです。
これによりintptr_t、 uintptr_tのパラメーターでCの関数を呼び出すことが出来ますし、UnsafePointersによって許可されているよりも高度なポインタ演算をすることができます。
SE-0019: Swift Testing
Swiftのテスト
Package Managerへテストが統合される?ことにより、安定性と信頼性の高くなります。
SE-0023: API Design Guidelines
APIの設計ガイドライン
全体の標準ライブラリを見直し、ガイドラインに従うためにそれを更新します。
(関連:SE-0006: Apply API Guidelines to the Standard Library)
SE-0029: Remove implicit tuple splat behavior from function applications
暗黙的なタプルスプラットの動作を削除
以下の関数があるとします。
func foo(a : Int, b : Int) {}
一般的な呼び出し方の例は下記のようになります。
foo(42, b : 17)
あまり知られていませんが、下記のようにタプル型の単一の値として引数を渡すことが出来ます。
let x = (1, b: 2) foo(x)
この挙動が削除される様です。
注意:以下のような関数に値としてタプルを渡す機能は削除されません。
func f1(a : (Int, Int)) { ... } let x = (1, 2) f1(x) func f2<T>(a : T) -> T { ... } let x = (1, 2) f2(x)
SE-0031: Adjusting inout Declarations for Type Decoration
タイプの装飾のためのinout宣言を調整
inoutを記述する位置が変更になります。
サンプル
// before func foo(inout a:Int, inout b:Int) { } // after func foo(a: inout Int, inout b:Int) { }
SE-0033: Import Objective-C Constants as Swift Types
Objective-CのコンテンツをSwiftのタイプとしてインポート
Objective-C APIの定数部分がEnumやStructで定義されるようになるみたいです。
サンプル
一例として、
// befor let quantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMassIndex) // after let quantityType = HKQuantityType.quantityTypeForIdentifier(.BodyMassIndex)
SE-0037: Clarify interaction between comments & operators
コメントの表記ルールを明確に
現在、コメントであるかの判定はいくつかの矛盾があります。
// OK let sum = 1 +/* comment */2 // OK if /* Commtnt */foo { return } // Error if /* Commtnt */!foo { return }
この曖昧なルールが修正になり、コメント自体は空白として扱われるようです。
SE-0039: Modernizing Playground Literals
モダンなPlaygroundでのリテラル
Playgroundのリテラルが再設計されるようです。
SE-0040: Replacing Equal Signs with Colons For Attribute Arguments
Attributesで=ではなく:を使うように
以前まで、
@available(*, deprecated=9.0)
と記載していましたが、
@available(*, deprecated: 9.0)
となり、=が:となる様です。
SE-0043: Declare variables in 'case' labels with multiple patterns
複数のパターンの"case"のラベルの変数
下記のように複数のパターンが含まれている場合エラーになってしまいますが、このエラーが出ないようにする修正の様です。
enum MyEnum { case Case1(Int,Float) case Case2(Float,Int) } switch value { case let .Case1(x, 2), let .Case2(2, x): print(x) case .Case1, .Case2: break }
SE-0044: Import as Member
Memberのインポート
Cのライブラリやフレームワークをインポート出来ますがSwiftっぽくありませんが、この修正でSwiftに最適化されるようです。
サンプル
// befor override func drawRect(rect: CGRect) { let context: CGContext = UIGraphicsGetCurrentContext()! let toCenter = CGPoint(x: bounds.width/2.0, y: bounds.height/2.0) let angle = CGFloat(M_PI / 16) var transform = CGAffineTransformIdentity for _ in 0..<32 { triangulateRect(bounds, inputTransform: transform, context: context) transform = CGAffineTransformTranslate(transform, toCenter.x, toCenter.y) transform = CGAffineTransformRotate(transform, angle) transform = CGAffineTransformTranslate(transform, -toCenter.x, -toCenter.y) } CGContextSetLineWidth(context, bounds.size.width / 100) CGContextSetGrayStrokeColor(context, 0.5, 1.0) CGContextDrawPath(context, .Stroke) } func triangulateRect(bounds: CGRect, inputTransform: CGAffineTransform, context: CGContext) { var transform = inputTransform // Triangle from top left corner, to bottom middle, to top right, and then // draw the boundary let topLeft = bounds.origin let bottomRight = CGPoint(x: bounds.size.width, y: bounds.size.height) let path = CGPathCreateMutable() CGPathMoveToPoint(path, &transform, topLeft.x, topLeft.y) CGPathAddLineToPoint(path, &transform, CGRectGetMidX(bounds), bottomRight.y) CGPathAddLineToPoint(path, &transform, bottomRight.x, topLeft.y) CGPathAddLineToPoint(path, &transform, topLeft.x, topLeft.y) CGPathAddLineToPoint(path, &transform, topLeft.x, bottomRight.y) CGPathAddLineToPoint(path, &transform, bottomRight.x, bottomRight.y) CGPathAddLineToPoint(path, &transform, bottomRight.x, topLeft.y) CGContextAddPath(context, path) } // after override func drawRect(rect: CGRect) { let context: CGContext = UIGraphicsGetCurrentContext()! let toCenter = CGPoint(x: bounds.width/2.0, y: bounds.height/2.0) let angle = CGFloat(M_PI / 16) var transform = CGAffineTransform.identity for _ in 0..<32 { triangulateRect(bounds, inputTransform: transform, context: context) transform = transform.translate(toX: toCenter.x, toY: toCenter.y) .rotate(angle: angle) .translate(toX: -toCenter.x, toY: -toCenter.y) } context.lineWidth = bounds.size.width / 100 context.strokeColor = CGColor(gray: 0.5, alpha: 1.0) context.drawPath(mode: .Stroke) } func triangulateRect(bounds: CGRect, inputTransform: CGAffineTransform, context: CGContext) { var transform = inputTransform // Triangle from top left corner, to bottom middle, to top right, and then // draw the boundary let topLeft = bounds.origin let bottomRight = CGPoint(x: bounds.size.width, y: bounds.size.height) let path = CGMutablePath() path.move(transform: &transform, x: topLeft.x, y: topLeft.y) path.addLine(transform: &transform, x: bounds.midX, y: bottomRight.y) path.addLine(transform: &transform, x: bottomRight.x, y: topLeft.y) path.addLine(transform: &transform, x: topLeft.x, y: topLeft.y) path.addLine(transform: &transform, x: topLeft.x, y: bottomRight.y) path.addLine(transform: &transform, x: bottomRight.x, y: bottomRight.y) path.addLine(transform: &transform, x: bottomRight.x, y: topLeft.y) context.addPath(path) }
SE-0046: Establish consistent label behavior across all parameters including first labels
最初のラベルを含むすべてのパラメータにわたって一貫したラベルの挙動を確立
最初のパラメーター宣言を第二以降のパラメーターの動作と同じにするという修正の様です。 現在、
func foo(x:Int, y:Int) { ... }
とあった場合、呼び出し側は
foo(_:,y:)
となっていますが、
foo(x:y:)
となるようです。
既存と同じように
foo(_:,y:)
としたい場合は、明示的なラベルをつける様です。
func foo(_ x:Int, y:Int) { ... }
SE-0049: Move @noescape and @autoclosure to be type attributes
@noescape @autoclosure の移動
@noescape @autoclosure を付ける位置が変わるようです。
サンプル
// befor func f(@noescape fn :() -> ()) {} // after func f(fn : @noescape () -> ()) {}
// befor func f2(@autoclosure a : () -> ()) {} // after func f2(a : @autoclosure () -> ()) {}
SE-0053: Remove explicit use of let from Function Parameters
Functionのパラメータからletの明示的な使用を削除
関数のパラメーターに以下のように明示的にletを付けると(無駄なので、)コンパイルエラーになる様です。
func foo(let x: Int) { ... }
SE-0054: Abolish ImplicitlyUnwrappedOptional type
ImplicitlyUnwrappedOptionalタイプを廃止
ImplicitlyUnwrappedOptionalタイプを削除し、IUO属性の宣言に置き換えられる様です。
また、
[Int!]
や
(Int!, Int!)
のような記述が出来なくなります。
サンプル
func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute let x1 = f() // succeeds; x1: Int? = 3 let x2: Int? = f() // succeeds; x2: Int? = .some(3) let x3: Int! = f() // succeeds; x3: Int? = .some(3), has IUO attribute let x4: Int = f() // succeeds; x4: Int = 3 let a1 = [f()] // succeeds; a: [Int?] = [.some(3)] let a2: [Int!] = [f()] // illegal, nested IUO type let a3: [Int] = [f()] // succeeds; a: [Int] = [3] func g() -> Int! { return nil } // f: () -> Int?, has IUO attribute let y1 = g() // succeeds; y1: Int? = .none let y2: Int? = g() // succeeds; y2: Int? = .none let y3: Int! = g() // succeeds; y3: Int? = .none, has IUO attribute let y4: Int = g() // traps let b1 = [g()] // succeeds; b: [Int?] = [.none] let b2: [Int!] = [g()] // illegal, nested IUO type let b3: [Int] = [g()] // traps func p<T>(x: T) { print(x) } p(f()) // prints "Optional(3)"; p is instantiated with T = Int? if let x5 = f() { // executes, with x5: Int = 3 } if let y5 = g() { // does not execute }
SE-0055: Make unsafe pointer nullability explicit using Optional
安全でないポインタNULL値を許可するかどうかをオプションを使って明示的に
ポインタに対してNULL値を許可する場合は
?
を明示的に付けるようにするみたいです。
それにより、一部のAPIにも修正が入る様です。
SE-0057: Importing Objective-C Lightweight Generics
Objective-C 軽量ジェネリックスのインポート
Cocoa と Cocoa Touchには静的な型の安全性と表現力を向上させるためにObjective-Cの軽量ジェネリックを採用している多数のAPIが含まれています。しかし、これらのパラメータはSwiftにインポートした際に型パラメータが失われます。
例えば、現時点では、
NSArray<NSString *> *
は
[String]
ではなく
[AnyObject]
にブリッジされます。
SwiftにおけるこれらのObjective-CのAPIのインポートが改善される様です。
SE-0059: Update API Naming Guidelines and Rewrite Set APIs Accordingly
APIガイドラインにしたがってSet APIの更新
SetAlgebra、Set
メモ:自分はSetAlgebraが何者か知らなかったのですが、数学的な集合演算を提供する型らしいです。
[参考] SetAlgebra|SwiftDoc http://swiftdoc.org/v3.0/protocol/SetAlgebra/
SE-0061: Add Generic Result and Error Handling to autoreleasepool()
Generic Result と autoreleasepool()のエラーハンドリングを追加
現在、標準ライブラリのautoreleasepool機能は、戻り値またはエラー処理をサポートしていません。
一般的な戻り値の型を可能にするために、標準ライブラリautoreleasepool関数のシグネチャを変更するだけでなく、エラーのスローをが可能になる様です。
標準ライブラリは以下のように更新されます。
public func autoreleasepool<Result>(@noescape body: () throws -> Result) rethrows -> Result { let pool = __pushAutoreleasePool() defer { __popAutoreleasePool(pool) } return try body() }
SE-0064: Referencing the Objective-C selector of property getters and setters
Objective-C selectorのgetter/setterの参照
SE-0022では、Objective-Cのメソッドセレクタを参照する#selectorが実装されましたが、プロパティのgetter/setterを参照出来ないため、参照出来るようになる様です。
SE-0065: A New Model For Collections and Indices
コレクションとインデックスの新しいモデル
index操作の変更など、コレクション周りが修正になるようです。
サンプル
// Before: var i = c.index { $0 % 2 == 0 } let j = i.successor() print(c[j]) // After: var i = c.index { $0 % 2 == 0 } let j = c.index(after: i) // ここが変更 print(c[j])
SE-0069: Mutability and Foundation Value Types
Mutability と Foundation の Value Types
新しい Value Types
Value Type | Class Type |
---|---|
AffineTransform | NSAffineTransform |
CharacterSet | NSCharacterSet, NSMutableCharacterSet |
Date | NSDate |
DateComponents | NSDateComponents |
Data | NSData, NSMutableData |
IndexSet | NSIndexSet, NSMutableIndexSet |
IndexPath | NSIndexPath |
Notification | NSNotification |
PersonNameComponents | NSPersonNameComponents |
URL | NSURL |
URLComponents | NSURLComponents |
URLQueryItem | NSURLQueryItem |
UUID | NSUUID |
SE-0070: Make Optional Requirements Objective-C-only
Objective-C専用のOptional要件作成
Objective-Cのプロトコルで「optional」の場合は@objcを明示的に付けるようにする変更の様です。
SE-0071: Allow (most) keywords in member references
(ほとんどの)メンバーの参照のキーワードを許可
メンバーアクセスにおける.後のキーワードの使用を許可した様です。 (ただし、言語的に特別な意味を持っている self, dynamicType, Type, Protocol, は除く)
(SE-0005 の修正でenumのcasesにlower-camel-casingが導入され、Default, Private, Repeatなどのキーワードが競合した?模様です。この修正ではその競合を解決したと思われます。)
SE-0072: Fully eliminate implicit bridging conversions from Swift
Swiftから完全に暗黙のブリッジ変換をなくします
Swift3で言語から暗黙のブリッジ変換が完全に?削除される様です。