###Пример первый.
Имеем сложный метод генерации случайных чисел, который в случае неудачи генерирует ошибку:
class Generator {
enum GeneratorError: Error {
case invalidRandom
}
class func superRandom() throws -> Int {
let result = arc4random()
guard result <= UInt32(Int32.max) else { throw GeneratorError.invalidRandom }
return Int(result)
}
}
Поскольку метод сложный и ресурсоёмкий, хотелось бы выполнить его один раз и результат записать в переменную, как ленивое свойство (lazy в данном случае не подойдет) на помощь приходят замыкания:
var result: () throws -> Int = {
var result: Int!
return {
if result == nil { result = try Generator.superRandom() }
return result
}
}()
Отработает он как положено один раз и есть возможность отловить ошибку или передать её дальше:
do {
var result = try self.result()
print(result)
result = try self.result()
print(result)
result = try self.result()
print(result)
} catch {
print(error)
}
###Пример второй.
Имеем метод загрузки данные из интернета, обычно выглядет так:
func load(url: String, comletion: @escaping (_ data: Data, _ error: Error?) -> ()) {
URLSession.shared.dataTask(with: URL(string: url)!) { data, _, error in
comletion(data ?? Data(), error)
}.resume()
}
И используется так, что конечно хорошо но совсем не круто:
load(url: "http://swiftbook.ru") { data, error in
guard error != nil else {
let alert = UIAlertController(title: "Error", message: error!.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
self.data = data
}
Самое в нем ужасное “error != nil” когда есть “do catch”, по этому воспользуемся силой замыканий и немного усложним его:
func superLoad(url: String, completion: @escaping (_ data: () throws -> Data) -> ()) {
guard let url = URL(string: url) else {
completion({ throw NetworkError.invalidURL })
return
}
URLSession.shared.dataTask(with: url) { data, _, error in
completion({
guard error == nil else { throw error! }
guard let data = data else { throw NetworkError.invalidData }
return data
})
}.resume()
}
Теперь вызов выглядет очень круто и понятно))):
superLoad(url: "http://swiftbook.ru") { data in
do {
self.data = try data()
} catch {
let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}