根据苹果文档,建议在iOS7应用程序中使用xcassets,并通过imageNamed引用这些图像。
但据我所知,imageNamed和内存总是存在问题。
所以我做了一个简短的测试应用程序 - 用imageNamed从xcassets目录中引用图像并启动了profiler ......结果如预期的那样。一旦分配的内存没有再次释放,即使我从superview中删除了ImageView并将其设置为nil。
我目前正在使用包含许多大图像的iPad应用程序,这种奇怪的imageView行为会导致内存警告。
但在我的测试中,我无法通过imageWithContentsOfFile访问xcassets图像。
那么在iOS7上使用大图像的最佳方法是什么?有没有办法以另一种(更高性能)的方式从xcassets目录访问图像?或者根本不应该使用xcassets以便我可以使用imageWithContentsOfFile?
感谢您的回答!
答案 0 :(得分:15)
更新:缓存逐出罚款(至少从iOS 8.3开始)。
我决定选择"新的Images.xcassets"来自Apple也是。事情开始变得糟糕,当我在应用程序中有大约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
(所有设备和回退机制的实现都没有完成!!)
#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