3

已尝试将我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 或我用来存储我的数组,ALAsset object然后将其保存在文件中NSDocuNSCaches文件中,然后再次检索它(这是我的主意)。

但问题是,虽然我尝试了这段代码但没有工作,也没有在NSDocuNSCache目录中显示任何内容。

第一次尝试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];

第四次尝试(不确定,因为它在 appbundle 中进行了修改): https ://stackoverflow.com/a/6311129/1302274

还有其他方法吗?希望有人指导我。

4

3 回答 3

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 形式的 Array 保存到 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
于 2012-10-18T10:02:07.457 回答
1

“writeToFile:atomically:”方法的 NSArray 文档显示所有成员都必须是属性列表对象。ALAsset 不是属性列表对象,因此将其写入文件是行不通的。

我知道它是一个 ALAsset 对象,在 AGImagePickerController 中它被比较为 NSDictionary

如果您仔细查看,您会发现它不比较 ALAsset,而是比较它们的“ALAssetPropertyURLs”属性。该属性的值是一个 NSDictionary。

由于 ALAsset 没有公共构造函数,因此即使您设法编写它,也无法在从文件或 NSUserDefaults 读取后重建它。

因此,您可以做的最好的事情是从您最初获得它们的源重新获取 ALAsset。我假设这是一个 ALAssetsGroup?与其保存到文件并再次检索,不如直接在 ALAssetsGroup 上使用与最初生成它们时相同的查询重新生成它们?

编辑

所以你说你从 AGImagePickerController 得到了原始的 ALAsset。为了存储它们,您可以在评论中采纳 Matej 的建议并存储识别它们的 URL。

但请记住,AGImagePickerController 是一种让用户选择一些照片然后对它们进行操作的方法。也就是说,ALAsset 只是指向照片原始位置的中间结果。如果您存储 URL 并稍后检索它们,则根本无法保证原件仍然存在。

所以问问自己:您希望用户对照片做什么,并存储该操作的结果,而不是资产本身。例如,您可以执行的一项合理操作是创建一个新的 ALAssetGroup(使用 ALAssetsLibrary 上的 addAssetsGroupAlbumWithName: 方法),并将资产存储在其中。ALAssetGroups 会自动保存,因此您无需为此做任何事情。

编辑 2 - 从 OP 获得更多信息后

Matej 在评论中暗示的是,通过从资产中检索 url,将您拥有的 ALAssets 数组转换为字典数组。正如您可以在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 建议使用 ALAssetsLibraryassetForURL:resultBlock:failureBlock:重新创建 ALAssets。但是我们现在知道您想再次在原始资产上打勾,最好获取原始 ALAsset 数组,并检查它们中的任何一个是否存在于恢复的 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
    }
}

这假设原始资产没有更改,这不受您的控制(例如,用户已删除/添加照片)。

于 2012-11-06T20:53:17.837 回答
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]; 
}
于 2012-11-01T10:47:19.420 回答