4

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.

Bazinga
  • 2,456
  • 33
  • 76
  • 1
    Has it to be in `NSUserDefaults` or is the point just saving and retrieving? – DAS Oct 16 '12 at 11:24
  • 1
    Just saving and able to retrieve even when app exits and restart. Like nsuserdefault – Bazinga Oct 16 '12 at 13:30
  • 1
    Sorry about the bounty removal; there was mod flag that this was a dupe (but I saw the other one was closed as a dupe of this), and I thought I had to close this one, but was mistaken (and started to remove the bounty). Feel free to add the bounty back on. – casperOne Oct 17 '12 at 17:51

3 Answers3

3

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"];
}
Krumelur
  • 31,081
  • 7
  • 77
  • 119
  • 1
    You could convert each `NSURL` to a string using `[someURL absoluteString]`. – Krumelur Oct 16 '12 at 13:20
  • 1
    can this be used? `ALAssetRepresentation *rep = [[info objectAtIndex: i] defaultRepresentation]; UIImage *image = [self scaleThenRotateImage:[UIImage imageWithCGImage:[rep fullResolutionImage]]];` – Bazinga Oct 16 '12 at 13:59
  • 1
    Sorry, you lost me there. You get the URL from the asset using `[representation url]`, or `[[asset defaultRepresentation] url]`. But I am not sure how it relates to your example. You are not storing the `UIImage` itself in the user defaults, I hope? :) – Krumelur Oct 16 '12 at 15:50
  • 1
    Sorry my bad, the image is for my nsdocu. But the url above is what is in my array. Can that be converted to string then be retrieved then? – Bazinga Oct 16 '12 at 15:53
  • 1
    I was able to save the url, but what I need is to save the whole property like the above – Bazinga Oct 17 '12 at 06:27
  • 1
    let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18162/discussion-between-superman-and-krumelur) – Bazinga Oct 17 '12 at 10:17
1

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.

MANIAK_dobrii
  • 6,014
  • 3
  • 28
  • 55
1

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-----");
     }];
Sam B
  • 27,273
  • 15
  • 84
  • 121