尝试将NSMutableArray
的对象存储到NSUserDefaults
,但没有运气。
我的NSMutableArray
包含此日志:
`ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=92A7A24F-D54B-496E-B250-542BBE37BE8C&ext=JPG`
我知道它是一个ALAsset object
,在AGImagePickerController
中它被比作NSDictionary,所以我需要做的是将NSDictionary或我用过的数组保存到我存储{{1}的地方然后将其保存在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");
}
第四次尝试(由于在appbundle中进行了修改,因此不确定): https://stackoverflow.com/a/6311129/1302274
还有其他方法吗?希望有人能指导我。
答案 0 :(得分:2)
您可以将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"]];
此外,您可以将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
答案 1 :(得分:1)
NSArray的“writeToFile:atomically:”方法文档显示所有成员必须是属性列表对象。 ALAsset不是属性列表对象,因此将其写入文件不起作用。
我知道它是一个ALAsset对象,它在AGImagePickerController中 与NSDictionary相比
如果仔细观察,那么你会发现它不会比较ALAsset,而是它们的'ALAssetPropertyURLs'属性。该属性的值是NSDictionary。
由于ALAsset没有公共构造函数,因此无法在从文件或NSUserDefaults读取后重新构建它,即使您设法编写它也是如此。
因此,您可以做的最好的事情是从您最初获取它们的源中重新获取ALAssets。我假设这是一个ALAssetsGroup?而不是保存到文件并再次检索,为什么不用最初用于生成它们的ALAssetsGroup上的相同查询重新生成它们?
修改强>:
所以你说你从AGImagePickerController获得了原始的ALAsset。为了存储它们,您可以在评论中提供Matej的建议并存储标识它们的URL。
但请记住,AGImagePickerController是用户选择一些照片然后 用它们做某事 的一种方法。也就是说,ALAssets只是指向照片原始位置的中间结果。如果您存储URL并稍后检索它们,则无法保证原件仍在那里。
请问自己:您希望用户对照片做什么,并存储该操作的结果,而不是资产本身。例如,您可以执行的一个合理操作是创建一个新的ALAssetGroup(在ALAssetsLibrary上使用addAssetsGroupAlbumWithName:方法),并将资产存储在那里。 ALAssetGroups会自动保存,因此您无需为此自行执行任何操作。
编辑2 - 来自OP的更多信息
Matej在评论中暗示的是,通过从资产中检索网址,将您拥有的ALAsset数组转换为字典数组。正如您可以在ALAsset class documentation中阅读的那样,您可以通过以下方式进行阅读:
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建议使用ALAssetsLibrary的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
}
}
这假设原始资产没有变化,这不在您的控制范围内(例如,用户已删除/添加了照片)。
答案 2 :(得分:0)
这是我用来存储数组或字典对象的方法。
- (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];
}