如何通过 Swift 中的闭包设置惰性计算属性的值?
Posted
技术标签:
【中文标题】如何通过 Swift 中的闭包设置惰性计算属性的值?【英文标题】:How to set the value of lazy computed property via a closure in Swift? 【发布时间】:2019-06-17 15:47:28 【问题描述】:所以我在这个问题上纠结了一段时间,在网上找不到解决我特定问题的问题。
我正在尝试在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: 不优雅并且违背了异步的目的。在 description
中使用临时变量 - 不起作用,因为 getInfo 在 API 调用完成之前返回。
如果您想知道我的用例:我想在表格视图中将书籍显示为单独的视图,但我不想在打开表格视图时为每本书进行 api 调用。因此,我想懒惰地进行 API 调用。由于描述应该是不变的,因此我选择将其设为惰性计算属性,因为它只会计算一次。
编辑:对于那些想知道的人,我的解决方案是下面提到的 cmets。我的方法不正确 - 我没有尝试异步设置属性,而是创建了一个方法并在视图控制器中获取描述。
【问题讨论】:
术语:这不是计算属性,而是存储属性。所有计算的属性都是“惰性的”。语义:你不能让一个属性在 Swift 中异步返回一个值。 How to properly declare a computed property, when calculation uses background threads?的可能重复 另见:***.com/questions/25203556/…,尤其是 Rob Napier 的回答 您遇到了该错误,因为getInfo
返回的内容什么都不是(这就是错误中出现“()”的原因)而不是字符串。如果你想通过调用你的方法为description
返回一些东西,这需要返回String
【参考方案1】:
cmets 中的解释已经足以说明问题所在,我将在您的用例中添加解决方案。
我想在表格视图中将书籍显示为单独的视图,但我 当我打开表格视图时,不想为每本书进行 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 进行惰性调用。希望这会有所帮助。
【讨论】:
至少,让我知道为什么它被否决了;这样我就可以改进了。以上是关于如何通过 Swift 中的闭包设置惰性计算属性的值?的主要内容,如果未能解决你的问题,请参考以下文章