繁体   English   中英

SwiftUI Escaping 闭包捕获变异的“自我”参数

[英]SwiftUI Escaping closure captures mutating 'self' parameter

我有一个可以通过两种方式打开的视图。 一个带有提供给它的数据,另一个带有对 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
    }
}

一个对象的初始化器不能做任何异步的事情。 它的工作是立即生成对象,并初始化其所有属性。

我很抱歉地说上面的答案是错误的。

一个对象的初始化器不能做任何异步的事情。 它的工作是立即生成对象,并初始化其所有属性

--> 这绝对是错误的。

10 年来,我在 Objective-C/C/Swift 中成功完成了大量多线程编程:没有任何内存泄漏、数据访问或访问竞争。

我已经成功地在制作我的游戏时异步初始化了一些对象,尤其是。 当我需要创建与以高性能方式初始化的对象以及大量惰性对象一样多的对象时。

初始值设定项可以异步执行,但这里的问题是无法修改以下转义闭包中的“self”。

init(reference: DocumentReference) {
    FirestoreService().fetchDocument(documentReference: reference) {    
        (request: RequestModel) in
         self.request = request
}

初始化器中的闭包详细是

{        
    @escaping [unowned self] (request: RequestModel) in

        self.request = request
}

因此,闭包中的 'self' 将比函数更长寿。 上面的代码似乎是视图类型的一部分,创建为结构。

https://docs.swift.org/swift-book/LanguageGuide/Closures.html

“如果 self 是结构或枚举的实例,您总是可以隐式地引用 self。但是,当 self 是结构或枚举的实例时,转义闭包无法捕获对 self 的可变引用。结构和枚举不允许共享可变性,如结构和枚举是值类型中所述。”

因此,“自我”不能是可变的。

这就是为什么您的代码会收到错误消息的原因:“转义闭包捕获了变异的‘self’参数”。

一个更好的解决方案是将部件移动到修改器内部的另一个位置,如“didAppear()”。

因为提问者没有在这里提供更多他或她的代码。 我无法在这里提供更具体的答案。

这大概可以分为两个不同的问题:

1:结构的属性不能在像“didSet”或“willSet”这样的闭包中改变。

2:只有使用@ObservedObject 或@EnvironmentObject .etc 声明的Observable 结构体才能在属性更改时调用UI 进行更新。 因为这样的修饰符赋予属性特殊的 getter 和 setter 函数

我正要发布一个关于这个问题的问题。 有了@Sungwood Kim 的回答,我现在明白了,我实际上是在尝试从内部更改值类型(结构),但不知道何时会发生(异步)。

因此,如果您需要这样的构造,例如:

  1. 异步读取其内容的struct (您的案例“Firestone”,我的是“HealthKit”)
  2. 在结构中, mutating的 function 处理异步读取,并希望使用接收到的数据更新自己

然后解决方法将要完成的更新移到外部:将更新代码移动到闭包中并在读取 function 中调用闭包。

这是一些代码:

struct Value {
    var localData: Int = 0

    mutating func thisOneWorks(_ completion: @escaping () -> Void) {
        DispatchQueue.main.async { completion() }
    }

    // Cannot compile the following function: "Escaping closure captures mutating 'self' parameter"
    mutating func thisOneDoesNotWork(_ value: Int) {
        DispatchQueue.main.async { self.localData = value }
    }
 }

其中completion包含更新代码:

    var value = Value()
    value.thisOneWorks { value.localData = 4711 }

注意:更新代码可能很大而且很复杂。 您可以将其放入同步执行的变异 function 并让完成关闭调用它。 有了这个,更新代码被封装在结构中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM