Ios 在UIImageView中加载gif图像时减少内存消耗
我想在UIImageView中显示gif图像,使用下面的代码(源代码:,*我不理解所有代码),我可以显示gif图像。然而,内存消耗似乎很高(在实际设备上测试)。有没有办法修改下面的代码以减少内存消耗Ios 在UIImageView中加载gif图像时减少内存消耗,ios,swift,memory,uiimageview,gif,Ios,Swift,Memory,Uiimageview,Gif,我想在UIImageView中显示gif图像,使用下面的代码(源代码:,*我不理解所有代码),我可以显示gif图像。然而,内存消耗似乎很高(在实际设备上测试)。有没有办法修改下面的代码以减少内存消耗 @IBOutlet weak var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() let url = "https://cdn-images-1.medium.com/max/
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let url = "https://cdn-images-1.medium.com/max/800/1*oDqXedYUMyhWzN48pUjHyw.gif"
let gifImage = UIImage.gifImageWithURL(url)
imageView.image = gifImage
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
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 {
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL!) else {
return nil
}
return gifImageWithData(imageData)
}
public class func gifImageWithName(_ name: String) -> UIImage? {
guard let bundleURL = Bundle.main
.url(forResource: name, withExtension: "gif") else {
return nil
}
guard let imageData = try? Data(contentsOf: bundleURL) else {
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
}
}
@ibvar-imageView:UIImageView!
重写func viewDidLoad(){
super.viewDidLoad()
让url=”https://cdn-images-1.medium.com/max/800/1*oDqXedYUMyhWzN48pUjHyw.gif“
让gifImage=UIImage.gifImageWithURL(url)
imageView.image=gifImage
}
重写函数didReceiveMemoryWarning(){
超级。我收到了记忆警告()
//处置所有可以重新创建的资源。
}
fileprivate func<(左:T?、右:T?->Bool{
开关(左、右){
小木箱(l?,r?):
返回lUIImage{
guard let source=CGImageSourceCreateWithData(数据为CFData,无)else{
打印(“图像不存在”)
归零
}
返回UIImage.animatedImageWithSource(源)
}
公共类func gifImageWithURL(gifull:String)->UIImage{
guard let bundleURL:URL?=URL(字符串:gifUrl)else{
归零
}
guard let imageData=try?Data(内容:bundleURL!)其他{
归零
}
返回gifImageWithData(图像数据)
}
公共类func-gifImageWithName(u-name:String)->UIImage{
guard let bundleURL=Bundle.main
.url(forResource:name,扩展名为:“gif”)else{
归零
}
guard let imageData=try?数据(内容:bundleURL)else{
归零
}
返回gifImageWithData(图像数据)
}
类func delayForImageAtIndex(uIndex:Int,source:cImageSource!)->Double{
var延迟=0.1
让cfProperties=CGImageSourceCopyPropertiesAtIndex(源,索引,无)
让属性:CFDictionary=unsafeBitCast(
CFDictionaryGetValue(cfProperties,
Unmanaged.passUnretained(kCGImagePropertyGIFDictionary.toOpaque()),
收件人:CFDictionary.self)
var delayObject:AnyObject=unsafeBitCast(
CFDictionaryGetValue(gifProperties,
未托管.passUnrepeated(KCGimagePropertyGifUnampledDelayTime).toOpaque()),
收件人:AnyObject.self)
如果delayObject.doubleValue==0{
delayObject=unsafeBitCast(CFDictionaryGetValue)(GIF属性,
Unmanaged.passUnrepaired(kCGImagePropertyGIFDelayTime.toOpaque()),收件人:AnyObject.self)
}
延迟=延迟对象为!双精度
如果延迟<0.1{
延迟=0.1
}
返回延迟
}
类函数gcdForPair(uA:Int?,b:Int?)->Int{
变量a=a
变量b=b
如果b==nil | | a==nil{
如果b!=nil{
返回b!
}否则,如果a!=零{
还一个!
}否则{
返回0
}
}
如果aInt{
如果array.isEmpty{
返回1
}
var gcd=数组[0]
对于数组中的val{
gcd=UIImage.gcdForPair(val,gcd)
}
返回gcd
}
类func animateImageWithSource(uSource:CGImageSource)->UIImage{
let count=CGImageSourceGetCount(源)
var images=[CGImage]()
变量延迟=[Int]()
对于0..中的i,所讨论的GIF分辨率为480×288,包含10帧
考虑到UIImageView
将帧存储为4字节RGBA,此GIF在RAM中占用4×10×480×288=5 529 600字节,超过5 MB
有许多方法可以减轻这种压力,但其中只有一种方法不会给CPU带来额外的压力;其他方法只是CPU与RAM之间的权衡
我所说的方法是将UIImageView
子类化,并手动加载GIF,保留其内部表示(索引图像+调色板)。这样可以将内存使用量减少四倍
注意:尽管GIF可以存储为每一帧的完整图像(这是GIF的情况),但很多都不是。相反,大多数帧只能包含自上一帧以来已更改的像素。因此,通常内部GIF表示只允许按直接顺序显示帧
保存RAM的其他方法包括:在显示前从磁盘上重新读取每一帧,这肯定不利于电池寿命。要以较少的内存消耗显示GIF,请尝试
BBWebImage将根据当前内存使用情况决定解码和缓存多少图像帧。如果可用内存不足,则仅解码和缓存部分图像帧
对于Swift 4:
//BBAnimatedImageView(UIImageView子类)显示动画图像
imageView=BBAnimatedImageView(帧:帧)
//加载和显示gif
imageView.bb_setImage(带:url,
占位符:UIImage(名为:“占位符”))
{(图像:UIImage?,数据:data?,错误:error?,缓存类型:BBImageCacheType)在中
//完成装载后做些什么
}
当您评论gif时,它使用了多少内存code@sanjaykmwt我现在已经在真实设备中进行了测试,并在t中更新了这两种情况下的消耗量