提问人:Sandeep Sahani 提问时间:12/8/2022 最后编辑:Sandeep Sahani 更新时间:12/8/2022 访问量:294
在将 gif 加载到 UIImageView 期间在 Xcode 中收到 STRANGE 警告
Getting a STRANGE warning in Xcode during loading gif into UIImageView
问:
我正在做一个项目,该项目将 gif 从其 url 加载到 UIImageView。
在 Xcode 中运行应用程序时会发出奇怪的警告,并且 gif 看起来也很迟钝。
警告如下所示:
不应在此应用程序的主线程上同步加载 https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/5eeea355389655.59822ff824b72.gif,因为它可能会导致 UI 无响应。请切换到异步网络 API 例如 URLSession。
我用于使用 url 加载 gif 的代码片段。
//
// iOSDevCenters+GIF.swift
// Get Fit
//
// Created by Sandeep Sahani on 08/12/22.
//
import UIKit
import ImageIO
// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
// Consider refactoring the code to use the non-optional operators.
fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
}
extension UIImage {
public class func gifImageWithData(_ data: Data) -> UIImage? {
guard let source = CGImageSourceCreateWithData(data as CFData, nil) else {
print("image doesn't exist")
return nil
}
return UIImage.animatedImageWithSource(source)
}
public class func gifImageWithURL(_ gifUrl:String) -> UIImage? {
guard let bundleURL:URL? = URL(string: gifUrl)
else {
print("image named \"\(gifUrl)\" doesn't exist")
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL!) else {
print("image named \"\(gifUrl)\" into NSData")
return nil
}
return gifImageWithData(imageData)
}
public class func gifImageWithName(_ name: String) -> UIImage? {
guard let bundleURL = Bundle.main
.url(forResource: name, withExtension: "gif") else {
print("SwiftGif: This image named \"\(name)\" does not exist")
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL) else {
print("SwiftGif: Cannot turn image named \"\(name)\" into NSData")
return nil
}
return gifImageWithData(imageData)
}
class func delayForImageAtIndex(_ index: Int, source: CGImageSource!) -> Double {
var delay = 0.1
let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil)
let gifProperties: CFDictionary = unsafeBitCast(
CFDictionaryGetValue(cfProperties,
Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque()),
to: CFDictionary.self)
var delayObject: AnyObject = unsafeBitCast(
CFDictionaryGetValue(gifProperties,
Unmanaged.passUnretained(kCGImagePropertyGIFUnclampedDelayTime).toOpaque()),
to: AnyObject.self)
if delayObject.doubleValue == 0 {
delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties,
Unmanaged.passUnretained(kCGImagePropertyGIFDelayTime).toOpaque()), to: AnyObject.self)
}
delay = delayObject as! Double
if delay < 0.1 {
delay = 0.1
}
return delay
}
class func gcdForPair(_ a: Int?, _ b: Int?) -> Int {
var a = a
var b = b
if b == nil || a == nil {
if b != nil {
return b!
} else if a != nil {
return a!
} else {
return 0
}
}
if a < b {
let c = a
a = b
b = c
}
var rest: Int
while true {
rest = a! % b!
if rest == 0 {
return b!
} else {
a = b
b = rest
}
}
}
class func gcdForArray(_ array: Array<Int>) -> Int {
if array.isEmpty {
return 1
}
var gcd = array[0]
for val in array {
gcd = UIImage.gcdForPair(val, gcd)
}
return gcd
}
class func animatedImageWithSource(_ source: CGImageSource) -> UIImage? {
let count = CGImageSourceGetCount(source)
var images = [CGImage]()
var delays = [Int]()
for i in 0..<count {
if let image = CGImageSourceCreateImageAtIndex(source, i, nil) {
images.append(image)
}
let delaySeconds = UIImage.delayForImageAtIndex(Int(i),
source: source)
delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms
}
let duration: Int = {
var sum = 0
for val: Int in delays {
sum += val
}
return sum
}()
let gcd = gcdForArray(delays)
var frames = [UIImage]()
var frame: UIImage
var frameCount: Int
for i in 0..<count {
frame = UIImage(cgImage: images[Int(i)])
frameCount = Int(delays[Int(i)] / gcd)
for _ in 0..<frameCount {
frames.append(frame)
}
}
let animation = UIImage.animatedImage(with: frames,
duration: Double(duration) / 1000.0)
return animation
}
}
我使用过代码的地方。
//
// GifViewController.swift
// Get Fit
//
// Created by Sandeep Sahani on 08/12/22.
//
import UIKit
class GifViewController: UIViewController
{
@IBOutlet weak var gif: UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
let gifURL : String = "https://mir-s3-cdn-cf.behance.net/project_modules/max_1200/5eeea355389655.59822ff824b72.gif"
let imageURL = UIImage.gifImageWithURL(gifURL)
self.gif.image = imageURL
}
}
我怎样才能删除那个奇怪的警告并使该 gif 流畅?
答:
1赞
Nik
12/8/2022
#1
您正在使用的 API 调用是在主线程上执行的,因此系统会警告您。
我建议使用现代项目的默认选择库来加载名为 Kingfisher 的远程图像:https://github.com/onevcat/Kingfisher
有一个关于使用 Kingfisher lib 加载 gif 图像的 wiki 部分:
https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet#animated-gif
加载 GIF
let imageView: UIImageView = ...
imageView.kf.setImage(with: URL(string: "your_animated_gif_image_url")!)
或
let imageView = AnimatedImageView()
imageView.kf.setImage(with: URL(string: "your_large_animated_gif_image_url")!)
您必须将 Kingfisher 作为 Swift Package Manager 项目添加到您的项目中,然后添加到文件的顶部import Kingfisher
评论
0赞
Sandeep Sahani
12/8/2022
我可以用它来在自定义表格视图单元格中添加 gif(大约有 100 多个具有不同 url 的单元格)吗?我的应用会挂起还是会平稳运行?
0赞
Nik
12/8/2022
它肯定会顺利运行。但不要忘记 1) 重复使用单元格和 2) 当单元格离开屏幕时取消图像下载任务
0赞
HangarRash
12/9/2022
@SandeepSahani 请记住,没有必要使用此第三方库。它会起作用,但你不需要用它来实现你想要的。
评论
URLSession
URLSession