iOS设备中的图像存储,适当的行为?
Posted
技术标签:
【中文标题】iOS设备中的图像存储,适当的行为?【英文标题】:Image storage in iOS devices, the appropriate behavior? 【发布时间】:2011-10-07 15:17:52 【问题描述】:对于我正在制作的应用程序在 ios 设备中的图像存储,我有点困惑。
我的要求是将图像加载到 tableViewCell 上,假设在 UITableViewCell 的默认图像空间中,因此不是背景图像。
现在用户可以通过 PhotoDirectory 添加图像或拍摄全新的图像。
如果拍摄新图像,该图像应该优先存储在哪里?在默认照片目录中?还是在应用沙箱的文档文件夹中?
因为这些是图片文件,我担心在app bundle中存储图片会变得很大,恐怕我不想超过大小限制。
虽然性能方面...更好的选择是什么?
【问题讨论】:
越过什么限制?我能想到的对应用程序大小的唯一限制与从 App Store 交付您的应用程序有关。例如,超过一定大小的应用可以通过无线方式交付。 【参考方案1】:我有一个应用程序也可以执行您描述的一些操作。我的解决方案是创建一个我称之为 imageStore 的单例。您可以找到有关单身人士的信息here
在这个 imageStore 中,我存储了我所有的“全尺寸”图像;但是,像您一样,我担心这些图像的大小,因此我没有直接使用它们,而是使用缩略图。我要做的就是这个。对于我想在表中表示的每个对象,我确保该对象定义了一个 UIImage,该 UIImage 大约为缩略图大小(64x64 或您想要的任何大小)。然后创建一个对象,我创建一个与对象一起存储的缩略图。我使用此缩略图而不是较大的图像,以便我可以使用它,例如在表格单元格上。
我现在不在我的 Mac 后面,但如果你愿意,我可以稍后发布一些代码来演示单例以及缩略图的创建和使用。
这是我的 ImageStore 头文件
#import <Foundation/Foundation.h>
@interface BPImageStore : NSObject
NSMutableDictionary *dictionary;
+ (BPImageStore *)defaultImageStore;
- (void)setImage:(UIImage *)i forKey:(NSString *)s;
- (UIImage *)imageForKey:(NSString *)s;
- (void)deleteImageForKey:(NSString *)s;
@end
这是 ImageStore.m 文件 - 我的单例
#import "BPImageStore.h"
static BPImageStore *defaultImageStore = nil;
@implementation BPImageStore
+ (id)allocWithZone:(NSZone *)zone
return [[self defaultImageStore] retain];
+ (BPImageStore *)defaultImageStore
if(!defaultImageStore)
defaultImageStore = [[super allocWithZone:NULL] init];
return defaultImageStore;
- (id)init
if(defaultImageStore)
return defaultImageStore;
self = [super init];
if (self)
dictionary = [[NSMutableDictionary alloc] init];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(clearCach:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
return self;
- (void) clearCache:(NSNotification *)note
[dictionary removeAllObjects];
- (oneway void) release
// no op
- (id)retain
return self;
- (NSUInteger)retainCount
return NSUIntegerMax;
- (void)setImage:(UIImage *)i forKey:(NSString *)s
[dictionary setObject:i forKey:s];
// Create full path for image
NSString *imagePath = pathInDocumentDirectory(s);
// Turn image into JPEG data
NSData *d = UIImageJPEGRepresentation(i, 0.5);
// Write it to full path
[d writeToFile:imagePath atomically:YES];
- (UIImage *)imageForKey:(NSString *)s
// if possible, get it from the dictionary
UIImage *result = [dictionary objectForKey:s];
if(!result)
// Create UIImage object from file
result = [UIImage imageWithContentsOfFile:pathInDocumentDirectory(s)];
if (result)
[dictionary setObject:result forKey:s];
return result;
- (void)deleteImageForKey:(NSString *)s
if(!s)
return;
[dictionary removeObjectForKey:s];
NSString *path = pathInDocumentDirectory(s);
[[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
@end
这是我使用图像存储的地方。在我的对象“播放器”中,我有一个 UIImage 来存储缩略图,我有一个 NSString 来存放我创建的密钥。我放入商店的每个原始图像都有一个密钥。我将密钥存储在我的播放器中。如果我需要原始图像,我会通过唯一键获得。在这里还值得注意的是,我什至不以全尺寸存储原始图像,我已经将它剪掉了一点。毕竟在我的情况下,这是一张球员的照片,没有人能比得上一张全分辨率的照片:)
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
NSString *oldKey = [player imageKey];
// did the player already have an image?
if(oldKey)
// delete the old image
[[BPImageStore defaultImageStore] deleteImageForKey:oldKey];
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Create a CFUUID object it knows how to create unique identifier
CFUUIDRef newUniqueID = CFUUIDCreate(kCFAllocatorDefault);
// Create a string from unique identifier
CFStringRef newUniqueIDString = CFUUIDCreateString(kCFAllocatorDefault, newUniqueID);
// Use that unique ID to set our player imageKey
[player setImageKey:(NSString *)newUniqueIDString];
// we used Create in the functions to make objects, we need to release them
CFRelease(newUniqueIDString);
CFRelease(newUniqueID);
//Scale the images down a bit
UIImage *smallImage = [self scaleImage:image toSize:CGSizeMake(160.0,240.0)];
// Store image in the imageStore with this key
[[BPImageStore defaultImageStore] setImage:smallImage
forKey:[player imageKey]];
// Put that image onto the screen in our image view
[playerView setImage:smallImage];
[player setThumbnailDataFromImage:smallImage];
下面是一个从imageStore返回原图的例子:
// Go get image
NSString *imageKey = [player imageKey];
if (imageKey)
// Get image for image key from image store
UIImage *imageToDisplay = [[BPImageStore defaultImageStore] imageForKey:imageKey];
[playerView setImage:imageToDisplay];
else
[playerView setImage:nil];
最后,这是我从原始图像创建缩略图的方法:
- (void)setThumbnailDataFromImage:(UIImage *)image
CGSize origImageSize = [image size];
CGRect newRect;
newRect.origin = CGPointZero;
newRect.size = [[self class] thumbnailSize]; // just give a size you want here instead
// How do we scale the image
float ratio = MAX(newRect.size.width/origImageSize.width, newRect.size.height/origImageSize.height);
// Create a bitmap image context
UIGraphicsBeginImageContext(newRect.size);
// Round the corners
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:newRect cornerRadius:5.0];
[path addClip];
// Into what rectangle shall I composite the image
CGRect projectRect;
projectRect.size.width = ratio * origImageSize.width;
projectRect.size.height = ratio *origImageSize.height;
projectRect.origin.x = (newRect.size.width - projectRect.size.width) / 2.0;
projectRect.origin.y = (newRect.size.height - projectRect.size.height) / 2.0;
// Draw the image on it
[image drawInRect:projectRect];
// Get the image from the image context, retain it as our thumbnail
UIImage *small = UIGraphicsGetImageFromCurrentImageContext();
[self setThumbnail:small];
// Get the image as a PNG data
NSData *data = UIImagePNGRepresentation(small);
[self setThumbnailData:data];
// Cleanup image context resources
UIGraphicsEndImageContext();
【讨论】:
嘿,感谢您的回复,我从概念上得到了它!如果您发布的话,我真的可以使用一些代码。它与我想要的非常相似! 嘿,您的帮助对我的理解大有帮助。 我想再问一个问题,将缩略图图像存储在文档中并从那里加载是个好主意吗?考虑到可能会加载很多图像? 这个答案看起来像是直接来自 Big Nerd Ranch iOS 书籍。以上是关于iOS设备中的图像存储,适当的行为?的主要内容,如果未能解决你的问题,请参考以下文章
从设备和云存储服务上传和下载图像或文件(文档、PDF)到 iOS 应用程序
文本字段的动画不隐藏在键盘下方,在 IOS 7 中的模拟器和实际设备中的行为不同