app*_*tal 20 memory-leaks imagenamed ios7 xcasset
根据Apple文档,建议在iOS7应用程序中使用xcassets,并通过imageNamed引用这些图像.
但据我所知,imageNamed和内存总是存在问题.
所以我做了一个简短的测试应用程序 - 使用imageNamed从xcassets目录中引用图像并启动了分析器...结果如预期的那样.一旦分配的内存没有再次释放,即使我从superview中删除了ImageView并将其设置为nil.
我目前正在开发一个带有许多大图像的iPad应用程序,这种奇怪的imageView行为会导致内存警告.
但在我的测试中,我无法通过imageWithContentsOfFile访问xcassets图像.
那么在iOS7上使用大图像的最佳方法是什么?有没有办法以另一种(更高性能)的方式从xcassets目录访问图像?或者我不应该使用xcassets,以便我可以使用imageWithContentsOfFile?
谢谢您的回答!
the*_*guy 15
更新:缓存逐出罚款(至少从iOS 8.3开始).
我决定使用Apple的"新Images.xcassets".事情开始变得糟糕,当我在应用程序中有大约350mb的图像和应用程序不断崩溃(在Retina iPad上;可能是因为加载图像的大小).
我写了一个非常简单的测试应用程序,我在其中加载三种不同类型的图像(观看分析器):
imageNamed: 从资产加载:图像永远不会被释放,应用程序崩溃(对我来说,我可以加载400张图片,但这实际上取决于图像大小)
imageNamed:(传统上包括在项目中):内存使用率很高,偶尔(> 400张图片)我看到一个调用didReceiveMemoryWarning:,但应用程序运行正常.
imageWithContentsOfFile([[NSBundle mainBundle] pathForResource:...):内存使用率非常低(<20mb),因为图像一次只加载一次.
我真的不会责怪imageNamed:所有方法的缓存,因为缓存是一个好主意,如果你不得不一次又一次地显示你的图像,但苹果没有为资产实现它(或没有记录它)有点令人遗憾它没有实现).在我的用例中,我会选择非缓存,imageWithData因为用户不会再看到图像.
由于我的应用程序几乎是最终的,我真的喜欢使用加载机制来自动找到正确的图像,我决定包装用法:
脚本:
cd projectFolderWithImageAsset
echo "{\"assets\": [" > a.json
find Images.xcassets/ -name \*.json | while read jsonfile; do
tmppath=${jsonfile%.imageset/*}
assetname=${tmppath##*/}
echo "{\"assetname\":\"${assetname}\",\"content\":" >> a.json
cat $jsonfile >> a.json;
echo '},' >>a.json
done
echo ']}' >>a.json
Run Code Online (Sandbox Code Playgroud)
(所有设备和后备机制的实现都不完整!!)
#import "UIImage+Extension.h"
#import <objc/objc-runtime.h>
#import "IMGADataModels.h"
@implementation UIImage (UIImage_Extension)
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
Method imageNamed = class_getClassMethod(class, @selector(imageNamed:));
Method imageNamedCustom = class_getClassMethod(class, @selector(imageNamedCustom:));
method_exchangeImplementations(imageNamed, imageNamedCustom);
});
}
+ (IMGABaseClass*)model {
static NSString * const jsonFile = @"a";
static IMGABaseClass *baseClass = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *fileFilePath = [[NSBundle mainBundle] pathForResource:jsonFile ofType:@"json"];
NSData* myData = [NSData dataWithContentsOfFile:fileFilePath];
__autoreleasing NSError* error = nil;
id result = [NSJSONSerialization JSONObjectWithData:myData
options:kNilOptions error:&error];
if (error != nil) {
ErrorLog(@"Could not load file %@. The App will be totally broken!!!", jsonFile);
} else {
baseClass = [[IMGABaseClass alloc] initWithDictionary:result];
}
});
return baseClass;
}
+ (UIImage *)imageNamedCustom:(NSString *)name{
NSString *imageFileName = nil;
IMGAContent *imgContent = nil;
CGFloat scale = 2;
for (IMGAAssets *asset in [[self model] assets]) {
if ([name isEqualToString: [asset assetname]]) {
imgContent = [asset content];
break;
}
}
if (!imgContent) {
ErrorLog(@"No image named %@ found", name);
}
if (is4InchScreen) {
for (IMGAImages *image in [imgContent images]) {
if ([@"retina4" isEqualToString:[image subtype]]) {
imageFileName = [image filename];
break;
}
}
} else {
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ) {
for (IMGAImages *image in [imgContent images]) {
if ([@"iphone" isEqualToString:[image idiom]] && ![@"retina4" isEqualToString:[image subtype]]) {
imageFileName = [image filename];
break;
}
}
} else {
if (isRetinaScreen) {
for (IMGAImages *image in [imgContent images]) {
if ([@"universal" isEqualToString:[image idiom]] && [@"2x" isEqualToString:[image scale]]) {
imageFileName = [image filename];
break;
}
}
} else {
for (IMGAImages *image in [imgContent images]) {
if ([@"universal" isEqualToString:[image idiom]] && [@"1x" isEqualToString:[image scale]]) {
imageFileName = [image filename];
if (nil == imageFileName) {
// fallback to 2x version for iPad unretina
for (IMGAImages *image in [imgContent images]) {
if ([@"universal" isEqualToString:[image idiom]] && [@"2x" isEqualToString:[image scale]]) {
imageFileName = [image filename];
break;
}
}
} else {
scale = 1;
break;
}
}
}
}
}
}
if (!imageFileName) {
ErrorLog(@"No image file name found for named image %@", name);
}
NSString *imageName = [[NSBundle mainBundle] pathForResource:imageFileName ofType:@""];
NSData *imgData = [NSData dataWithContentsOfFile:imageName];
if (!imgData) {
ErrorLog(@"No image file found for named image %@", name);
}
UIImage *image = [UIImage imageWithData:imgData scale:scale];
DebugVerboseLog(@"%@", imageFileName);
return image;
}
@end
Run Code Online (Sandbox Code Playgroud)