Swiftの結果タイプを理解する
Understanding Swift’s Result type
私たちが本当に望んでいるのは、非ブロッキング呼び出しです。つまりResult、戻り値として返送することはできません。代わりに、メソッドが2つのパラメーターを受け入れるようにする必要があります。1つはフェッチするURL用で、もう1つは値で呼び出される完了クロージャーです。つまり、メソッド自体は何も返しません。そのデータは、将来のある時点で呼び出される完了クロージャーを使用して戻されます。
@escaping。これは、「このクロージャーは、このメソッドの現在の実行の外で使用される可能性があるため、完了するまでメモリーを存続させてください。
文字列とクロージャを受け入れ、何も返しません–しかし、今度は、完了クロージャをさまざまな方法で呼び出します。
URLが悪い場合はを呼び出しますcompletion(.failure(.badURL))。
リクエストから有効なデータが返されたら、それを文字列に変換してからを呼び出しますcompletion(.success(stringData))。
リクエストからエラーが返された場合は、を呼び出しますcompletion(.failure(.requestFailed))。
なんらかの理由でデータまたはエラーが返されない場合は、を呼び出しますcompletion(.failure(.unknown))。
// // ContentView.swift // HotProspects // // import SwiftUI //--------------------------- struct ContentView: View { enum NetworkError: Error { case badURL, requestFailed, unknown } //ブロッキング関数呼び出し // func fetchData(from urlString: String) -> Result<String, NetworkError> { // .failure(.badURL) // } //非ブロッキング呼び出し-> Void // func fetchData(from urlString: String, completion: (Result<String, NetworkError>) -> Void) { // completion(.failure(.badURL)) // } // func fetchData(from urlString: String, completion: @escaping (Result<String, NetworkError>) -> Void) { // DispatchQueue.main.async { // completion(.failure(.badURL)) // } // } func fetchData(from urlString: String, completion: @escaping (Result<String, NetworkError>) -> Void) { // check the URL is OK, otherwise return with a failure guard let url = URL(string: urlString) else { completion(.failure(.badURL)) return } URLSession.shared.dataTask(with: url) { data, response, error in // the task has completed – push our work back to the main thread DispatchQueue.main.async { if let data = data { // success: convert the data to a string and send it back let stringData = String(decoding: data, as: UTF8.self) completion(.success(stringData)) } else if error != nil { // any sort of network failure completion(.failure(.requestFailed)) } else { // this ought not to be possible, yet here we are completion(.failure(.unknown)) } } }.resume() } var body: some View { Text("Hello, World!") .onAppear { self.fetchData(from: "https://www.apple.com") { result in switch result { case .success(let str): print(str) case .failure(let error): switch error { case .badURL: print("Bad URL") case .requestFailed: print("Network problems") case .unknown: print("Unknown error") } } } } } } //--------------------------- struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
ObservableObjectの変更を手動で公開する
Manually publishing ObservableObject changes
import SwiftUI //--------------------------- class DelayedUpdater: ObservableObject { //@Published var value = 0 var value = 0 { willSet { objectWillChange.send() } } init() { for i in 1...10 { DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) { self.value += 1 } } } } //--------------------------- struct ContentView: View { @ObservedObject var updater = DelayedUpdater() var body: some View { Text("Value is: \(updater.value)") } } //---------------------------
willSetオブザーバー内に機能を追加する機会があります。おそらく、何かをログに記録したり、別のメソッドを呼び出したり、整数を内部に固定したりしてvalue、範囲外にならないようにしたい場合があります。これですべてが制御されます。
SwiftUIでの画像補間の制御
Controlling image interpolation in SwiftUI
struct ContentView: View { var body: some View { // Image("example") // .resizable() // .scaledToFit() // .frame(maxHeight: .infinity) // .background(Color.black) // .edgesIgnoringSafeArea(.all) Image("example") .interpolation(.none) .resizable() .scaledToFit() .frame(maxHeight: .infinity) .background(Color.black) .edgesIgnoringSafeArea(.all) } }