我正在制作一个应用程序,它在一个UImageView中显示gif,从Parse加载gif。我遇到的问题是,每当我加载一个Gif时,它都会使用大约20 mb的内存,而当我执行segue时,这个内存没有被分配。我从UImageView中删除了图像本身,但它仍然没有释放内存。
这是我用来显示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
}
}
这可能是我记忆问题的原因吗?感谢任何帮助!
我决定添加完整的代码来节省内存,如果您使用的是GIF文件,修改UIImage scale方法(在这里找到了它,一个Stackoverflow)。正如SD图像中所说的GangstaGraham存在方法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
引用脚本的内容: /* “显示组件占用大小”与“在组件页面增加按钮”例子 by Ansifa 编译需要: NSIS建议最新版,ButtonEvent插件,还有修改过的UI.EXE(见附件) */ !AddPluginDir . XPStyle on OutFile "显示组件占用大小.EXE" Name "显示组件占用大小" !include "WordFunc.nsh" !include 'M
问题内容: 我是所有内存管理主题的新手,所以有很多我不了解的事情。 我正在尝试将图像缓存在我的应用程序中,但是我在内存消耗方面遇到了麻烦: 所有的Bitmap Chaching代码都可以从此处复制粘贴:http : //developer.android.com/training/displaying- bitmaps/index.html 我调试了代码,并在Eclipse的DDMS视图中检查了堆
Java1.8。0_131 Windows Server 2012 R2。 “-Xmx=9000m”。但是Windows任务管理器显示java进程使用的内存超过14GB。 NMT显示“内部”消耗超过4.5 GB的内存。为什么会出现这种情况?我知道为本机内存定义空间不是Java功能。但是有什么方法可以限制“内部”内存吗? 总计:保留=15782485KB,提交=14653869KB-Java堆(保留
问题内容: 我正在尝试创建一个文件下载程序作为后台服务,但是当计划了一个大文件时,首先将其放入内存中,然后在下载结束时将文件写入磁盘。 考虑到我可能同时下载许多文件,如何使文件逐渐写入磁盘保留内存? 这是我使用的代码: 问题答案: 我将回调更改为: 这工作得很好。
本文向大家介绍rsync备份海量文件时占用大量内存的解决方法,包括了rsync备份海量文件时占用大量内存的解决方法的使用技巧和注意事项,需要的朋友参考一下 linux发行版中大多都自带rsync,不过版本比较低,一般都是2.6.X 在2.X的版本中,rsync备份时都是先列表再备份(添加或者删除),在处理大量文件时,会耗费比较多的内存。 备份的时候,rsync扫描到的每个文件(目录也一样),在它的
问题内容: 我有一小段代码每隔五分钟拍摄一次我的桌面的屏幕截图。但是,我对它占用的内存量有些困惑-通常它会爬升到200mb RAM,我敢肯定这是多余的…谁能告诉我a)减少内存占用空间的明智方法或b)它为什么涨 可言 ? 问题答案: 其他答案是正确的:Java将使用允许的尽可能多的内存,这时它将进行垃圾回收。要解决此问题,可以在JVM设置中指定较小的最大堆大小。您可以使用- Xmx设置来执行此操作。