Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Swift 2.0 で変わったところ「後編」 #cswift

16,572 views

Published on

2015.09.26 に開催した『カジュアル Swift 勉強会』で、Swift 2.0 での変更点をざっくりと紹介してみました。今回は、前回の続き「後編」として、細々とした仕様変更の話題が中心になってます。

とりわけ目立つ変化は「前編」にまとめてあるので、Swift 2 のおおよその雰囲気を知りたい時はそちらから目を通すのがオススメです。

これらで挙げたほかにもいろいろ小さな変更があるんですけど、とりあえずこの「前編」「後編」で Swift 2.0 の変更点のお話はおしまいです。

Published in: Software
  • Dating for everyone is here: ❤❤❤ http://bit.ly/39mQKz3 ❤❤❤
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Follow the link, new dating source: ❶❶❶ http://bit.ly/39mQKz3 ❶❶❶
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Swift 2.0 で変わったところ「後編」 #cswift

  1. 1. EZ-‐‑‒NET  熊⾕谷友宏   http://ez-‐‑‒net.jp/ 2015.09.26   @  カジュアル  Swift  勉強会  #2 Swift  2.0  で変わったところ Swift  カジュアルプログラミング (後編)
  2. 2. 熊谷友宏 EZ-NET http://ez-net.jp/ @es_kumagai Xcode 5 徹底解説 IP Phone 音でダイヤル 音で再配達ゴッド いつもの電卓 with 割勘ウォッチ MOSA ̶ 勉強会開催 ̶ #yidev 横浜 iPhone 開発者勉強会 カジュアル Swift 勉強会 @ 青葉台
  3. 3. Swift 2.0 ̶ 2015.09.16 ̶
  4. 4. 大幅な仕様変更 ?
  5. 5. そこで
  6. 6. Swift 2.0 で変わったところを ざっくり紹介してみる
  7. 7. 前編
  8. 8. http://www.slideshare.net/ tomohirokumagai54/swift-20-cswift SlideShare で公開中 前編
  9. 9. 後編
  10. 10. NSObject 1/5
  11. 11. performSelector
  12. 12. ▶ Selector を使って機能を実行 ▶ Objective-C と同等の使い心地 ▶ プリミティブ型の引数や戻り値は非対応 performSelector func performSelector(sel: Selector)
 -> Unmanaged<AnyObject>! func performSelector(sel: Selector, withObject obj: AnyObject!) -> Unmanaged<AnyObject>! func performSelector(sel: Selector, withObject obj1: AnyObject!, withObject obj2: AnyObject!) -> Unmanaged<AnyObject>!
  13. 13. ▶ Objective-C と同じ指定方法 ▶ 文字列リテラルから生成できる ▶ nil リテラルから生成できる Selector struct Selector : StringLiteralConvertible, NilLiteralConvertible
  14. 14. 文字列を返すメソッドを実行 performSelector let obj = NSString(string: "TEST.TXT") // ObjC でいう NSString (NSObject) は取得可能 let extname:String = obj.performSelector("pathExtension") .takeRetainedValue()
  15. 15. 文字列を渡してメソッドを実行 performSelector let obj = NSString(string: "TEST.TXT") // ObjC でいう NSString (NSObject) は取得可能 let extname:String = obj.performSelector( "componentsSeparatedByString:", withObject: "T") .takeRetainedValue()
  16. 16. プリミティブな値は取得できない? performSelector let obj = NSString(string: "TEST.TXT") // 戻り値が NSInteger (long) 相当だと nil になる let length:Int = obj.performSelector("length") .takeRetainedValue() Execution was interrupted, reason: EXC_BAD_ACCESS.
  17. 17. プリミティブな引数は受け取れない? performSelector let obj = NSString(string: "TEST.TXT") // NSUInteger (unsigned long) 相当を渡せない let length:Int = obj.performSelector("characterAtIndex:", withObject: UInt(1)) .takeRetainedValue() Execution was interrupted, reason: signal SIGABRT. characterAtIndex: Range or index out of bounds.
  18. 18. プリミティブな引数は受け取れない? performSelector let obj = NSString(string: "TEST.TXT") // NSNumber に変換しても渡せない let length:Int = obj.performSelector("characterAtIndex:", withObject: NSNumber(unsignedInteger:1)) .takeRetainedValue() Execution was interrupted, reason: signal SIGABRT. characterAtIndex: Range or index out of bounds.
  19. 19. Swift performSelector 引数
  20. 20. Swift クラスの機能は呼び出せる? performSelector class MyClass : NSObject { func toStringWithStr(v:String) -> String func toStringWithInt(v:Int) -> String }
  21. 21. 文字列を受け取るメソッドは実行可能 performSelector let obj = MyClass() // String を渡すメソッドは正常動作 let result:String = obj.performSelector("toStringWithStr:", withObject: "A") .takeRetainedValue()
  22. 22. 数値を受け取るメソッドは予期しない動作 performSelector let obj = MyClass() // Int だと渡した値とは違う値が渡される様子 let result:String = obj.performSelector("toStringWithInt:", withObject: 1) .takeRetainedValue() エラーにならないが 違う値 が渡される
  23. 23. 数値を受け取るメソッドは予期しない動作 performSelector let obj = MyClass() // NSNumber にラップしても違う値が渡される様子 let result:String = obj.performSelector("toStringWithInt:", withObject: NSNumber(integer:1)) .takeRetainedValue() エラーにならないが 違う値 が渡される
  24. 24. NSNumber を受け取るメソッドは OK performSelector let obj = MyClass() // 呼び出し先が NSNumber を受け取るなら正常動作 let result:String = obj.performSelector("toStringWithNSNumber:", withObject: NSNumber(integer:1)) .takeRetainedValue()
  25. 25. NSNumber を受け取るメソッドは OK performSelector let obj = MyClass() // 呼び出し先の NSNumber にリテラル値も渡せる let result:String = obj.performSelector("toStringWithNSNumber:", withObject: 1) .takeRetainedValue()
  26. 26. Swift performSelector 戻り値
  27. 27. Swift クラスの機能は呼び出せる? performSelector class MyClass : NSObject { func asString() -> String func asInt() -> Int }
  28. 28. 文字列を返すメソッドは実行可能 performSelector let obj = MyClass() // String 型の戻り値は取得可能 let value:String = obj.performSelector("asString") .takeRetainedValue()
  29. 29. 整数を返すメソッドは実行できない performSelector let obj = MyClass() // Int 型の戻り値は取得できない let value:Int = obj.performSelector("asInteger") .takeRetainedValue() Execution was interrupted, reason: EXC_BAD_ACCESS.
  30. 30. Swift performSelector ObjC 互換 & Swift ネイティブ
  31. 31. Swift で定義したクラスは受け取れる? performSelector class MyClass : NSObject { func asObjC() -> ObjCClass func asNative() -> NativeClass } class ObjCClass : NSObject { } class NativeClass { }
  32. 32. ObjC 互換クラスを返すメソッドは実行可能 performSelector let obj = MyClass() // 自作 ObjC 互換クラスは取得できるが AnyObject let result:AnyObject = obj.performSelector("asObjC") .takeRetainedValue() // キャストして正常に使用できる let value:Int = (result as! ObjCClass).value
  33. 33. Swift クラスを返すメソッドは実行できない performSelector let obj = MyClass() // Swift ネイティブ型の戻り値は取得できない let value:Int = obj.performSelector("asNative") .takeRetainedValue() Execution was interrupted, reason: signal SIGABRT. asNative: unrecognized selector sent to instance.
  34. 34. performSelector は 独特の癖に悩まされそう
  35. 35. performSelector スレッド
  36. 36. performSelector extension NSObject { func performSelectorOnMainThread( aSelector: Selector, withObject arg: AnyObject?, waitUntilDone wait: Bool) func performSelector( aSelector: Selector, onThread thr: NSThread, withObject arg: AnyObject?, waitUntilDone wait: Bool) func performSelectorInBackground( aSelector: Selector, withObject arg: AnyObject?) }
  37. 37. @objc
  38. 38. ▶ ObjC で使いたい Swift クラスに付与 ▶ NSObject を継承していなくても良い @objc これまで ▶ ObjC 互換な Swift クラスに付与 ▶ NSObject を継承している必要がある これから
  39. 39. // NSObject を継承しないクラスには付けられない @objc class SwiftClass { } // NSObject を継承するクラスには付けてもいい @objc class SwiftClass : NSObject { } Only classes that inherit from NSObject can be declared @objc コンパイル時の扱われ方 @objc class
  40. 40. // 原則 ObjC 互換クラスにだけ設定できる @objc protocol MyProtocol { } // 全ての型に設定できる protocol MyProtocol { } コンパイル時の扱われ方 @objc protocol 実装を要求しない場合は
 どんな型にも設定できる
  41. 41. // 明記によりネイティブクラスにも設定可能 @objc protocol MyProtocol { func method() } // @objc プロトコルが要求する機能に @objc を明記 class SwiftClass : MyProtocol { @objc func method() } コンパイル時の扱われ方 @objc protocol
  42. 42. @nonobjc
  43. 43. ▶ Objective-C にブリッジしない機能を明示 ▶ プロパティやメソッドに記載する @nonobjc class SwiftClass : NSObject { var value:Int @nonobjc var native:Int @objc var compatible:Int }
  44. 44. ブリッジしない機能を選べる @nonobjc SwiftClass* instance = [[SwiftClass alloc] init]; // @nonobjc を付与した機能は候補に挙がらない instance.value
  45. 45. 制御構文 2/5
  46. 46. #available
  47. 47. ▶ プラットフォーム毎に条件を指定 ▶ 必ず『全てのプラットフォーム』を含む ▶ 判定は実行時に行われる #available // 全てのプラットフォームが対象 #available(*) // OSX 10.10 以上と、その他のプラットフォームが対象 #available(OSX 10.10, *) // OSX 10.10 以上と、iOS 8.4 以上と、
 // その他のプラットフォームが対象 #available(OSX 10.10, iOS 8.4, *)
  48. 48. if 文で使用する #available if #available(OSX 10.10, *) { // OSX 10.10 以上か、その他のプラットフォーム } else { // OSX 10.10 未満 }
  49. 49. else if 文も使用できる #available if #available(OSX 10.9, *) { // OSX 10.9 以上か、その他のプラットフォーム } else if #available(OSX 10.10, *) { // OSX 10.9 以上か、その他のプラットフォーム } else { // OSX 10.9 未満 }
  50. 50. 論理演算はできない #available if #available(iOS 9.0, *) && value == 1 { } Expected { after if condition
  51. 51. 条件を必ず満たす場合は警告扱い #available // Deployment Target が iOS 9.0 のとき if #available(iOS 9.0, *) { } Unnecessary check for iOS ; minimum deployment target ensures guard will always be true ▶ ライブラリ内で使用されていると
 使うときに警告に悩まされるかもしれない
  52. 52. guard 文で使用する #available guard #available(OSX 10.10, *) else { // 条件を満たさない場合は早期 Exit 必須 } // 以降は OSX 10.10 以上か、 // その他のプラットフォームであることを保証
  53. 53. 指定できるプラットフォーム #available ▶ * ▶ iOS ▶ iOSApplicationExtension ▶ OSX ▶ OSXApplicationExtension ▶ watchOS ▶ watchOSApplicationExtension
  54. 54. Error Handling 3/5 Beta  5  以降降の   変更更点
  55. 55. Error Type
  56. 56. 列挙型以外もエラー型にできる Error Type // 構造体でもエラーを定義可能 struct FileOperationError : ErrorType { } ▶ 型を ErrorType に準拠 ▶ 既定のエラードメインは型名 ▶ 既定のエラーコードは 1
  57. 57. ドメインとエラーコードを指定可能? Error Type // 構造体でもエラーを定義可能 struct FileOperationError : ErrorType { var _code:Int var _domain:String } ▶ _code でエラーコードを指定 ▶ _domain でエラードメインを指定可能 ▶ インスタンス毎に違う値を持てる ▶ ただしプロトコルには明記されていない
  58. 58. エラーの送出方法 Error Type // インスタンスを生成してエラー送信 throw FileOperationError()
  59. 59. rethrows
  60. 60. 標準メソッドが rethrows に対応 rethrows func map<T>( transform: (Generator.Element) throws -> T ) rethrows -> [T] func reduce<T>( initial: T, combine: (T, Generator.Element) throws -> T ) rethrows -> T func filter( element: (Generator.Element) throws -> Bool ) rethrows -> [Generator.Element]
  61. 61. 演算子も かに rethrows 対応 rethrows func &&<T : BooleanType, U : BooleanType>( lhs: T, @autoclosure rhs: () throws -> U ) rethrows -> Bool func ||<T : BooleanType, U : BooleanType>( lhs: T, @autoclosure rhs: () throws -> U ) rethrows -> Bool func ??<T>( optional: T?, @autoclosure defaultValue: () throws -> T ) rethrows -> T
  62. 62. try?
  63. 63. エラー機構をオプショナルに変換 try? var handle:Handle? = try? File.open(path) ▶ 戻り値をオプショナルで包む ▶ エラーが発生すると nil が返る ▶ エラー情報は 破棄 される
  64. 64. 動作のイメージ try? // 戻り値をオプショナルで扱う var handle:Handle? do { // メソッドを呼び出して戻り値を取得 handle = try File.open(path) } catch { // エラーが発生した場合は nil を設定 handle = nil }
  65. 65. guard で使う try? guard let handle = try? File.open(path) else { // エラーが発生したときに早期 Exit return } // これ以降はファイルを開けた前提で記載できる return readFrom(handle)
  66. 66. rethrows と使う try? // クロージャー内でエラー発生時に全体を nil に変換 let sum:Int? = try? objects.reduce(0) { try $0 + $1.toInt() } // メソッドチェーンの流れを打ち切ってみたり let sum:Int? = try? objects .map { try $0.toInt() } .reduce(0, combine: +)
  67. 67. 関数 4/5
  68. 68. 大域関数
  69. 69. // 主要な大域関数が軒並み削除 count(array) map(array) { $0 } // プロトコル拡張に移行された extension CollectionType { var count: Index.Distance { get } func map<T>(f:(Generator.Element)->T)->[T] } 大域関数の多くがプロトコル拡張に移行 大域関数
  70. 70. // Swift 1 までの呼び出し方 count(array) map(array) { $0 } // Swift 2 からの呼び出し方 array.count array.map { $0 } 機能の呼び出し方の違い 大域関数
  71. 71. // toString 関数が削除された let string = toString(value) // これからは String の変換イニシャライザを使う let string = String(value) toString 関数は変換イニシャライザへ 大域関数 ▶ 変換は型が責任を持つ意志の顕われ?
  72. 72. 引数のラベル付けルール
  73. 73. ▶ Swift 1.x では 3 つのルール ✴ 関数 ✴ メソッド ✴ イニシャライザ ▶ Swift 2.0 では 2 つのルール ✴ 関数 & メソッド ✴ イニシャライザ 引数のラベル付けルール
  74. 74. 関数はメソッドと同じルールに変更 引数のラベル付けルール // このような 関数 定義のとき func getPrice(price:Int, tax:Double) -> Int // Swift 1 では両方にラベル名が不要 getPrice(100, 0.05) // Swift 2 では第二引数以降でラベル名が必要 getPrice(100, tax: 0.05)
  75. 75. ▶ 外部引数名の明記が必須 ▶ 同じ名前でも # で表記できない func getPrice(#price:Int) -> Int func getPrice(price price:Int) -> Int 外部ラベル名の省略表記が廃止 引数のラベル付けルール '#' has been removed from Swift; double up 'price price' to make the argument label the same as the parameter name
  76. 76. まとめ 引数のラベル付けルール ▶ 左側に _ を付けてラベル名を削除可能 ▶ 左側にラベル名を明記できる 引数ラベル 第1引数 第2引数 … 関数 メソッド なし(明示で付与) あり(_ で削除) イニシャライザ あり(_ で削除)_ あり(_ で削除)
  77. 77. ディフォルト引数の補完
  78. 78. ▶ 全ての引数を省略した時の補完候補 ▶ 全ての引数を指定するための補完候補 func action(a:Int, b:Int = 1, c:Int = 2) { } // 複数の補完候補が表示される value.action 補完候補が複数出るようになった ディフォルト引数の補完
  79. 79. forEach
  80. 80. forEach extension SequenceType { func forEach( @noescape body:(Generator.Element) throws -> () ) rethrows } ▶ 各要素を順番に処理 ▶ 処理にはクロージャーを使う ▶ for … in と似た動作(関数+クロージャー版)
  81. 81. メソッドチェインと併用する forEach items.filter(isValid).forEach { $0.activate() } ▶ break や continue は使えない ▶ return はクロージャーを抜ける ▶ チェーン以外では for … in を推奨らしい クロージャーで   処理理を実⾏行行
  82. 82. 可変長引数
  83. 83. 定義と実行方法 可変長引数 // 可変値引数を引数リストの途中に含む関数の定義 func writeTo( path:String, items:String..., permit:Int ) { } // 定義した関数の実行 writeTo(path, items:"A","B","C", permit:0o775) 可変⻑⾧長引数の終わりは
 ラベルで判断
  84. 84. 既定値引数と併せて使う 可変長引数 // 可変値引数の後に既定値を持つ引数を定義 func writeTo( path:String, items:String..., permit:Int = 0o755) { } // 定義した関数の実行 writeTo(path, items:"A","B","C") 可変⻑⾧長引数の後の   引数を省省略略可能
  85. 85. 末尾クロージャーと併せて使う 可変長引数 // 引数リストの最後でクロージャーを定義 func writeTo( path:String, items:String..., preAction:(String) -> String) { } // 定義した関数の実行 writeTo(path, items:"A","B","C") { return parseItem($0) } 末尾クロージャーの   書式で引数を渡せる
  86. 86. 複数の可変長引数は指定できない 可変長引数 // 複数の可変長引数があるとビルドエラー func writeTo( path:String, items:String..., permits:Int...) { } Only a single variadic parameter '...' is permitted
  87. 87. イニシャライザ
  88. 88. 失敗可能イニシャライザに委譲可能 イニシャライザ struct MyType { // 失敗可能イニシャライザがあったとき init?(string: String) { } // ある失敗可能イニシャライザで init?(resource:String) { // 別の失敗可能イニシャライザへ委譲可能 self.init(string: readFrom(resource)) } } 失敗時は  nil
  89. 89. 通常のものから失敗可能なものに委譲 イニシャライザ struct MyType { // 失敗可能イニシャライザがあったとき init?(string: String) { } // ある通常のイニシャライザで init() { // 別の失敗可能イニシャライザへ委譲可能 self.init(string: "DEFAULT")! } } 失敗時は打ち切切り
  90. 90. let strings = ["10", "3.5", "8", "20.8"] // イニシャライザを普通の関数として渡せる let values = strings.flatMap(Double.init) ▶ イニシャライザの引数を取る ▶ 戻り値に自身の型を返す ▶ 失敗可能な場合はオプショナルを返す 静的メソッドとして使える イニシャライザ
  91. 91. struct Selector : StringLiteralConvertible { init(_ str: String) init(stringLiteral value: String) } // 実行したい方を選択できない let sel = optionalString.map(Selector.init) ▶ 引数ラベル名で選択できない ▶ 関数型の引数に適切なものを渡しづらい 静的メソッドは衝突しやすい イニシャライザ Ambiguous reference to member Selector.init
  92. 92. インスタンスメソッド Swift 2 以前からかもしれない
  93. 93. let string = "New in Swift 2.0" // インスタンスからメソッドを呼び出す操作を string.containsString("Swift") // 型から静的メソッドを呼ぶ操作に書き換えられる String.containsString(string)("Swift") ▶ インスタンスを取り
 本来のインスタンスメソッドを返す関数 ▶ プロパティーは静的メソッドにならない 静的メソッドとして使える インスタンスメソッド
  94. 94. // クロージャーを使ったメソッドチェイン let sorted = letters .filter { string.containsString($0) } .sort { $0 > $1 } // 関数だけで作ったメソッドチェイン let sorted = letters .filter(String.containsString(string)) .sort(>) 静的メソッドとメソッドチェインの例 インスタンスメソッド
  95. 95. 列挙型 5/5
  96. 96. indirect case
  97. 97. // 再帰的な列挙型を定義 enum Cascade { indirect case Device(String, next:Cascade) case Terminate } 再帰的な列挙型を作る indirect case // 再帰的に列挙子を組み立てられる let devices:Cascade = .Device("HDD", next: .Device("DVD", next: .Device("MO", next: .Terminate))) indirect  case  にすることで
 列列挙⼦子の値で⾃自⾝身の型を扱える
  98. 98. 深さを計算する機能の実装例 indirect case extension Cascade { var depth:Int { switch self { case .Device(_, next: let next): return 1 + next.depth case .Terminate: return 0 } } } // 深さを計算する devices.depth
  99. 99. Raw 値
  100. 100. // 再帰的な列挙型を定義 enum Language : String { case Swift case ObjectiveC = "Objective-C" case C case Ruby } // 未設定のものは列挙子名と同じ文字列が得られる Language.Swift.rawValue 列挙子と同じ文字列なら省略可能に Raw 値 列列挙⼦子と違う場合だけ
 明記すれば  OK
  101. 101. おしまい 他にも細かい変更はあるけれど 😏
  102. 102. Swift 2.0 で変わったところ ▶ NSObject ▶ 制御構文 ▶ Error Handling ▶ 関数 ▶ 列挙型 前編後編 ▶ 制御構文 ▶ Error Handling ▶ 詳細な条件指定 ▶ Extension

×