SwiftUI 转义闭包捕获变异的“自我”参数
Posted
技术标签:
【中文标题】SwiftUI 转义闭包捕获变异的“自我”参数【英文标题】:SwiftUI Escaping closure captures mutating 'self' parameter 【发布时间】:2020-03-15 23:43:01 【问题描述】:我有一个可以通过两种方式打开的视图。一个带有提供给它的数据,另一个带有对 Firestore 文档的文档引用。我创建了两个构造函数,第一个提供数据,另一个提供文档参考。 然后我使用此引用进行网络调用位我收到错误:
Escaping closure captures mutating 'self' parameter
关于如何解决这个问题的任何想法?
@State var request: RequestModel?
init(request: RequestModel)
self.request = request
init(reference: DocumentReference)
FirestoreService().fetchDocument(documentReference: reference) (request: RequestModel) in
self.request = request
【问题讨论】:
视图是结构体。尝试在闭包中更改它们是没有意义的。你能做的最好的就是改变一个副本。 你能说得具体一点吗? 【参考方案1】:很抱歉,上面的答案是错误的。
对象的初始化器不能做任何异步操作。它的工作是立即生成对象,并初始化其所有属性
--> 这是绝对错误的。
10 年来,我在 Objective-C/C/Swift 中成功完成了大量多线程编程:没有任何内存泄漏、数据访问或访问竞争。
我已经成功地让一些对象在制作我的游戏时异步初始化,尤其是。当我需要以高性能方式创建尽可能多的对象以及许多惰性对象时。
initializers 可以做异步,但是这里的问题是 'self' 在下面的转义闭包中不能被修改。
init(reference: DocumentReference)
FirestoreService().fetchDocument(documentReference: reference)
(request: RequestModel) in
self.request = request
详细的初始化器中的闭包是
@escaping [unowned self] (request: RequestModel) in
self.request = request
因此,闭包中的“self”将比函数更长寿。 而上面的代码似乎是 View 类型的一部分,被创建为结构体。
来自https://docs.swift.org/swift-book/LanguageGuide/Closures.html,
“如果 self 是结构或枚举的实例,则始终可以隐式引用 self。但是,当 self 是结构或枚举的实例时,转义闭包无法捕获对 self 的可变引用。结构和枚举不允许共享可变性,如结构和枚举是值类型中所述。"
因此,'self' 不能是可变的。
这就是您的代码收到错误消息的原因:“Escaping Closure captures mutating 'self' parameter”。
更好的解决方案是将部件移动到修饰符内的另一个位置,例如“didAppear()”。
因为提问者没有在此处提供更多他或她的代码。 我无法在这里提供更具体的答案。
【讨论】:
【参考方案2】:对象的初始化器不能做任何异步操作。它的工作是立即生成对象,并初始化其所有属性。
【讨论】:
那么我怎样才能达到预期的效果呢?我试图将逻辑移动到一个函数并在初始化时调用它。它的工作,但视图没有被更新。 如果你有一些数据需要通过网络获取,那是某种 ObservableObject 类实例存在于数据空间中,而不是在实例化时初始化的实例属性。 这已经讨论过很多次了。为什么不搜索?这是一个开始:***.com/questions/tagged/swiftui+firebase 好的,我会检查它...最后一个问题..为什么这些调用在 .appear() 中工作正常? 因为出现的不是对象初始化。【参考方案3】:这大概可以分为两个不同的问题:
1: 结构的属性不能在像'didSet'或'willSet'这样的闭包中改变。
2:只有使用@ObservedObject 或@EnvironmentObject .etc 声明的Observable struct 才能在属性更改时调用UI 进行更新。因为这样的修饰符赋予属性特殊的 getter 和 setter 函数
【讨论】:
以上是关于SwiftUI 转义闭包捕获变异的“自我”参数的主要内容,如果未能解决你的问题,请参考以下文章