#iphone #ios #uitableview #uiimage
#iPhone #iOS #uitableview #uiimage
Вопрос:
Я немного озадачен хранением изображений на устройствах iOS для приложения, которое я создаю.
Мое требование — загрузить изображение в tableViewCell, скажем, в пространстве изображений по умолчанию UITableViewCell и, следовательно, не является фоновым изображением.
Теперь пользователь может либо добавить изображение через PhotoDirectory, либо создать совершенно новое изображение.
Если берется новое изображение, где предпочтительнее хранить это изображение? В каталоге фотографий по умолчанию? или в папке «Документы» песочницы приложений?
Поскольку это файлы изображений, я боюсь, что хранение изображений в пакете приложений может сделать его довольно большим, боюсь, я не хочу превышать ограничение по размеру.
Однако с точки зрения производительности… что было бы лучшим вариантом?
Комментарии:
1. Пересечь какой предел? Единственное ограничение на размер приложения, о котором я могу думать, касается доставки вашего приложения из App Store. Приложения определенного размера могут доставляться, например, по воздуху.
Ответ №1:
У меня есть приложение, которое также выполняет некоторые из описанных вами действий. Мои решения заключались в создании синглтона, который я называю my imageStore. Вы можете найти информацию о синглтоне здесь
В этом хранилище изображений я храню все свои изображения «в натуральную величину»; однако, как и вы, меня беспокоит размер этих изображений, поэтому вместо того, чтобы использовать их напрямую, я использую эскизы. Что я делаю, так это. Для каждого объекта, который я хочу представить в таблице, я удостоверяюсь, что объект имеет определенный UIImage размером примерно с палец (64×64 или любой желаемый размер). Затем создается объект, я создаю эскиз, который я сохраняю вместе с объектом. Я использую этот эскиз вместо больших изображений, где я могу с ним справиться, например, в ячейке таблицы.
В данный момент я не за своим Mac, но, если вы хотите, я могу позже опубликовать некоторый код, чтобы продемонстрировать как синглтон, так и создание и использование эскиза.
Вот мой заголовочный файл для хранилища изображений
#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 resu<
}
- (void)deleteImageForKey:(NSString *)s {
if(!s) {
return;
}
[dictionary removeObjectForKey:s];
NSString *path = pathInDocumentDirectory(s);
[[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
}
@end
Здесь я использую хранилище изображений. В моем объекте «player» у меня есть 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];
}
Вот пример возврата к исходному изображению из хранилища изображений:
// 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();
}
Комментарии:
1. Привет, спасибо за ответ, я понял его концептуально!, Я действительно мог бы использовать некоторый код, если бы вы опубликовали. Это очень похоже на то, что я хочу!
2. Эй, ваша помощь прошла долгий путь в моем понимании.
3. Я хотел бы задать еще один вопрос: хорошая ли идея сохранять миниатюры изображений в документах и загружать их оттуда? учитывая, что может быть загружено много изображений?
4. Этот ответ выглядит прямо из книги Big Nerd Ranch iOS.