Сохранение в NSDocumentDirectory или NSCachesDirectory

Попробовали хранить объект NSUserDefaults для NSUserDefaults но не повезло. Мой NSMutableArray содержит этот журнал прямо здесь:

 `ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=92A7A24F-D54B-496E-B250-542BBE37BE8C&ext=JPG` 

Я знаю, что его ALAsset object , в AGImagePickerController он сравнивается как NSDictionary, поэтому мне нужно было сохранить NSDictionary или массив, в котором я использовал, где я ALAsset object затем сохраняю его в NSDocu или NSCaches как файл, а затем вернуть его (это была моя идея).

Но проблема в том, что я пробовал этот код, но не работал, и ничего не показываю в NSDocu или NSCache .

Первая попытка ( info – это та, которая содержит ALAsset object ):

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; NSString *filePath = [basePath stringByAppendingPathComponent:@"filename.plist"]; NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfURL:filePath]; NSString *error; NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error]; if(plistData) { [info writeToFile:filePath atomically:YES]; } else { NSLog(error); } 

Вторая попытка :

 - (NSString *)createEditableCopyOfFileIfNeeded:(NSString *)_filename { // First, test for existence. BOOL success; NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *writableFilePath = [documentsDirectory stringByAppendingPathComponent: _filename ]; success = [fileManager fileExistsAtPath:writableFilePath]; if (success) return writableFilePath; // The writable file does not exist, so copy the default to the appropriate location. NSString *defaultFilePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: _filename ]; success = [fileManager copyItemAtPath:defaultFilePath toPath:writableFilePath error:&error]; if (!success) { NSLog([error localizedDescription]); NSAssert1(0, @"Failed to create writable file with message '%@'.", [error localizedDescription]); } return writableFilePath; } 

Сохраните это так:

  NSString *writableFilePath = [self createEditableCopyOfFileIfNeeded:[NSString stringWithString:@"hiscores"]]; if (![info writeToFile:writableFilePath atomically:YES]){ NSLog(@"WRITE ERROR"); } 

Третья попытка :

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *filePath = [documentsDirectory stringByAppendingPathComponent:??????]; [info writeToFile:filePath atomically:YES]; 

Четвертая попытка (Невозможно из-за ее модификации в приложении): https://stackoverflow.com/a/6311129/1302274

Есть ли другой способ? Надеюсь, кто-то будет вести меня.

Вы можете сохранить свой NSMutableArray в NSUserDefault, заархивировав его в NSData, а затем извлекая его, отправив его обратно в NSMutableArray.

 -(NSData*) getArchievedDataFromArray:(NSMutableArray*)arr { NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr]; return data; } -(NSMutableArray*) getArrayFromArchievedData:(NSData*)data { NSMutableArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data]; return arr; } 

Для сохранения массива в NSUserDefault:

  [[NSUserDefaults standardUserDefaults] setObject:[self getArchievedDataFromArray: yourArray] forKey:@"YourKey"]; [[NSUserDefaults standardUserDefaults] synchronize]; 

Для получения массива из NSUserDefault:

 NSMutableArray *yourArray = [self getArrayFromArchievedData:[[NSUserDefaults standardUserDefaults]objectForKey:@"YourKey"]]; 

Также вы можете сохранить Array в виде NSData в файл в NSDocumentDirectory или NSCachesDirectory. Надеюсь это поможет….

Отредактировано: категория UIImage + NSCoding

файл .h

 #import <UIKit/UIKit.h> @interface UIImage (NSCoding) - (id) initWithCoderForArchiver:(NSCoder *)decoder; - (void) encodeWithCoderForArchiver:(NSCoder *)encoder ; @end 

.m файл

 #import "UIImage+NSCoding.h" #import <objc/runtime.h> #define kEncodingKey @"UIImage" @implementation UIImage (NSCoding) + (void) load { @autoreleasepool { if (![UIImage conformsToProtocol:@protocol(NSCoding)]) { Class class = [UIImage class]; if (!class_addMethod( class, @selector(initWithCoder:), class_getMethodImplementation(class, @selector(initWithCoderForArchiver:)), protocol_getMethodDescription(@protocol(NSCoding), @selector(initWithCoder:), YES, YES).types )) { NSLog(@"Critical Error - [UIImage initWithCoder:] not defined."); } if (!class_addMethod( class, @selector(encodeWithCoder:), class_getMethodImplementation(class, @selector(encodeWithCoderForArchiver:)), protocol_getMethodDescription(@protocol(NSCoding), @selector(encodeWithCoder:), YES, YES).types )) { NSLog(@"Critical Error - [UIImage encodeWithCoder:] not defined."); } } } } - (id) initWithCoderForArchiver:(NSCoder *)decoder { if (self = [super init]) { NSData *data = [decoder decodeObjectForKey:kEncodingKey]; self = [self initWithData:data]; } return self; } - (void) encodeWithCoderForArchiver:(NSCoder *)encoder { NSData *data = UIImagePNGRepresentation(self); [encoder encodeObject:data forKey:kEncodingKey]; } @end 

Документация NSArray для метода writeToFile: atomically: показывает, что все члены должны быть объектами списка свойств. ALAsset не является объектом списка свойств, поэтому запись этого файла не будет работать.

Я знаю, что его объект ALAsset, в AGImagePickerController сравнивается как NSDictionary

Если бы вы внимательно посмотрели, вы бы увидели, что он не сравнивает ALAsset, а их свойство «ALAssetPropertyURLs». Значение этого свойства является NSDictionary.

Поскольку у ALAsset нет публичного конструктора, вы не можете его восстановить после чтения из файла или NSUserDefaults, даже если вам удастся его написать.

Поэтому самое лучшее, что вы можете сделать, это повторно извлечь ALAssets из источника, из которого вы изначально их получили. Я предполагаю, что это ALAssetsGroup? Вместо сохранения в файл и повторного поиска, почему бы вам просто не восстановить их с тем же запросом в ALAssetsGroup, как вы изначально использовали для их создания?

EDIT :

Итак, вы говорите, что у вас есть оригинальный ALAset от AGImagePickerController. Чтобы сохранить их, вы можете взять рекомендации Matej в комментариях и сохранить URL-адреса, которые их идентифицируют.

Но имейте в виду, что AGImagePickerController – это средство для пользователя, чтобы выбрать несколько фотографий, а затем сделать что-то с ними . То есть, ALAssets – это просто промежуточные результаты, указывающие на исходные местоположения фотографий. Если вы сохраните URL-адрес и получите их позже, нет никакой гарантии, что оригиналы все еще существуют.

Поэтому спросите себя: что вы хотите, чтобы пользователь делал с фотографиями, и сохраните результат этого действия, а не сами активы. Например, одно разумное действие, которое вы можете сделать, – создать новую ALAssetGroup (с помощью метода addAssetsGroupAlbumWithName: ALAssetsLibrary) и сохранить там активы. ALAssetGroups автоматически сохраняются, поэтому вам не нужно ничего делать самостоятельно.

EDIT 2 – после получения дополнительной информации от OP

То, что Matej намекает в комментариях, состоит в том, чтобы преобразовать массив ALAssets, который у вас есть, в массив словарей, извлекая URL-адреса из активов. Как вы можете прочитать в документации класса ALAsset, вы можете сделать это следующим образом:

 NSArray *assetArray = // your array of ALAssets NSMutableArray *urls = [NSMutableArray arrayWithCapacity:assetArray.count]; for( ALAsset *asset in assetArray ) { NSDictionary *urlDictionary = [asset valueForProperty:@"ALAssetPropertyURLs"]; [urls addObject:urlDictionary]; } 

Результирующий массив словарей, которые вы можете сохранить любым способом.

После перезапуска вашего приложения вы читаете массив словарей назад, откуда вы его сохранили. Затем Matej предлагает использовать активную базу данных assetForURL:resultBlock:failureBlock: воссоздать ALAssets. Но, как мы теперь знаем, вы хотите снова поставить галочку на исходные активы, лучше получить исходный массив ALAssets и проверить, присутствует ли какой-либо из них в восстановленных URL-адресах. Для этого должны работать следующие:

 NSArray *assetArray = // the full array of ALAssets from AGImagePickerController NSArray *urls = // the recovered array of NSDictionaries for( ALAsset *asset in assetArray ) { NSDictionary *urlDictionary = [asset valueForProperty:@"ALAssetPropertyURLs"]; if( [urls containsObject:urlDictionary] ) { ... // set checkmark on asset } } 

Это предполагает, что первоначальные активы не изменились, что не под вашим контролем (например, пользователь удалил / добавил фотографии).

Это метод, который я использую для хранения объектов массива или словаря.

 - (NSArray*)readPlist { NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:@"filename.plist"]; NSFileManager *fMgr = [NSFileManager defaultManager]; if (![fMgr fileExistsAtPath:plistPath]) { [self writePlist:[NSArray array]]; } return [NSArray arrayWithContentsOfFile:plistPath]; } - (void)writePlist:(NSArray*)arr { NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:@"filename.plist"]; NSFileManager *fMgr = [NSFileManager defaultManager]; if ([fMgr fileExistsAtPath:plistPath]) [fMgr removeItemAtPath:plistPath error:nil]; [arr writeToFile:plistPath atomically:YES]; } 
Давайте будем гением компьютера.