Quellcode durchsuchen

Decode the image ref to workaround the ref retain issue

onevcat vor 3 Jahren
Ursprung
Commit
3ac35f767f
2 geänderte Dateien mit 37 neuen und 16 gelöschten Zeilen
  1. 14 10
      Sources/Image/ImageDrawing.swift
  2. 23 6
      Sources/Views/AnimatedImageView.swift

+ 14 - 10
Sources/Image/ImageDrawing.swift

@@ -548,20 +548,24 @@ extension KingfisherWrapper where Base: KFCrossPlatformImage {
         if images != nil { return base }
         #endif
 
-        guard let refImage = cgImage else {
+        guard let refImage = cgImage,
+              let decodedRefImage = refImage.decoded(on: context, scale: scale) else
+        {
             assertionFailure("[Kingfisher] Decoding only works for CG-based image.")
             return base
         }
+        return KingfisherWrapper.image(cgImage: decodedRefImage, scale: scale, refImage: base)
+    }
+}
 
-        let size = CGSize(width: CGFloat(refImage.width) / scale, height: CGFloat(refImage.height) / scale)
-
-        context.draw(refImage, in: CGRect(origin: .zero, size: size))
-
-        guard let cgImage = context.makeImage() else {
-            return base
-        }
-
-        return KingfisherWrapper.image(cgImage: cgImage, scale: scale, refImage: base)
+extension CGImage {
+    func decoded(on context: CGContext, scale: CGFloat) -> CGImage? {
+        let size = CGSize(width: CGFloat(self.width) / scale, height: CGFloat(self.height) / scale)
+        context.draw(self, in: CGRect(origin: .zero, size: size))
+        guard let decodedImageRef = context.makeImage() else {
+            return nil
+        }
+        return decodedImageRef
     }
 }
 

+ 23 - 6
Sources/Views/AnimatedImageView.swift

@@ -545,14 +545,31 @@ extension AnimatedImageView {
             guard let cgImage = CGImageSourceCreateImageAtIndex(imageSource, index, options as CFDictionary?) else {
                 return nil
             }
-
-            let image = KFCrossPlatformImage(cgImage: cgImage)
             
-            guard let context = GraphicsContext.current(size: imageSize, scale: imageScale, inverting: true, cgImage: cgImage) else {
-                return image
+            if #available(iOS 15, tvOS 15, *) {
+                // From iOS 15, a plain image loading causes iOS calling `-[_UIImageCGImageContent initWithCGImage:scale:]`
+                // in ImageIO, which holds the image ref on the creating thread.
+                // To get a workaround, create another image ref and use that to create the final image. This leads to
+                // some performance loss, but there is little we can do.
+                // https://github.com/onevcat/Kingfisher/issues/1844
+                guard let context = GraphicsContext.current(size: imageSize, scale: imageScale, inverting: true, cgImage: cgImage),
+                      let decodedImageRef = cgImage.decoded(on: context, scale: imageScale)
+                else {
+                    return KFCrossPlatformImage(cgImage: cgImage)
+                }
+                
+                return KFCrossPlatformImage(cgImage: decodedImageRef)
+            } else {
+                let image = KFCrossPlatformImage(cgImage: cgImage)
+                if backgroundDecode {
+                    guard let context = GraphicsContext.current(size: imageSize, scale: imageScale, inverting: true, cgImage: cgImage) else {
+                        return image
+                    }
+                    return image.kf.decoded(on: context)
+                } else {
+                    return image
+                }
             }
-            
-            return backgroundDecode ? image.kf.decoded(on: context) : image
         }
         
         private func updatePreloadedFrames() {