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 设备中保存从 Web 下载的图像的最佳位置?

文本字段的动画不隐藏在键盘下方,在 IOS 7 中的模拟器和实际设备中的行为不同

解析 ios 的图像分辨率

如何使用 Objective-C 从 IOS Cordova 中的设备(本地数据库)中删除图像

iOS 上 MFi 认证蓝牙设备的确认行为