-->

Saving ALAsset URL in NSUserDefaults

2020-07-18 03:50发布

问题:

Hi I have my ALAsset URL save in NSMutableArray,

"ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=119A0D2D-C267-4B69-A200-59890B2B0FE5&ex‌​t=JPG", 
"ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=92A7A24F-D54B-496E-B250-542BBE37BE8C&ex‌​t=JPG", 
"ALAsset - Type:Photo, URLs:assets-library://asset/asset.JPG?id=77AC7205-68E6-4062-B80C-FC288DF96F24&ex‌​t=JPG

I wasnt able to save NSMutableArray in NSUserDefaults due to it having an error Note that dictionaries and arrays in property lists must also contain only property values. Im thinking of using this :

            - (void)encodeWithCoder:(NSCoder *)encoder {
                //Encode properties, other class variables, etc
                [encoder encodeObject:self.selectedPhotos forKey:@"selectedPhotos"];
            }

            - (id)initWithCoder:(NSCoder *)decoder {
                if((self = [super init])) {
                    //decode properties, other class vars
                    self.selectedPhotos = [decoder decodeObjectForKey:@"selectedPhotos"];
                }
                return self;
            }

then save and retrieve it with this code:

            - (void)saveCustomObject:(MyCustomObject *)obj {
                NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:obj];
                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                [defaults setObject:myEncodedObject forKey:@"myEncodedObjectKey"];
            }

            - (MyCustomObject *)loadCustomObjectWithKey:(NSString *)key {
                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                NSData *myEncodedObject = [defaults objectForKey:key];
                MyCustomObject *obj = (MyCustomObject *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
                return obj;
            }

But I somehow dont quite get it, still crashes in my code. Dont know how. And I wasnt able to save it in NSUserDefaults. Hope someone help. Really been having problem with this a while. Hope someone guide me on the right path of saving and retrieving it the right way from NSUserDefaults. Then back to a NSMutableArray.

回答1:

The NSUserDefaults only takes a restricted set of classes as objects. See the documentation. You must take care only to store values of these types (NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary, and of course it applies recursively) in the dictionary.

To store the URLs in the NSUserDefaults, store them as strings, then read them back as URLs. If you need to have the dictionary in the current format, you may have to transform it before saving it.

- (void) saveMyUrls
{
    NSMutableArray* urls = [NSMutableArray arrayWithCapacity:self.myUrls.count];
    for(NSURL* url in self.myUrls) {
        [urls addObject:[url absoluteString]];
    }
    [[NSUserDefaults standardUserDefaults] setObject:urls forKey:@"myUrls"];
}


- (void) loadUrls
{
    NSArray* urls = [[NSUserDefaults standardUserDefaults] objectForKey:@"myUrls"];
    self.myUrls = [NSMutableArray arrayWithCapacity:urls.count];
    for(NSString* urlString in urls) {
        [self.myUrls addObject:[NSURL URLWithString:urlString]];
    }
    [[NSUserDefaults standardUserDefaults] setObject:urls forKey:@"myUrls"];
}

If you need to save more information than just the URL, let's say a user-specified label, you could save the object as a NSDictionary instead, e.g.

- (void) saveMyUrlsWithLabels
{
    NSMutableArray* objs = [NSMutableArray arrayWithCapacity:self.myObjects.count];
    for(MyObject* obj in self.myObjects) {
        [objs addObject:[NSDictionary dictionaryWithKeys:@"url", @"label"
            forObjects:obj.url.absoluteString, obj.userSpecifiedLabel];
    }
    [[NSUserDefaults standardUserDefaults] setObject:objs forKey:@"myObjects"];
}


回答2:

Maybe you should do it like this:

- (MyCustomObject *)loadCustomObjectWithKey:(NSString *)key {

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults synchronize]; // note this
    NSData *myEncodedObject = [defaults objectForKey:key];
    MyCustomObject *obj = nil;

    // it would be even better
    // to wrap this into @try-@catch block
    if(myEncodedObject)
    {
        obj = (MyCustomObject *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
    }

    return obj;
}

Also note that if you want to use NSKeyedArchiver and NSKeyedUNarchiver your MyCustomObject class has to conform to NSCoding protocol. Check NSCoding protocol reference and Archives and Serializations Programming Guide.



回答3:

This is another way to do it and yes you can use NSUserDefaults. Basically you get asset URL, save it and then convert it back to an asset / image

//SET IT
ALAsset *asset3 = [self.assets objectAtIndex:[indexPath row]];
    NSMutableString *testStr = [NSMutableString stringWithFormat:@"%@", asset3.defaultRepresentation.url];

    //NSLog(@"testStr: %@ ...", testStr);

    [[NSUserDefaults standardUserDefaults] setObject:testStr forKey:@"userPhotoAsset"];
    [[NSUserDefaults standardUserDefaults] synchronize];


//GET IT 
NSString *assetUrlStr = [[NSUserDefaults standardUserDefaults] objectForKey:@"userPhotoAsset"];
    NSURL* aURL = [NSURL URLWithString:assetUrlStr];
    NSLog(@"aURL: %@ ...", aURL);

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library assetForURL:aURL resultBlock:^(ALAsset *asset)
     {
         UIImage  *copyOfOriginalImage = [UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage] scale:1.0 orientation:UIImageOrientationUp];

         imgVwPortrait.image = copyOfOriginalImage;

     }
            failureBlock:^(NSError *error)
     {
         // error handling
         NSLog(@"failure-----");
     }];


标签: iphone ios xcode