Swift 5.1-新機能





Swift 5.0はXcode 10.2のリリースで利用可能になりましたが、次のバージョンでの作業は継続されており、その中に期待できることのニュースが既にあります。



Swift 5.1の重要な機能はモジュールの安定性です 。これにより、サードパーティのライブラリを使用して作成されたSwiftコンパイラのバージョンを気にすることなく、サードパーティのライブラリを使用できます。 Swift 5.0で得たABIの安定性のように見えますが、わずかな違いがあります。ABIの安定性は、実行時のSwiftバージョンとコンパイル時のモジュール安定性の違いを解決します。



この重要な革新に加えて、Swiftでいくつかの重要な改善が行われます。この記事では、実際に動作を確認できるように、例を挙げて説明します。



普遍的な自己



SE-0068Selfの使用を拡張して、クラス、構造、および列挙内でそれを含む型を参照するようにします。 これは通常、実行時に何かの正確なタイプを判別する必要がある動的タイプに役立ちます。



例として、次のコードを検討してください。



class NetworkManager { class var maximumActiveRequests: Int { return 4 } func printDebugData() { print("Maximum network requests: \(NetworkManager.maximumActiveRequests).") } }
      
      





ここでは、 NetworkManagerクラス内で静的プロパティmaximumActiveRequestsを定義し、 printDebugData()メソッドを追加してこのプロパティを印刷します。 ここではすべて問題ありませんが、 NetworkManagerから継承することを決定するまでのみです。



 class ThrottledNetworkManager: NetworkManager { override class var maximumActiveRequests: Int { return 1 } }
      
      





この相続人では、maximumActiveRequestsプロパティを1に等しくなるように変更しますが、 printDebugData()を呼び出すと、親クラスから値を推測します。



 let manager = ThrottledNetworkManager() manager.printDebugData()
      
      





ここで、4ではなく1を取得する必要があります。また、ここでSE-0068をレスキューします。現在のタイプを参照するには、 Self (大文字の 'S')を使用できます。 したがって、親クラスのprintDebugData()メソッドを次のように書き換えることができます。



 class ImprovedNetworkManager { class var maximumActiveRequests: Int { return 4 } func printDebugData() { print("Maximum network requests: \(Self.maximumActiveRequests).") } }
      
      





つまり、Swiftの以前のバージョンのプロトコルで動作していたのと同じようにSelfが動作します。



あいまいな場合の警告なし



Swiftのオプションは、 someおよびnoneの 2つのオプションを持つ列挙として実装されます。 noneオプションを持つ独自の列挙を作成し、 optionalでラップすると、混乱を招く可能性があります 。 例:



 enum BorderStyle { case none case solid(thickness: Int) }
      
      





オプションではないものを使用すると、すべてがきれいになります。



 let border1: BorderStyle = .none print(border1)
      
      





これは「none」を出力します。 ただし、この列挙にオプションを使用すると、問題が発生します。



 let border2: BorderStyle? = .none print(border2)
      
      





Nilはここで出力されます。これは、Swiftが.noneはオプションがであることを意味すると考えているためですが、実際に BorderStyle.noneの値を持つオプションです。

Swift 5.1では、このようなあいまいさが発生した場合、警告が表示されます:

「「Optional.none」を意味すると仮定します。 代わりに「BorderStyle.none」を意味しましたか?」

したがって、開発者は、自分のコードではすべてがスムーズになるとは限らないことを通知されます。



オプションの列挙と非オプションの列挙のマッチング



Swiftは、オプション/非オプションのテキストと整数値を組み合わせるときにスイッチ/ケースコンストラクトを理解できるほどスマートですが、列挙型の場合はそうではありません。



Swift 5.1では、スイッチ/ケースを使用して、列挙オプションと非オプションオプションを一致させることができます。



 enum BuildStatus { case starting case inProgress case complete } let status: BuildStatus? = .inProgress switch status { case .inProgress: print("Build is starting…") case .complete: print("Build is complete!") default: print("Some other build status") }
      
      





Swiftは、オプションの列挙をオプションではないオプションにマッピングできます。ここに「ビルドを開始しています...」が表示されます。



注文したコレクションを比較する



SE-0240では、順序付けられたコレクション間の差異を計算し、結果の比較結果をコレクションに適用する機能が導入されました。 これは、TableViewに複雑なコレクションがあり、アニメーションを使用して多くの要素を追加または削除する必要がある開発者にとって興味深い場合があります。



基本的な原理はシンプルです-Swift 5.1は新しいメソッドの違い(from :)を提供し、2つの順序付けられたコレクションの違い、つまり追加する要素と削除する要素を決定します。 これは、 Equatableプロトコルに準拠するアイテムを含む順序付きコレクションに適用されます。



これを実証するために、2つの値の配列を作成し、一方の差を計算し、差のリストを調べて適用し、2つのコレクションを同じにします。



注:Swiftは現在Appleのオペレーティングシステムの一部として配布されているため、 #availableチェックで新しい言語ツールを使用して、必要な機能をサポートするOSでコードが実行されることを確認する必要があります。 将来リリースされる可能性がある未知の未発表のOSで実行される機能には、「9999」という特別なバージョン番号が使用されます。これは「正しいバージョン番号がまだわかりません」という意味です。



 var scores1 = [100, 91, 95, 98, 100] let scores2 = [100, 98, 95, 91, 100] if #available(iOS 9999, *) { let diff = scores2.difference(from: scores1) for change in diff { switch change { case .remove(let offset, _, _): scores1.remove(at: offset) case .insert(let offset, let element, _): scores1.insert(element, at: offset) } } print(scores1) }
      
      





より高度なアニメーションの場合、結果の違いのリストの3番目のパラメーターrelatedWithを使用できます。 したがって、 .insert(let offset、let element、_)の代わりに、 .insert(let offset、let element、let relatedWith)を記述できます。 これにより、変更のペアを同時に追跡することができます。コレクション内の要素を2ポジション下に移動すると、要素が削除されてから追加されます。



差分を1つずつ手動で適用する代わりに、新しいapply()メソッドを使用してそれらを一度に適用できます。



 if #available(iOS 9999, *) { let diff = scores2.difference(from: scores1) let result = scores1.applying(diff) ?? [] }
      
      





初期化されていない配列の作成



SE-0245は、配列にデフォルト値を入力しない新しいイニシャライザーを導入しました。 以前はプライベートAPIとして利用可能であったため、Xcodeはコード補完を要求しませんでしたが、必要な場合は使用でき、この機能が将来はなくなる可能性があることを理解していました。



初期化子を使用するには、配列のサイズを設定してから、配列を値で埋めるクロージャーを渡します。 クロージャは、可変バッファへの安全でないポインタと、実際に使用する値の数を示す2番目のパラメータを受け取ります。



たとえば、次のような10個のランダムな整数の配列を作成できます。



 let randomNumbers = Array<Int>(_unsafeUninitializedCapacity: 10) { buffer, initializedCount in for x in 0..<10 { buffer[x] = Int.random(in: 0...10) } initializedCount = 10 }
      
      





いくつかのルールがあります:



  1. 要求したボリューム全体を使用する必要はありませんが、それを超えることはできません。 つまり、配列のサイズを10に設定すると、 initializedCountを0〜10の範囲で設定できますが、11は設定できません。
  2. 配列で使用される要素を初期化していない場合、たとえば、 initializedCountを5に設定したが、要素0〜4に実際の値を指定しなかった場合、ほとんどの場合、ランダムな値を受け取ります。 ご存知のように、これは悪いオプションです。
  3. initializeCountを設定しない場合、0に等しくなり、割り当てたすべてのデータが失われます。


はい、 map()を使用してコードを書き換えることができます。



 let randomNumbers2 = (0...9).map { _ in Int.random(in: 0...10) }
      
      





これは明らかに読みやすいですが、それほど効率的ではありません。範囲を作成し、新しい空の配列を作成してサイズを割り当て、範囲全体を「通過」して、各要素にクロージャーを適用します。



おわりに



Swift 5.1はまだ開発中です。Swift自体の最終ブランチは通過しましたが、他のいくつかの関連プロジェクトからの変更はまだ見えています。



したがって、最も重要な変更はモジュールの安定性であり、開発チームがこれに懸命に取り組んでいることが知られています。 Swift 5.1は、Swift 5.0に比べて開発時間が非常に短いため、多大な労力と注意が必要であると述べていますが、正確なリリース日は示していません。 WWDC19へのアクセスを想定できますが、特定の日付に急ぐ必要がある場合はそうではないことは明らかです。



注目に値する別のポイント。 このリストに対する2つの変更(「noneオプションのあいまいさに関する警告」および「オプションと非オプションの列挙のマッチング」)は、Swiftの進化の結果ではなく、バグとして認識され、調整されました。



All Articles