ここでいう Swift Playgrounds はXcodeに付属のPlaygroundではなく、iPadアプリとしての Swift Playgroundsを指しています。
以降、 Swift Playgrounds は 「iPadアプリのSwift Playground」、 Xcode Playground はXcodeに付属のPlaygroundと使い分けます。
Swift Playgroundのmainファイルでは、Previewを UIHostingController で描画するようにします。
Swift Playgroundsでのmainと、その他のファイルとでは、別Module扱いになるため、 public 修飾子ないものにはアクセスできません。 import はいらない。
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)extensionForEachwhere Data == Range<Int>, ID == Int, Content :View {
/// Creates an instance that computes views on demand over a *constant*/// range.////// This instance only reads the initial value of `data` and so it does not/// need to identify views across updates.////// To compute views on demand over a dynamic range use/// `ForEach(_:id:content:)`.publicinit(_ data:Range<Int>, @ViewBuildercontent:@escaping (Int)->Content)
}
/** * Creates a new {@link LiveData} object does not emit a value until the source LiveData value * has been changed. The value is considered changed if {@code equals()} yields {@code false}. * * @param source the input {@link LiveData} * @param <X> the generic type parameter of {@code source} * @return a new {@link LiveData} of type {@code X} */@MainThread@NonNullpublicstatic <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) {
final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>();
outputLiveData.addSource(source, new Observer<X>() {
boolean mFirstTime = true;
@Overridepublicvoid onChanged(X currentValue) {
final X previousValue = outputLiveData.getValue();
if (mFirstTime
|| (previousValue == null && currentValue != null)
|| (previousValue != null && !previousValue.equals(currentValue))) {
mFirstTime = false;
outputLiveData.setValue(currentValue);
}
}
});
return outputLiveData;
}