2016-02-29 446 views
0

我正在製作一個應用程序,它在UIImageView中顯示gif,並從parse中加載gif。我偶然發現的問題是每當我加載一個Gif時,它會使用大約20 MB的內存,並且當我執行一個segue時,這個內存不會被分配。我從UIImageView中刪除圖像本身,但它仍然不釋放內存。顯示gif時出現巨大的內存使用Swift iOS

這是我用來顯示GIF代碼:

extension UIImage { 

public class func gifWithData(data: NSData) -> UIImage? { 
    guard let source = CGImageSourceCreateWithData(data, nil) else { 
     print("SwiftGif: Source for the image does not exist") 
     return nil 
    } 
    return UIImage.animatedImageWithSource(source) 
} 

public class func gifWithName(name: String) -> UIImage? { 
    guard let bundleURL = NSBundle.mainBundle().URLForResource(name, withExtension: "gif") else { 
     print("SwiftGif: This image named \"\(name)\" does not exist") 
     return nil 
    } 
    guard let imageData = NSData(contentsOfURL: bundleURL) else { 
     print("SwiftGif: Cannot turn image named \"\(name)\" into NSData") 
     return nil 
    } 
    return gifWithData(imageData) 
} 

class func delayForImageAtIndex(index: Int, source: CGImageSource!) -> Double { 
    var delay = 0.1 

    // Get dictionaries 
    let cfProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil) 
    let gifProperties: CFDictionaryRef = unsafeBitCast(
     CFDictionaryGetValue(cfProperties, 
      unsafeAddressOf(kCGImagePropertyGIFDictionary)), 
     CFDictionary.self) 

    // Get delay time 
    var delayObject: AnyObject = unsafeBitCast(
     CFDictionaryGetValue(gifProperties, 
      unsafeAddressOf(kCGImagePropertyGIFUnclampedDelayTime)), 
     AnyObject.self) 
    if delayObject.doubleValue == 0 { 
     delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties, 
      unsafeAddressOf(kCGImagePropertyGIFDelayTime)), AnyObject.self) 
    } 

    delay = delayObject as! Double 

    if delay < 0.1 { 
     delay = 0.1 // Make sure they're not too fast 
    } 

    return delay 
} 

class func gcdForPair(var a: Int?, var _ b: Int?) -> Int { 
    // Check if one of them is nil 
    if b == nil || a == nil { 
     if b != nil { 
      return b! 
     } else if a != nil { 
      return a! 
     } else { 
      return 0 
     } 
    } 

    // Swap for modulo 
    if a < b { 
     let c = a 
     a = b 
     b = c 
    } 

    // Get greatest common divisor 
    var rest: Int 
    while true { 
     rest = a! % b! 

     if rest == 0 { 
      return b! // Found it 
     } 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 = [CGImageRef]() 
    var delays = [Int]() 

    // Fill arrays 
    for i in 0..<count { 
     // Add image 
     if let image = CGImageSourceCreateImageAtIndex(source, i, nil) { 
      images.append(image) 
     } 

     // At it's delay in cs 
     let delaySeconds = UIImage.delayForImageAtIndex(Int(i), 
      source: source) 
     delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms 
    } 

    // Calculate full duration 
    let duration: Int = { 
     var sum = 0 

     for val: Int in delays { 
      sum += val 
     } 

     return sum 
     }() 

    // Get frames 
    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) 
     } 
    } 

    // Heyhey 
    let animation = UIImage.animatedImageWithImages(frames, 
     duration: Double(duration)/1000.0) 

    return animation 
} 

class func FinalFrame(source: CGImageSource) -> UIImage? { 
    let count = CGImageSourceGetCount(source) 
    var images = [CGImageRef]() 
    var delays = [Int]() 
    var finalFrame = UIImage() 

    // Fill arrays 
    for i in 0..<count { 
     // Add image 
     if let image = CGImageSourceCreateImageAtIndex(source, i, nil) { 
      images.append(image) 
     } 

     // At it's delay in cs 
     let delaySeconds = UIImage.delayForImageAtIndex(Int(i), 
      source: source) 
     delays.append(Int(delaySeconds * 1000.0)) // Seconds to ms 
    } 

    // Get frames 
    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) 
     } 
    } 
    finalFrame = frames[frames.count-1] 

    return finalFrame 
} 
} 

難道這是原因,我得到的內存問題? 感謝任何幫助!

+0

兩者GIF和APNG可以以低存儲器請求數,像這樣進行處理:http://stackoverflow.com/a/25478854/763355 – MoDJ

回答

0

我決定添加完整的代碼來保存內存,如果你使用的是GIF文件,請修改UIImage scale方法(在這裏找到它,一個Stackoverflow)。作爲所述GangstaGraham在SD圖像中存在的方法sd_animatedImageByScalingAndCroppingToSize

@interface UIImage (Scaling) 

-(UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize; 
-(UIImage*) croppedImageWithRect: (CGRect) rect; 

@end 

@implementation UIImage (Scaling) 

- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize { 

    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { 
     if ([[UIScreen mainScreen] scale] == 2.0) { 
      targetSize.height *= 2.0f; 
      targetSize.width *= 2.0f; 
     } 
    } 

    NSUInteger width = targetSize.width; 
    NSUInteger height = targetSize.height; 
    UIImage *newImage = [self resizedImageWithMinimumSize: CGSizeMake (width, height)]; 
    return [newImage croppedImageWithRect: CGRectMake ((newImage.size.width - width)/2, (newImage.size.height - height)/2, width, height)]; 
} 

-(CGImageRef)CGImageWithCorrectOrientation 
{ 
    if (self.imageOrientation == UIImageOrientationDown) { 
     //retaining because caller expects to own the reference 
     CGImageRetain([self CGImage]); 
     return [self CGImage]; 
    } 

    UIGraphicsBeginImageContext(self.size); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    if (self.imageOrientation == UIImageOrientationRight) { 
     CGContextRotateCTM (context, 90 * M_PI/180); 
    } else if (self.imageOrientation == UIImageOrientationLeft) { 
     CGContextRotateCTM (context, -90 * M_PI/180); 
    } else if (self.imageOrientation == UIImageOrientationUp) { 
     CGContextRotateCTM (context, 180 * M_PI/180); 
    } 

    [self drawAtPoint:CGPointMake(0, 0)]; 

    CGImageRef cgImage = CGBitmapContextCreateImage(context); 
    UIGraphicsEndImageContext(); 

    return cgImage; 
} 

-(UIImage*)resizedImageWithMinimumSize:(CGSize)size 
{ 
    CGImageRef imgRef = [self CGImageWithCorrectOrientation]; 
    CGFloat original_width = CGImageGetWidth(imgRef); 
    CGFloat original_height = CGImageGetHeight(imgRef); 
    CGFloat width_ratio = size.width/original_width; 
    CGFloat height_ratio = size.height/original_height; 
    CGFloat scale_ratio = width_ratio > height_ratio ? width_ratio : height_ratio; 
    CGImageRelease(imgRef); 
    return [self drawImageInBounds: CGRectMake(0, 0, round(original_width * scale_ratio), round(original_height * scale_ratio))]; 
} 

-(UIImage*)drawImageInBounds:(CGRect)bounds 
{ 
    UIGraphicsBeginImageContext(bounds.size); 
    [self drawInRect: bounds]; 
    UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return resizedImage; 
} 

-(UIImage*)croppedImageWithRect:(CGRect)rect 
{ 

    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, self.size.width, self.size.height); 
    CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height)); 
    [self drawInRect:drawRect]; 
    UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return subImage; 
} 

-(UIImage *) resizableImageWithCapInsets2: (UIEdgeInsets) inset 
{ 
    if ([self respondsToSelector:@selector(resizableImageWithCapInsets:resizingMode:)]) 
    { 
     return [self resizableImageWithCapInsets:inset resizingMode:UIImageResizingModeStretch]; 
    } 
    else 
    { 
     float left = (self.size.width-2)/2;//The middle points rarely vary anyway 
     float top = (self.size.height-2)/2; 
     return [self stretchableImageWithLeftCapWidth:left topCapHeight:top]; 
    } 
} 

@end 

和的UIImageView:

#import <SDWebImage/SDImageCache.h> 

@implementation UIImageView (Scaling) 

-(void)setImageWithURL:(NSURL*)url scaleToSize:(BOOL)scale 
{ 
    if(url.absoluteString.length < 10) return; 
    if(!scale){ 
     [self setImageWithURL:url]; 
     return; 
    } 
    __block UIImageView* selfimg = self; 
    __block NSString* prevKey = SPRINTF(@"%@_%ix%i", url.absoluteString, (int)self.frame.size.width, (int)self.frame.size.height); 
    __block UIImage* prevImage = nil; 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    dispatch_async(queue,^{ 

     prevImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:prevKey]; 
     if(prevImage){ 
      dispatch_async(dispatch_get_main_queue(),^{ 
       [self setImage:prevImage]; 
      }); 
     }else{ 

      [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:url options:SDWebImageDownloaderFILOQueueMode progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { 
       if(error){ 
        [selfimg setImageWithURL:url scaleToSize:scale]; 
       }else{ 
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
        dispatch_async(queue,^{ 
         prevImage = [image imageByScalingProportionallyToSize:self.frame.size]; 
         if(finished) 
          [[SDImageCache sharedImageCache] storeImage:prevImage forKey:prevKey]; 
         dispatch_async(dispatch_get_main_queue(),^{ 
          [self setImage:prevImage]; 
         }); 
        }); 
       } 
      }]; 
     } 
    }); 

    return; 
} 

-(void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder scaleToSize:(BOOL)scale 
{ 
    [self setImage:placeholder]; 
    [self setImageWithURL:url scaleToSize:scale]; 
} 


@end