瀏覽代碼

Assume isolate for deinit

onevcat 1 年之前
父節點
當前提交
420f6de482
共有 1 個文件被更改,包括 20 次插入1 次删除
  1. 20 1
      Sources/Views/AnimatedImageView.swift

+ 20 - 1
Sources/Views/AnimatedImageView.swift

@@ -248,7 +248,9 @@ open class AnimatedImageView: KFCrossPlatformImageView {
     
     
     deinit {
     deinit {
         if isDisplayLinkInitialized {
         if isDisplayLinkInitialized {
-            self.displayLink.invalidate()
+            assumeIsolatedDuringDeinit { view in
+                view.displayLink.invalidate()
+            }
         }
         }
     }
     }
     
     
@@ -473,6 +475,23 @@ open class AnimatedImageView: KFCrossPlatformImageView {
     }
     }
 }
 }
 
 
+extension AnimatedImageView {
+    // An actor's deinit is nonisolated so we need to cleanup state that needs to exist past this instance's deinit. 
+    // Currently there is no way to accomplish this that wouldn't be an error in Swift 6, hopefully that changes at
+    // some point. This evolution proposal attempts to address this problem:
+    // https://github.com/apple/swift-evolution/blob/main/proposals/0371-isolated-synchronous-deinit.md
+    // Method influenced from
+    // https://github.com/apple/swift/blob/47803aad3b0d326e5231ad0d7936d40264f56edd/stdlib/public/Concurrency/ExecutorAssertions.swift#L351
+    @_unavailableFromAsync(message: "express the closure as an explicit function declared on the specified 'actor' instead")
+    private nonisolated func assumeIsolatedDuringDeinit<T>(_ operation: @MainActor (AnimatedImageView) throws -> T) rethrows -> T {
+        typealias Isolated = (AnimatedImageView) throws -> T
+        // To do the unsafe cast, we have to pretend it's @escaping.
+        return try withoutActuallyEscaping(operation) { (_ fn: @escaping Isolated) throws -> T in
+            return try fn(self)
+        }
+    }
+}
+
 @MainActor
 @MainActor
 protocol AnimatorDelegate: AnyObject {
 protocol AnimatorDelegate: AnyObject {
     func animator(_ animator: AnimatedImageView.Animator, didPlayAnimationLoops count: UInt)
     func animator(_ animator: AnimatedImageView.Animator, didPlayAnimationLoops count: UInt)