3

NSMutableArrayのオブジェクトをに保存しようとしましNSUserDefaultsたが、運がありません。私NSMutableArrayはここにこのログを含んでいます:

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

私はそれがNSDictionaryとして比較されることを知っているALAsset objectのでAGImagePickerController、私がする必要があるのは、私が保存した場所に使用したNSDictionaryまたは配列をALAsset object保存し、それをファイルに保存するかNSDocuNSCachesファイルとして保存してから再度取得することです(これは私の考えでした)。

しかし、問題は、このコードを試しましたが機能せず、ディレクトリに何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);

}

2回目の試行

- (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");
    } 

3回目の試行

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

[info writeToFile:filePath atomically:YES];

4回目の試行(Appbundleで変更されているため不明): https ://stackoverflow.com/a/6311129/1302274

他の方法はありますか?誰かが私を導いてくれることを願っています。

4

3 に答える 3

2

NSMutableArray を NSData にアーカイブすることで NSUserDefault に格納し、アーカイブ解除して 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
于 2012-10-18T10:02:07.457 に答える
1

「writeToFile:atomically:」メソッドの NSArray のドキュメントは、すべてのメンバーがプロパティ リスト オブジェクトでなければならないことを示しています。ALAsset はプロパティ リスト オブジェクトではないため、ファイルへの書き込みは機能しません。

私はそれがALAssetオブジェクトであることを知っています.AGImagePickerControllerではNSDictionaryとして比較されます

注意深く見ると、ALAsset の比較ではなく、「ALAssetPropertyURLs」プロパティの比較であることがわかります。そのプロパティの値は NSDictionary です。

ALAsset にはパブリック コンストラクターがないため、ファイルまたは NSUserDefaults から読み取った後に再構築する方法はありません。

そのため、ALAsset を最初に取得したソースから再度取得することをお勧めします。ALAssetsGroup だと思いますか? ファイルに保存して再度取得する代わりに、ALAssetsGroup で最初に生成に使用したのと同じクエリを使用して再生成してみませんか?

編集

つまり、元の ALAsset を AGImagePickerController から取得したと言えます。それらを保存するには、コメントで Matej のアドバイスを参考にして、それらを識別する URL を保存します。

ただし、AGImagePickerController は、ユーザーが多数の写真を選択し、それらに対して何かを行うための手段であることを覚えておいてください。つまり、ALAssets は、写真の元の場所を指す単なる中間結果です。URL を保存して後で取得する場合、元の URL がまだそこにあるという保証はまったくありません。

ユーザーに写真で何をしてもらいたいのか、そしてアセットそのものではなく、そのアクションの結果を保存してもらいたいのかを自問してください。たとえば、新しい ALAssetGroup を (ALAssetsLibrary の addAssetsGroupAlbumWithName: メソッドを使用して) 作成し、そこにアセットを保存することが合理的なアクションの 1 つです。ALAssetGroup は自動的に保存されるため、自分で何もする必要はありません。

EDIT 2 - OPからの詳細情報の後

コメントで Matej が示唆しているのは、アセットから URL を取得することにより、持っている ALAsset の配列を辞書の配列に変換することです。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 は 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
    }
}

これは、元のアセットが変更されておらず、管理下にないことを前提としています (ユーザーが写真を削除/追加したなど)。

于 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 に答える