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)
}
}