「Swift 2の新機胜」䟋付き。 パヌト2

最初の郚分では、Swift 2の新機胜の䞀郚のみを怜蚎したした。


2番目の郚分では、残りに぀いお怜蚎したす。


Swift 2の新機胜に぀いお、 Githubにコヌドが蚘茉されおいるサンプルずずもに玹介したす。

プロトコル拡匵


Swift 2でプロトコル拡匵が可胜になり、プロトコルを実装するクラス、構造、および列挙に新しい関数実装枈みを远加できるようになりたした。

Swift 2より前は、Objective-CずSwift 1.xの䞡方で、プロトコルにはメ゜ッド宣蚀のみが含たれおいたした。 Swift 2のプロトコル拡匵により、プロトコルにメ゜ッドの実装を宣蚀ずずもに含めるこずができたす。 私たちは、Objective-Cのこの機胜を䜕幎も埅っおいたので、新しい蚀語で具䜓化されるのを芋るのは玠晎らしいこずです。

特定のプロトコルむンタヌフェヌスを確認するすべおのタむプにいく぀かの機胜を远加する必芁があるこずがよくありたす。 たずえば、すべおのコレクションは、芁玠の倉換に基づいお新しいコレクションを䜜成するずいう抂念をサポヌトしたす。 叀いスタむルのプロトコルでは、2぀の方法でこの可胜性を実装できたす。1メ゜ッドをプロトコルに配眮し、このプロトコルを確認する各タむプがメ゜ッドを実装するこずを芁求するか、2プロトコルを確認するタむプの倀で機胜するグロヌバル関数を䜜成したす。

ほずんどの堎合、CocoaObjective-Cは最初の゜リュヌションを奜みたす。

Swift 1.xは2番目の゜リュヌションを䜿甚したした。 CollectionTypeで操䜜されるmapなどのグロヌバル関数。 これにより、実装䞭のコヌドの優れた分離が提䟛されたしたが、ひどい構文ず特定のタむプの実装をオヌバヌラむドするこずができたせんでした。

let x = filter(map(numbers) { $0 * 3 }) { $0 >= 0 } //-- Swift 1 


プロトコル拡匵により、他の2぀よりも倧幅に優れた3番目の機䌚が生たれたした。 mapは、 CollectionTypeプロトコルの拡匵で実装できたす。 CollectionTypeプロトコルをサポヌトするすべおのタむプは、 マップの実装を完党に無料で自動的に受け取りたす 。

 let x = numbers.map { $0 * 3 }.filter { $0 >= 0 } //-- Swift 2 

䟋ずしお、Swift 2でCollectionTypeプロトコルの拡匵ずしお新しいmyMapメ゜ッドの実装を怜蚎したす。



その結果、 配列<T>配列にすぐにmyMapを䜿甚できたす


蟞曞甚蟞曞<キヌ倀>


セットセット<T>


String.characters文字列甚


スラむスArraySlice <T>の堎合


StrideThrough <T> strikesの堎合、盎接ではなく、シヌケンス SequenceTypeプロトコルをコレクション CollectionTypeプロトコルに倉換するmapを介しお


プロトコル拡匵は、Appleがプロトコル指向プログラミングPOPであるず䞻匵する新しい゜フトりェア蚭蚈アプロヌチの䞭心にあり、埓来のオブゞェクト指向プログラミングOOPおよび機胜プログラミングFP芁玠ずずもにSwiftに存圚したす。 「壊れやすい基本クラス」、継承の剛性ず脆匱性、 「ダむダモンドの問題」 、オブゞェクトぞの参照の暗黙的な分離、「キャスト」ダりンの頻繁な䜿甚の必芁性ダりンキャストなどのOOP問題を克服する必芁がありたす。 オヌバヌラむドされたメ゜ッド内。 たた、倚くの開発者が蚀葉でポリモヌフィズムを説明するのはどれほど難しいかですが、䟋で瀺す方が簡単です。プロトコル指向プログラミングの機胜を䟋で瀺したす。

䟋1. Fisher-Jensシャッフルアルゎリズム


これらの違いを詳しく芋るために、Swift 1.2OOPおよびSwift 2POPのシャッフル関数を䜿甚しおコレクション芁玠を「混合」 するFisher-Jens Shuffle アルゎリズムの実装を䟋ずしお芋おみたしょう。 このアルゎリズムは、カヌドゲヌムでカヌドを扱うずきによく䜿甚されたす。

Swift 1.2では、方法2に埓っおコレクションを操䜜するグロヌバルシャッフル関数を远加したす。぀たり、 ゞェネリックを持぀グロヌバル関数を䜿甚する堎合です。



この機胜をさらに詳しく芋おみたしょう。 var listCコレクション自䜓は、このグロヌバル関数の入力ぞの匕数ずしお䜿甚され、同じタむプCの新しいコレクションが元のリストコレクションの「混合」倀ずずもに返されたす。 このグロヌバル関数は、 MutableCollectionTypeプロトコルをサポヌトし、敎数むンデックスを持぀すべおのタむプに䜿甚できたす。 そのようなコレクションが2぀ありたす Array <T> arrayおよびArraySlice <T> slice



しかし、このグロヌバル機胜の魅力は䜕ですか
 shuffle(strings1) shuffle(numbers1) 


この関数では、括匧内にコレクション自䜓を指定する必芁がある「ドット」付きの衚蚘を䜿甚できたせん。 倚くのネストされた括匧に぀ながる倉換のチェヌン党䜓がある堎合、これが非垞に䞍䟿であり、これらすべおが型メ゜ッドず亀互になっおいる堎合、䞀般的には灜害です。 䞊蚘で同様の構文をすでに芋たした。

 let x = filter(map(numbers) { $0 * 3 }) { $0 >= 0 } //-- Swift 1 


Swift 1.2で「ポむント」衚蚘を䜿甚する堎合は、 配列クラスなどの個々のタむプの拡匵にシャッフル関数を远加したすこれはメ゜ッド1です。 そしお、その堎で倉化する倉曎するshuffleInPlaceメ゜ッドず、元の配列の「混合」芁玠を持぀新しい配列を返す倉曎しないshuffleメ゜ッドの䞡方を远加できたす。



最埌の2぀のメ゜ッドは、 配列配列の拡匵であり、配列でのみ䜿甚できたす。


SetもArraySliceも、その他のCollectionTypeもこれらを䜿甚できたせん。

Swift 2では、 shuffleおよびshuffleInPlaceメ゜ッドを远加しお、 CollectionTypeおよびMutableCollectionTypeプロトコルを拡匵したす メ゜ッド3。


プロトコルの拡匵により、 shuffleおよびshuffleInPlaceメ゜ッドをSet 、 Array 、 ArraySliceおよびその他のCollectionTypeに、远加の劎力なしで、必芁な「ポむント」衚蚘で適甚できるようになりたした。



Swift 2でプロトコルを拡匵する堎合、型の制限を蚭定できたす。 コヌドからわかるように、最初にむンデックスずしお敎数を䜿甚する可倉コレクションMutableCollectionTypeに察しおのみプロトコル拡匵を実行し、次にそれをCollectionTypeに拡匵したす 。

最埌に、コレクションの芁玠を「混合」するアルゎリズムに関しお、少し発蚀する必芁がありたす。 Swift 2には、既にGameplayKitで Fisher-Jensシャッフルアルゎリズムの効果的で正しい実装がありたす名前にかかわらず、ゲヌムだけでなく適切です。 確かに、このメ゜ッドは配列でのみ機胜したす。


䟋2.さようならパむプパむプラむン挔算子|>プロトコル拡匵の出珟


Swiftの到来ず、関数型プログラミング挔算子を含むカスタム挔算子の䜜成の可胜性により、関数型プログラミング手法を䜿甚しおいく぀かの問題を解決する詊みが行われ、非垞に成功しおいたす。 特に、プラスチックカヌドのチェックディゞットを蚈算するためのLunaアルゎリズムでは、パむプパむプラむン挔算子を䜿甚しお、関数ずメ゜ッド間での迷惑なスロヌを回避するこずが提案されたした。 しかし、Swift 2が登堎し、プロトコル拡匵技術によりこのタスクがさらに簡単になりたした。

開発者が説明した元のアルゎリズム


アルゎリズムは䞀連のステップで構成されたす。各ステップは、プロトコルたたはタむプの拡匵機胜を䜿甚するか、既知の方法を䜿甚しお説明したす。

たず、Swift 2ではStringはもはやシヌケンスではなく、 String.charactersは文字のシヌケンスであり、文字を敎数に倉換する必芁があるこずを思い出しおください。 Int型の拡匵でこの倉換を構築したす。 ぀たり、 String.toIntegerの代わりに、 Int.initStringを取埗したす。



クレゞットカヌド番号にスペヌスが含たれおいる可胜性があるため、この倉換はOptionalを返し、受信した敎数に察しお匕き続き算術挔算を実行する必芁があるため、Swift 2で登堎したflatMapメ゜ッドを䜿甚しお、カヌド番号のすべおのスペヌスを削陀したす



私たちのアルゎリズムによれば、数字を右から巊に考慮し、それらは巊から右に進むので、 reverseメ゜ッドずtrivial mapメ゜ッドを䜿甚しお数字のシヌケンスを反察方向に䞊べたす



ただし、単玔なマップではなく、シヌケンスの各N番目のメンバヌに察しおのみ倉換を実行するマップが必芁です。 再床、拡匵を実行したすが、タむプではなくSequenceTypeを実行したす



次の結果が埗られたす



次に、敎数を含むシヌケンスの合蚈を蚈算できるメ゜ッドが必芁です。



および別の数を法ずする数を蚈算する方法



その結果、 luhnchecksumメ゜ッドを取埗したす。このメ゜ッドは、 String型に远加し、1行でチェックサムを蚈算したす



結果を取埗するのは非垞に簡単です



プロトコル拡匵のいく぀かの機胜


プロトコル拡匵は、オプションのプロトコル方匏に関する質問に察するAppleの䞀皮の答えかもしれないず思いたす。 玔粋なSwiftプロトコルには、オプションのメ゜ッドを含めるこずはできたせん。 しかし、Objective-Cプロトコルのオプションのメ゜ッドには、たずえばデリゲヌトのようなものに慣れおいたす。

 @protocol MyClassDelegate @optional - (BOOL)shouldDoThingOne; - (BOOL)shouldDoThingTwo @end 


Pure Swiftには同等のものはありたせん


これたで、このプロトコルを怜蚌した人は党員、これらの方法をすべお実装しおいたはずです。 これは、オプションですべおのデリゲヌトメ゜ッドを蚭定し、デフォルトのメ゜ッド実装を優先する可胜性があるずいうCocoaの委任の考え方ず矛盟したす。 Swift 2でのプロトコル拡匵の出珟により、合理的なデフォルトの動䜜をプロトコル自䜓で実珟できたす。



最終的に、これはObjective-Cの@optionalず同じ機胜を提䟛したすが、実行時の必須チェックはありたせん。

API可甚性チェック


iOS開発者を萜ち蟌たせる専門的な問題の1぀は、新しいAPIを䜿甚する際に非垞に泚意する必芁があるこずです。 たずえば、iOS 8でUIStackViewを䜿甚しようずするず、アプリケヌションがクラッシュしたす。 Objective-Cの昔、開発者は次のようなコヌドを蚘述しおいたした。

 NSClassFromString(@"UIAlertController") != nil 


これは「 UIAlertControllerlクラスが存圚する堎合」を意味し、iOS 8以降で実行されるかどうかを確認する方法です。 しかし、Xcodeはこのコヌドの真の目的を知らなかったずいう事実により、その実行の正確性を保蚌したせんでした。 次のようなコヌドを明瀺的に蚘述できるため、Swift 2ではすべおが倉曎されたした。

 if #available(iOS 9, *) { let stackView = UIStackView() //  ... } 


マゞックは#available文で発生したす。iOS9以降で実行しおいるかどうかを自動的にチェックし、実行しおいる堎合は、 UIStackViewのコヌドが起動したす。 「iOS 9」の埌に蚘号「*」が存圚するずいうこずは、この提案がAppleが導入する将来のプラットフォヌムに察しお実行されるこずを意味したす。

#available文はたた 、 elseブロックにコヌドを曞く機䌚を䞎えるずいう点でも泚目に倀したす。これは、デバむスがiOSバヌゞョン8以前である堎合にこのブロックが実行され、新しいAPIを䜿甚するず譊告できるようになるためです。 。 たずえば、次のようなものを曞いた堎合

 if #available(iOS 9, *) { // do cool iOS 9 stuff } else { let stackView = UIStackView() } 

...その埌、゚ラヌが発生したす



Xcodeは、利甚できないUIStackViewを䜿甚しようずしおいるこずを認識し 、これが発生しないようにしたす。 したがっお、「このクラスが利甚可胜」からXcodeに真の意図を䌝えるために切り替えるず、セキュリティに察する倚倧なサポヌトが埗られたした。

互換性


Swift、぀たり、メ゜ッド、プロパティなどをObjective-Cなどに公開するかどうか、どのように公開するかをコンパむラに䌝える䞀連の事前定矩されたルヌルを蚘述するずき さらに、このプロセスを制埡できる少数の属性を自由に䜿甚できたす。 これらの属性は次のずおりです。





Swift 2は、Objective-Cでのプロパティたたはメ゜ッドの䜿甚を明瀺的に防止する@nonobjcなどの新しい属性を導入したした。 この属性は、たずえば次の堎合に非垞に圹立ちたす。 Cocoa UIViewControllerクラスを継承するViewControllerクラスのCalculatorアプリケヌション以䞋を参照で、 performOperationずいう同じ名前で異なる匕数を持぀3぀のメ゜ッドを定矩したした。 これは正垞であり、Swiftはこれらのメ゜ッドを区別するこずができ、異なる皮類の匕数に基づいおいたす。 しかし、Objective-Cはそのようには機胜したせん。 Objective-Cでは、メ゜ッドは名前ではなくタむプによっお異なりたす。 これらのメ゜ッドがObjective-Cで䜿甚するために公開されおいる堎合、この圢匏のObjecrive-Cでは䜿甚できないずいう゚ラヌが衚瀺されたす。 問題は、蚈算機むンタヌフェむス甚に䜜成したViewControllerクラスがUIViewCiontrollerクラスのCocoaクラスを継承し、コンパむラがすべおのプロパティずメ゜ッドを@objc属性で暗黙的に自動的にマヌクするこずです。 Objective-Cでメ゜ッドを䜿甚する぀もりがない堎合は、それらに@noobjc属性を指定する必芁があり、゚ラヌが消えたす。


.........................

Swift 2が互換性を改善しようずしおいるもう1぀の分野は、C関数ポむンタヌずの互換性です。 この改善の目的は、厄介なSwiftの制限を修正するこずです。これにより、コヌルバック関数を集䞭的に䜿甚するCore Audioなどの重芁なCフレヌムワヌクを完党に䜿甚できなくなりたす。 Swift 1.xでは、C関数ぞのポむンタヌをSwift関数に盎接眮き換えるこずはできたせんでした。 CたたはObjective-Cでコヌルバック関数をカプセル化する小さな「ラッパヌ」を䜜成する必芁がありたした。 Swift 2では、Swift 2でこれを完党に自然な方法で行うこずが可胜になりたした。 C関数ぞのポむンタヌはクロヌゞャヌずしおSwiftにむンポヌトされたす。 Swift 2の任意のクロヌゞャヌたたは関数を、適切なパラメヌタヌを䜿甚しお、C関数ぞのポむンタヌを予期するコヌドに枡すこずができたす。1぀の重芁な制限がありたす。クロヌゞャヌずは察照的に、C関数ぞのポむンタヌには、「キャプチャされた」状態の抂念がありたせん単なるポむンタヌです。 その結果、C関数ぞのポむンタヌずの互換性のために、コンパむラは倖郚コンテキストを「キャプチャ」しないSwift 2クロヌゞャヌのみを蚱可したす。 Swift 2は新しい@芏玄©衚蚘を䜿甚しお、呌び出しでこの芏玄を瀺したす。



たずえば、暙準のC qsort゜ヌト関数の堎合、次のようになりたす。


非垞に良い䟋がSwiftのC Callbacksにありたす。これは、 CGPathApply関数を呌び出しお、コヌルバック関数にポむンタヌを枡すこずでCGPathたたはUIBezierPath芁玠にアクセスする方法を瀺しおいたす。 次に 、 CGPathApplyは各パス芁玠に察しおこのコヌルバックを呌び出したす。





次に、 パス党䜓を調べお、その芁玠の説明を出力したす。



たたは、このパスにある closepathコマンドの数を蚈算できたす 。



結論ずしお、Swift 2は、C関数ずクロヌゞャヌぞのポむンタヌの互換性ブリッゞを自動的に保蚌するず蚀うこずができたす。 これにより、コヌルバックずしお関数ポむンタヌを䜿甚する倚数のC APIで䜜業するこずが可胜になりたす非垞に䟿利です。 C関数の呌び出しに関する芏則では、これらのクロヌゞャヌが倖郚状態を「キャプチャ」するこずは蚱可されないため、倚くのC APIがコヌルバッククロヌゞャヌがアクセスする必芁がある倖郚ポむンタヌを倖郚ポむンタヌに枡す必芁がありたす。

新しいObjective-Cの機胜


Appleは、よりスムヌズなSwift互換性のためにそれらを䜿甚するこずを目的ずしお、Xcode 7のObjective-Cに3぀の新機胜を導入したした。



ヌル可胜性


この機胜はすでにXcode 6.3で導入されたしたが、Objective-Cを䜿甚するず、メ゜ッドやプロパティの動䜜を正確に特性化しお、 nilであるかどうかを確認できるようになりたした。 これは、 オプションたたは非オプションのタむプに察するSwiftの芁件に盎接察応し、Objective-Cむンタヌフェむスをより衚珟力豊かにしたす。 nullabilityには3぀の修食子がありたす。



䞊蚘の修食子は、次の䟋のように、Objective-Cクラスに泚釈を付けるために䜿甚できたす。



この䟋では、角かっこNS_ASSUME_NONNULL_BEGINおよびNS_ASSUME_NONNULL_ENDでマヌクされた領域党䜓が遞択されおいるため、 null以倖はデフォルト倀になりたす。 これにより、開発者はデフォルト倀ず䞀臎しない芁玠のみに泚釈を付けるこずができたす。

軜量ゞェネリック


Objective-Cの軜量ゞェネリックは、特にApple゚ンゞニアにずっおは、過去10幎間でObjective-Cで間違いなく最も望たしいものです。 NSArrayやNSDictionaryなどのコレクションで䜿甚するために必芁です。Objective -Cのコレクションの欠点の1぀は、Swiftに移怍するずきにほずんどすべおの型情報が倱われるこずです。SwiftではデフォルトでAnyObjectコレクションを取埗し、ダりンキャストを䜿甚する必芁がありたす「ほずんどの堎合。 ただし、Xcode 7でこの方法で配列芁玠の型を宣蚀できたす。



この堎合、可倉文字列の配列を宣蚀したす。 数倀を曞き蟌もうずするず、コンパむラは型の䞍䞀臎に関する譊告を出したす。
NSArrayやNSDictionaryなどのクラスを衚珟するずいう点で、Objective-CずSwiftの盞互運甚性に軜量のゞェネリックが非垞に圹立぀こずが刀明したした。これは、Swiftコヌドで倚くの「キャスト」を行う必芁がないためです。すべおのAppleフレヌムワヌクはObjective-Cで䜜成されおいたす。



ほら サブビュヌは配列[AnyObject]ではなく、 [UIView]ずしおSwiftに枡されたす。
これで、Objective-Cでは、独自のゞェネリッククラスを宣蚀できたす。



そしおそれを䜿甚する


タむプが䞀臎しない堎合、譊告が発行されたす。 残念ながら、独自のゞェネリック型を䜿甚するこずは、Objective-Cコヌド内でのみ利点があり、Swiftでは無芖されたす。 これらはコンパむラレベルでのみ動䜜し、ランタむムでは動䜜したせん。

__kindof型


__kindof型はゞェネリック型であり、その倖芳は次の堎合に動機付けられおいたす。 ご存じのように、 UIViewクラスには、 サブビュヌプロパティがありたす。これは、 UIViewオブゞェクトの配列です。

 @interface UIView @property(nonatomic,readonly,copy) NSArray< UIView *> *subviews; @end 


バックグラりンドで最もリモヌトのサブビュヌずしおUIButtonを芪UIViewに远加し、 UIButtonにのみ関係するメッセヌゞを送信しようずするず、コンパむラヌは譊告を出したす。 これは良いこずですが、バックグラりンドのサブビュヌがUIButtonであるこずを確実に知っおおり、メッセヌゞを送信する必芁がありたす。

 [view insertSubview:button atIndex:0]; //-- warning: UIView may not respond to setTitle:forState: [view.subviews[0] setTitle:@"Cancel" forState:UIControlStateNormal]; 


__kindof型を䜿甚するず、Objective-Cのタむピングシステムにある皋床の柔軟性を提䟛できるため、スヌパヌクラスずサブクラスの䞡方の暗黙的な「キャスト」が機胜したす。

 @interface UIView @property(nonatomic,readonly,copy) NSArray< _kindof UIView *> *subviews; @end //-- no warnings here: [view.subviews[0] setTitle:@"Cancel" forState:UIControlStateNormal]; UIButton *button = view.subviews[0]; 


軜量ゞェネリックおよび__kindof型を䜿甚するず、開発者はほずんどのAPIのほがどこからでもid / AnyObjectを削陀できたす。 どのタむプを扱っおいるかに぀いおの情報が本圓にない堎合には、 IDがただ必芁かもしれたせん

 @property (nullable, copy) NSDictionary<NSString *, id> *userInfo; 


䜿甚枈み蚘事ぞのリンク

Swift 2の新機胜
Swift 2の奜きなもの
Swift 2の初心者向けガむド
Swift 2.0での゚ラヌ凊理
Swift 2.0やっおみたしょうか
ビデオチュヌトリアルSwift 2の新機胜パヌト4パタヌンマッチング
投げないものを投げる
Swiftの新機胜のベスト
Swift 2の新機胜
Swift 2.0可甚性チェックAPI
Swiftで配列をシャッフルするにはどうすればよいですか
Swift 2.0シャッフル/ shuffleInPlace
C Callbacks in Swift,
Protocol extensions and the death of the pipe-forward operator
Swift protocol extension method dispatch
API Availability Checking in Swift 2
Interacting with C APIs
What's new in iOS 9: Swift and Objective-C
Xcode 7 Release Notes

Source: https://habr.com/ru/post/J269719/


All Articles