【SwiftUI】Betaからの変更点まとめ

# この投稿は何？
SwiftUIフレームワークをによる開発が可能なXcode11も正式版ががリリースされました。とは言え、SwiftUIの特徴でもあるキャンバスはmacOS10.15 Catalinaが動作するMacで使用可能です。Catalinaの正式リリースは10月以降です。
なので、学習リソースはそれなりに用意されているSwiftUIですが、まだ気軽に試すわけにはいきません。
正式版がリリースされた時、スムーズに学習を始めるために__これまでにおこなわれたSwiftUIの変更点__をまとめておきます。

### 環境
macOS10.15 Catalina beta9
Xcode11 

# About SwiftUI
49833933
UIColorまたはNSColorから、Colorを作成できるようになりました。

50280673
NSManagedObjectはObservableObjectに準拠するようになりました。
新しい@FetchRequestプロパティラッパーは、フェッチリクエストの結果からビューを駆動でき、managedObjectContextが環境に含まれるようになりました。

50395282
一貫性を保つために、ジェスチャー修飾子の名前が変更されました。
たとえば…tapAction（count：_ :)はonTapGesture（count：perform :)に、
longPressAction(minimumDuration: maximumDistance: _: pressing:)はonLongPressGesture(minimumDuration: maximumDistance; pressing: perform:)に変更されます。

51147116
テキストのデフォルトの行制限がnilになり、デフォルトで折り返されるようになりました。

51168712
ContentSizeCategoryおよびその他のいくつかの列挙型は、CaseIterableになりました。

51769046
SegmentedControlは、ピッカーのスタイルになりました。

50800624
BindableObjectは、CombineフレームワークのObservableObjectプロトコルに置き換えられました。

オブジェクトが変更される前に発行するobjectWillChangeパブリッシャーを定義することにより、ObservableObjectに手動で準拠できます。
ただし、デフォルトでは、ObservableObjectは自動的にobjectWillChangeを合成し、@Publishedプロパティが変更される前に出力します。

````Swift:
// RoomStore.swift
import Foundation

class RoomStore: ObservableObject {
    @Published var rooms: [Room] = []
}

struct Room: Identifiable {
    var id: UUID
    var name: String
    var capacity: Int
    var hasVideo: Bool
}

// ContentView.swift
import SwiftUI

struct ContentView: View {
    @ObservedObject var store: RoomStore

    var body: some View {
        NavigationView {
            List(store.rooms) { room in
                RoomCell(room: room)
            }
            .navigationBarTitle("Rooms")
        }
    }
}
````
@ObjectBindingは、@ObservedObjectに置き換えられました。

SE-0261
Identifiableプロトコルは、Swift標準ライブラリの一部になりました。
その結果、モデルファイルにSwiftUIフレームワークをインポートする必要がなくなりました。

51712481
EnvironmentValues構造体には、環境からアクセシビリティ値を読み取る新しいプロパティとして、以下の4つがあります。
- accessibilityDifferentiateWithoutColor
- accessibilityReduceTransparency
- accessibilityReduceMotion
- accessibilityInvertColors

50391847
ビューに対するforegroundColor(_:)修飾子との一貫性のために、テキストのcolor(_:)修飾子はforegroundColor(_:)に名前が変更されました。

51580731
BindableObjectプロトコルの要件は、didChangeではなくwillChangeになりました。
オブジェクトの変更後ではなく、変更前に送信されます。この変更により、変更通知の合体が改善されました。

51991601
RangeReplaceableCollectionプロトコルはremove(atOffsets:)メソッドを含むように拡張されました。
MutableCollectionプロトコルはmove(fromOffsets:toOffset:)メソッドを含むように拡張されました。
新しいメソッドはそれぞれ、ForEachビューでonMove(perform:)およびonDelete(perform:)修飾子とともに使用するIndexSetインスタンスを取ります。

52075730
改善されたプレゼンテーション修飾子を追加されました。
環境内のisPresentedとともに、以前のpresentation(_:)、Sheet 、Modal、およびPresentationLink型と置き換え。 
- sheet(isPresented: onDismiss: content:)修飾子
- actionSheet(isPresented: content:)修飾子
- alert(isPresented: content:) 修飾子

50280375
アニメーションを作成するAPIを更新しました。
基本的なアニメーションの名前は、linearやeaseInOutなどの曲線タイプにちなんで付けられました。
- 補間ベースのアニメーション spring(mass: stiffness: damping: initialVelocity:)メソッド → interpolatingSpring(mass: stiffness: damping: initialVelocity:)メソッド
- fluidSpring(stiffness: dampingFraction: blendDuration: timestep: idleThreshold:)メソッド → インタラクティブにアニメーションさせる interactiveSpring(response: dampingFraction: blendDuration:)メソッド → インタラクティブにさせない spring(response: dancingFraction: blendDuration:)

51849885
CTFontからFontを作成するイニシャライザーを追加しました。

51636729
NavigationViewをスタイルできる2つの新しいスタイルプロパティを追加しました。
- StackNavigationViewStyle → iPhoneとAppleTVのデフォルトスタイル
- DoubleColumnNavigationViewStyle → iPadとMacのデフォルトスタイル
デフォルトでは、iPhoneとAppleTVのナビゲーションビューは視覚的にナビゲーションスタックを反映します。
iPadとMacでは、スプリットビュー形式のナビゲーションビューが表示されます。

DoubleColumnNavigationViewStyleスタイルを使用する場合、ナビゲーションビュー作成時に2つのビューを提供できます。
1つ目はマスター、2つ目は詳細です。

````Swift:
NavigationView {
    MyMasterView()    // マスター
    MyDetailView()      // 詳細
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())    // NavigationViewのスタイルを指定 `
```

### Known Issues（既知の問題）
53706729
Swiftパッケージ内にSwiftUIを含むアプリは、iOS13より前のバージョンのiOSでは実行できない場合があります。

回避策: SwiftUIフレームワークを含まないOSにバックデプロイする場合、-weak_framework SwiftUIフラグをその他に追加します [ビルド設定]タブのリンカーフラグ設定。フレームワークの弱いリンクの詳細については、フレームワークと弱いリンクを参照してください。この回避策は、SwiftUIをインポートする動的にリンクされたSwiftパッケージを使用する場合には適用されません。

Deprecations
53187891
コマンド構造体は、セレクターを直接渡すことで置き換えられました。

50630794
NavigationDestinationLinkおよびDynamicNavigationDestinationLinkは非推奨です。
これらの機能はNavigationLinkに含まれるようになりました。

 50654095
Length型はCGFloatに置き換えられました。

51012120
TabbedViewの名前がTabViewになりました。 

51190531
HAlignmentとVAlignmentは非推奨になりました。
代わりに、より柔軟なHorizo​​ntalAlignmentまたはVerticalAlignment型を使用し、テキストにはTextAlignmentを使用してください。

51557694
SelectionManagerプロトコルが削除されました。
オプショナルを使用して、選択に対して直接、インスタンスを設定してください。

51641238
isPresented環境値は廃止されました。
より一般的なpresentationMode値に置き換えられました。

52911961
StaticMemberプロトコルは非推奨です。
代わりに、プロトコルに準拠したタイプを直接使用してください。
たとえば、wheel静的メンバーではなくWheelPickerStyleのインスタンスを直接使用します。

53067530
background(_: alignment:)およびborder(_: width:)修飾子の複雑なオーバーロードは非推奨です。
代わりにbackground(_: alignment:)またはoverlay(_: alignment:)の図形を使用してこれらを描画します。

52587863
ベータ版で廃止済みのSwiftUI APIは削除されました。

52976883, 52029393
Collectionプロトコルのidentified(by:)メソッドは、専用のinit(_: id: selection: rowContent:)およびinit(_: id: content:)イニシャライザを優先して廃止されました。

IntのIdentifiableプロトコルへの遡及的な適合性が削除されました。
この適合に依存するコードを変更して、\.selfを関連するイニシャライザのidパラメータに渡します。
Intの一定範囲は引き続き受け入れられます。

````Swift:
List(0..<5) {
    Text("Rooms")
}
````

ただし、実行時に変化する範囲を渡さないでください。 
実行時に変化する変数を使用して範囲を定義すると、リストには初期範囲に従ってビューが表示され、その後で範囲を更新しても無視されます。 
51624798
バインディング構造のいくつかの拡張機能が削除されました。 
次のようなコードがある場合:

````Swift:
struct LandmarkList: View {
    var landmark: [Landmark]
    @Binding var favorites: Set<Landmark>

    var body: some View {
        List(landmarks) { landmark in
            Toggle(landmark.name, isOn: self.$favorites.contains(landmarkID))
        }
    }
}
````

`Set`構造体に、次の添え字を定義します。

````Swift:
extension Set {
    subscript(member: Element) -> Bool {
        get { contains(member) }
        set {
            if newValue {
                insert(member)
            } else {
                remove(member)
            }
        }
    }
}
````

そして、`self.$favorites.contains(landmarkID)`を`self.$favorites[landmarkID]`に変更します。 

51624798
`Collection`プロトコルへの`Binding`構造体の条件付き適合性は、削除されました。
以下のようなコードがある場合: 

````Swift:
struct LandmarkList: View {
    @Binding var landmark: [Landmark]
    var body: some View {
        List(landmarks) { landmark in
            Toggle(landmark.value.name, isOn: landmark[\.isFavorite])
        }
    }
}
````
以下のようにコレクション型を定義します。 

````Swift:
struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
    typealias Index = Base.Index
    typealias Element = (index: Index, element: Base.Element)
    let base: Base
    var startIndex: Index { base.startIndex }
    var endIndex: Index { base.startIndex }  
    
    func index(after i: Index) -> Index { 
        base.index(after: i) 
    }

    func index(before i: Index) -> Index {
        base.index(before: i)
    }
    
    func index(_ i: Index, offsetBy distance: Int) -> Index {
        base.index(i, offsetBy: distance) 
    }

    subscript(position: Index) -> Element { 
        (index: position, element: base[position]) 
    }
}

extension RandomAccessCollection {
    func indexed() -> IndexedCollection<Self> {
        IndexedCollection(base: self)
    }
}
````

そして、コードを更新します。

````Swift:
struct LandmarkList: View {
    @Binding var landmarks: [Landmark]
    var body: some View {
        List(landmarks.indexed(), id: \.1.id) { (index, landmark) in
            Toggle(landmark.name, isOn: self.$landmarks[index].isFavorite)
        }
    }
}
````

51494692
以下の修飾子は非推奨になりました。
- `relativeWidth(_:)`
- `relativeHeight(_:)`
- `relativeSize(width: height:)`

代わりに、他の`frame(minWidth: idealWidth: maxWidth: minHeight: idealHeight: maxHeight: alignment:)`修飾子などを使用します。