Iphone 保存在NSDocumentDirectory或NSCachesDirectory中

Iphone 保存在NSDocumentDirectory或NSCachesDirectory中,iphone,objective-c,ios,Iphone,Objective C,Ios,已尝试将我的NSMutableArray对象存储到NSUserDefaults中,但没有成功。 我的NSMutableArray在此处包含此日志: `ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=92A7A24F-D54B-496E-B250-542BBE37BE8C&ext=JPG` 我知道它是一个ALAsset对象,在AGImagePickerController中,它被比较为NSDictionary,

已尝试将我的
NSMutableArray
对象存储到
NSUserDefaults
中,但没有成功。 我的
NSMutableArray
在此处包含此日志:

`ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=92A7A24F-D54B-496E-B250-542BBE37BE8C&ext=JPG`
我知道它是一个
ALAsset对象
,在
AGImagePickerController
中,它被比较为NSDictionary,因此我需要做的是保存NSDictionary或我用来存储
ALAsset对象的数组
,然后将其保存在
NSDocu
NSCaches
中作为文件,然后再次检索它(这是我的主意)

但问题是,尽管我尝试了这段代码,但没有工作,并且在
NSDocu
NSCache
目录中没有显示任何内容

第一次尝试
info
是包含
ALAsset对象
)的:

第二次尝试

- (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;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:??????];

[info writeToFile:filePath atomically:YES];
这样保存它:

    NSString *writableFilePath = [self createEditableCopyOfFileIfNeeded:[NSString stringWithString:@"hiscores"]];   
    if (![info writeToFile:writableFilePath atomically:YES]){
        NSLog(@"WRITE 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;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:??????];

[info writeToFile:filePath atomically:YES];
第四次尝试(不确定,因为它在appbundle中被修改):


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

您可以通过将NSMutableArray存档到NSData将其存储到NSSERDEFAULT,而不是通过将其解压缩回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];
NSMutableArray *yourArray = [self getArrayFromArchievedData:[[NSUserDefaults standardUserDefaults]objectForKey:@"YourKey"]];  
要从NSUserDefault检索回阵列,请执行以下操作:

  [[NSUserDefaults standardUserDefaults] setObject:[self getArchievedDataFromArray: yourArray] forKey:@"YourKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSMutableArray *yourArray = [self getArrayFromArchievedData:[[NSUserDefaults standardUserDefaults]objectForKey:@"YourKey"]];  
您还可以将数组以NSData的形式保存到NSDocumentDirectory或NSCachesDirectory中的文件中。希望这对您有所帮助

已编辑:UIImage+N编码类别

.h文件

#import <UIKit/UIKit.h>

@interface UIImage (NSCoding)
- (id) initWithCoderForArchiver:(NSCoder *)decoder;
- (void) encodeWithCoderForArchiver:(NSCoder *)encoder ;
@end
#导入
@接口UIImage(NSCoding)
-(id)initWithCoderForArchiver:(NSCoder*)解码器;
-(void)encodeWithCoderForArchiver:(NSCoder*)编码器;
@结束
.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
#导入“UIImage+NSCoding.h”
#进口
#定义kEncodingKey@“UIImage”
@实现UIImage(NSCoding)
+(空)荷载
{
@自动释放池{
如果(![UIImage conformsToProtocol:@协议(NSCoding)]){
Class Class=[UIImage Class];
if(!class_addMethod)(
类,
@选择器(initWithCoder:),
类_getMethodImplementation(类,@selector(initWithCoderForArchiver:),
协议_getMethodDescription(@protocol(NSCoding),@selector(initWithCoder:),YES,YES)。类型
)) {
NSLog(@“严重错误-[UIImage initWithCoder:]未定义”);
}
if(!class_addMethod)(
类,
@选择器(编码器和编码器:),
类_getMethodImplementation(类,@selector(encodeWithCoderForArchiver:),
协议\u getMethodDescription(@protocol(NSCoding),@selector(encodeWithCoder:),YES,YES)。类型
)) {
NSLog(@“严重错误-[UIImage EncoderWithCoder:]未定义”);
}
} 
}
}
-(id)initWithCoderForArchiver:(NSCoder*)解码器{
if(self=[super init]){
NSData*data=[decoder decodeObjectForKey:kEncodingKey];
self=[self initWithData:data];
}
回归自我;
}
-(void)encodeWithCoderForArchiver:(NSCoder*)编码器{
NSData*data=UIIMAGEPNGRE表示(自我);
[编码器编码对象:数据分叉:kEncodingKey];
}
@结束

这是我用来存储数组或字典对象的方法

- (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]; 
}

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

我知道它是一个ALAsset对象,在AGImagePickerController中它是 与词典相比

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

由于ALAsset没有公共构造函数,因此在读取文件或nsUserDefault后无法重建它,即使您成功地编写了它

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

编辑

- (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;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:??????];

[info writeToFile:filePath atomically:YES];
所以你说你从AGImagePickerController那里得到了原始的ALAsset。为了存储它们,你可以在评论中接受Matej的建议并存储识别它们的URL

但请记住,AGImagePickerController是一种让用户挑选大量照片,然后对其进行处理的方法。也就是说,这些照片集只是指向照片原始位置的中间结果。如果您存储URL并在以后检索它们,则根本无法保证原始照片他们仍然在那里

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

编辑2-在OP提供更多信息之后

Matej在注释中暗示的是,通过从资产中检索URL,将您拥有的集合数组转换为字典数组。正如您在中所读到的,您可以通过以下方式进行转换:

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建议使用ALAsse