【问题标题】:Escaping closure captures mutating 'self' parameter: struct [duplicate]转义闭包捕获变异的“自我”参数:结构[重复]
【发布时间】:2022-01-10 07:38:55
【问题描述】:

我在 SwiftUI 中使用了以下代码:

import Foundation

public struct Trigger {
    public var value = false

    public mutating func toggle() {
        value = true
        let responseDate = Date().advanced(by: 3)

        OperationQueue.main.schedule(after: .init(responseDate)) {
            moveBack()
        }
    }

    private mutating func moveBack() {
        value = false
    }
}

但是,我收到一个错误:

转义闭包捕获变异的“自我”参数

我知道将结构更改为类可以解决这个问题,但是有没有办法在结构中的转义闭包中实际捕获变异的自我?

【问题讨论】:

  • 没有。视图模型应该几乎总是类,如果你想改变模型,它们几乎必须是类

标签: ios swift class struct closures


【解决方案1】:

如您所见,快速解决方案是使用 引用类型。但是为什么会这样呢?

Swift 结构体是值类型,因此它们是不可变的。您可以将函数标记为 mutating 以向编译器指示函数会改变结构,但这实际上意味着什么?

考虑一个简单的结构:

struct Counter {
   var count

   init(_ count: Int = 0)
   {
       self.count = count
   }

   mutating func increment() {
       self.count+=1
   }
}

现在,尝试将 this 的一个实例分配给 let 常量:

let someCounter = Counter()
someCounter.increment()
print(someCounter.count)

你会得到一个错误;你需要使用var

var someCounter = Counter()
someCounter.increment()
print(someCounter.count)

调用mutating 函数时实际发生的情况是创建了一个新的Counter,新的count 被分配给someCounter。它实际上是在说someCounter = Counter(someCounter.count+1)

现在,想想如果你可以在转义闭包中改变 self 会发生什么 - 新的 Counter 将在未来某个未指定的时间创建,但执行已经继续。来不及更新someCounter

正如您所发现的,使用class 的另一个优点是您可以使用ObservableObject,这使得更新您的 SwiftUI 视图变得更加容易。

【讨论】:

  • 感谢您非常详细的解释。我开始研究struct 解决方案的唯一原因是我一开始无法配置ObservableObject 解决方案。
  • 很好的解释。 (投票)。我正打算解释它,但你打败了我,而且可能比我做得更好。
【解决方案2】:

我完成的解决方案:

import Foundation
import Combine

public final class IntervalTrigger: ObservableObject {
    private let timeInterval: TimeInterval
    @Published var value = false

    public init(_ timeInterval: TimeInterval) {
        self.timeInterval = timeInterval
    }

    public func toggle() {
        value = true
        let responseDate = Date().advanced(by: timeInterval)
        OperationQueue.main.schedule(after: .init(responseDate)) { [weak self] in
            self?.value = false
        }
    }
}

【讨论】:

    猜你喜欢
    • 2021-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 2018-04-28
    • 1970-01-01
    相关资源
    最近更新 更多