所以我在这个问题上停留了一段时间,找不到在线解决我特定问题的问题。
我正在尝试在description
中设置值,该值被定义为惰性计算属性并利用自执行闭包。
要获取书的描述,我进行了API调用,将另一个处理程序传递给API完成处理程序,以便可以在惰性计算属性内设置书的描述。
我知道下面的代码是错误的,因为出现错误:
无法将类型'()'的值转换为指定的类型'字符串'
class Book : NSObject {
func getInfo(for name: String, handler: @escaping (_ string: String) -> String) {
let task = URLSession.shared.dataTask(with: "foo_book.com" + name) { (data, response, error) in
guard let data = data else {return}
descriptionStr = String(data: data, encoding: .utf8) ?? "No description found"
handler(descriptionStr)
}
}
lazy var description: String = {
getInfo(for: self.name) { str in
return str
}
}()
}
如何设置description
的值?
我尝试了两种方法。使用while循环来等待boolean:inelegant并破坏了异步的目的。在description
中使用临时变量-不起作用,因为getInfo在API调用完成之前返回。
如果您想知道我的用例:我想在表格视图中将书籍显示为单独的视图,但是当我打开表格视图时,我不想为每本书进行api调用。因此,我想懒惰地进行API调用。由于描述应该是不变的,因此我选择使其成为惰性计算属性,因为它只会被计算一次。
编辑:对于那些想知道的人,我的解决方案是下面提到的评论。我的方法不正确-我没有尝试异步设置属性,而是创建了一个方法并在视图控制器中获取了描述。
答案 0 :(得分:-1)
注释中的解释已经足够解决发生了什么问题,我将为您的用例添加解决方案。
我想将图书显示为表格视图中的单个视图,但是我 当我打开tableview时,不想为每本书进行api调用。 因此,我想懒惰地进行API调用。
首先,在这里使lazy
有意义。以后每当您调用描述时,都将保留URLSession
的引用,并会为所有书籍使用。看起来您将很容易造成内存泄漏。
第二,task.resume()
方法中需要getInfo
。
第三,您的模型(书)不应发出请求。为什么?想想,我上面给出了一个原因。异步确实意味着并行,所有这些网络调用都在队列中。如果模型太多,事件循环中的网络调用太多。
您可以将网络呼叫职责转移为服务BookService
,然后使用类似BookService.getInfo(_ by: name)
的方法。您的Book模型应该是愚蠢的课程。
class Book {
let description: String
init(desc: String) {
self.description = desc
}
}
现在,您的控制器/交互器将负责调用该服务以获取信息。在这里打个懒电话。
class BookTableViewController: ViewController {
init(bookService: BookService, book: [String]) {
}
# you can call when you want to show this book
func loadBook(_ name: String) -> Book {
BookService.getInfo(name).map { Book(desc: str) }
}
func tableView(UITableView, didSelectRowAt: IndexPath) {
let bookName = ....
# This is lazy loading
let book = loadBook(bookName)
showThisBook()
}
}
在这里,您可以对loadBook进行延迟调用。希望这会有所帮助。