簡體   English   中英

Escaping 閉包捕獲變異的“自我”參數:結構

[英]Escaping closure captures mutating 'self' parameter: struct

我有以下與 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
    }
}

但是,我收到一個錯誤:

Escaping 閉包捕獲變異的“自我”參數

在此處輸入圖像描述

我知道將結構更改為 class 可以解決這個問題,但是有沒有辦法在結構中的 escaping 閉包中實際捕獲變異自我?

如您所見,快速解決方案是使用參考類型class 但為什么會這樣呢?

Swift 結構是值類型,因此它們是不可變的。 您可以將 function 標記為正在mutating ,以向編譯器指示 function 會變異該結構,但這實際上意味着什么?

考慮一個簡單的結構:

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 func 時,實際發生的是一個新的Counter被創建,新的count被分配給someCounter 它實際上是在說someCounter = Counter(someCounter.count+1)

現在,想想如果你可以在 escaping 閉包中改變self會發生什么 - 新的Counter將在未來某個未指定的時間創建,但執行已經繼續。 更新someCounter為時已晚。

正如您所發現的,使用class的另一個優點是您可以使用ObservableObject ,這使得更新 SwiftUI 視圖更加容易。

我完成的解決方案:

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
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM