Saving ALAsset URL in NSUserDefaults - iphone

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.

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

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.

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

Related

Storing custom OrderedDictionary to NSUserDefaults

I need to save the OrderedDictionary to NSUserDefaults.
I read here and in many other posts how to do it:
-(id)initWithCoder:(NSCoder *)decoder{
if (self != nil){
dictionary = [decoder decodeObjectForKey:#"dictionary"];
array = [decoder decodeObjectForKey:#"array"];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject: dictionary forKey:#"dictionary"];
[encoder encodeObject: array forKey:#"array"];
}
I then call it like this:
OrderedDictionary *od = [OrderedDictionary dictionaryWithDictionary:[businessInfo objectForKey:#"allowedStates"]];
NSData *archivedObject = [NSKeyedArchiver archivedDataWithRootObject:od];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:archivedObject forKey:#"allowedStates"];
[defaults synchronize];
and unarchive it like this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *archivedObject = [defaults objectForKey:#"allowedStates"];
OrderedDictionary *countryStates = (OrderedDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:archivedObject];
I see that archivedObject is not empty, however countryStates is empty, although when I save it it's not empty.
How is it?
How can I archive successfully the OrderedDictionary?
EDITED
The method initWithCoder is being called, but not encodeWithCoder
Please refer below link, may be will you get proper solution.
encodeWithCoder is not called in derived class of the NSMutableDictionary
When does encodeWithCoder get called?
Good Luck !!!!
Make sure your class conforms to the <NSCoding> protocoll (so your class definition reads #interface OrderedDictionary <NSCoding>)
Else, the framework doesn't know it should call encodeWithCoder:

Saving NSDictionary with NSMutableArray as a value to NSUserDefaults

I am storing UIImage in NSMutableArray then storing NSMutableArray into NSDictionary.
Key of NSDictionary is a foldername and value of NSDictionary is a NSMutableArray.
Now how can i store and retrieve NSDictionary in NSUserDefaults.
I have done as follows:
NSMutableArray *imageArray=[[NSMutableArray alloc] init];
[imageArray addObject:selectedImage];
[allFolderWithImageDict setValue:imageArray forKey:#"UniqueFolderName"];
NSUserDefaults *defauktCenter = [NSUserDefaults standardUserDefaults];
[defauktCenter setValue:allFolderWithImageDict forKey:#"FolderImageDict"];
[defauktCenter synchronize];
But NSDictionary is not saving in NSUserDefaults.
Please suggest with some example
thanks
To Store and Retrieve Values of Custom Objects, you can use NSKeyedArchiver and NSKeyedUnarchiver Classes :
// To Save. . .
NSData *resData = [NSKeyedArchiver archivedDataWithRootObject:allFolderWithImageDict];
[[NSUserDefaults standardUserDefaults] setObject:resData forKey:#"FolderImageDict"];
// To Load. . .
NSData *respData = [[NSUserDefaults standardUserDefaults] objectForKey:#"FolderImageDict"];
resultDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:respData];
NSLog(#"dict :: %#",resultDictionary);
GoodLuck !!!
To store UIImage objects in NSUserDefaults you need to a category implementation for UIImage that implements NSCoding protocol
here is one:
https://code.google.com/p/iphonebits/source/browse/trunk/src/Categories/UIImage-NSCoding.h
https://code.google.com/p/iphonebits/source/browse/trunk/src/Categories/UIImage-NSCoding.m
from
http://iphonedevelopment.blogspot.it/2009/03/uiimage-and-nscoding.html
Instead of using NSDictionary, use NSMutableDictionary.... :)
And to retrieve the data stored in dictionary.....
NSUserDefaults *d = [NSUserDefaults standardUserDefaults];
NSString *loadname1 = [d objectForKey:#"FolderImageDict"];
NSLog(#"%#", loadname1);

Unable to retrieve NSMutableArray from NSUserDefaults

I have an issue persisting data in local storage for an NSMutableArray containing a list of NSStrings.
I have a save method and a get method both appear to work when the app is running. However, once I close the app and restart the items in the array are gone.
NSMutableArray*ImageTags;
Get Data
-(NSMutableArray*)GetDataNSMutableArray:(NSString*)ItemName
{
NSMutableArray *GetData = [[NSMutableArray alloc] init];
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:ItemName];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
GetData = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
GetData = [[NSMutableArray alloc] init];
}
return GetData;
}
Save Data
-(void)SaveDataNSMutableArray:(NSString*)ItemName:(NSMutableArray*)Data
{
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:Data] forKey:ItemName];
}
How items are added
[ImageTags addObject:Control.titleLabel.text]
How array is saved
[super SaveDataNSMutableArray:CVC_ImageURL:ImageTags];
How array is retrieved
ImageTags = [super GetDataNSMutableArray:CVC_ImageURL];
NSUserDefaults always return immutable instances.
Unrelated:
(Conventions says that methodNames should always begin with a small letter).
[[NSUserDefaults standardUserDefaults] synchronize]
To dump all the contents from NSUserDefaults onto persistent store
Your can not store mutable array to user defaults. Store the immutable copy and retrieve that and convert to mutable ones to access during the next launch.
You can do synchronization while saving:
-(void)SaveDataNSMutableArray:(NSString*)ItemName:(NSMutableArray*)Data
{
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:Data] forKey:ItemName];
[[NSUserDefaults standardUserDefaults] synchronize] //add this code of a line.
}

How to save User Name and Password in NSUserDefault?

I need to save User Name and Password in NSUserDefault. I am planning to place a round rect button in IB. On pressing of which the User name and Password would be saved in NSUserDefault, so that when user kills the application and tries to login again after some time, they do not need to enter their login details again.
Any help would be highly appreciated.
Thanks and best regards,
PC
For Saving Username and Password I will personally suggest to use Keychain as they are more safer than NSUserDefault in terms of security since Keychain stores data in encrypted form while NSUserDefault stores as plain text. If you still want to use NSUserDefault Here's the way
FOR SAVING
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSString
[prefs setObject:txtUsername.text forKey:#"userName"];
[prefs setObject:txtPassword.text forKey:#"password"];
[prefs synchronize];
FOR RETRIEVING
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *savedUsername = [prefs stringForKey:#"userName"];
NSString *savedPassword = [prefs stringForKey:#"password"];
Do not store plaintext passwords in user defaults, even if they are unimportant.
Use Keychain Services. The Generic Keychain Sample provides sample KeychainWrapper class, that can be used for reading and writing data into keychain with exactly the same setObject:forKey: interface as NSUserDefaults uses.
To Save:
[[NSUserDefaults standardUserDefaults] setValue:_Username forKey:#"Username"];
[[NSUserDefaults standardUserDefaults] setValue:_password forKey:#"password"];
[[NSUserDefaults standardUserDefaults] synchronize];
To Read:
NSString * _UserName = [[NSUserDefaults standardUserDefaults] stringForKey:#"Username"];
NSString * _password = [[NSUserDefaults standardUserDefaults] stringForKey:#"password"];
First off, I would not store the password in NSUserDefaults. I would rather use the keychain.
This is how you can save the username in NSUserDefaults:
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
[standardUserDefaults setObject:myString forKey:#"username"];
NSString* username = [standardUserDefaults objectForKey:#"username"];
On the other hand, an easy way to use the keychain is by using the SSKeychain class by Sam Soffes; in this case you would just say:
NSString* password = [SSKeychain passwordForService:#"YOUSERVICENAMEHERE" account:username];
[SSKeychain setPassword:password forService:#"YOUSERVICENAMEHERE" account:username];
You can store your credentials like this:
-(void)saveToUserDefaults:(NSString*)stringUserName pswd:(NSString*)strPassword
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if (standardUserDefaults) {
[standardUserDefaults setObject:stringUserName forKey:#"UserName"];
[standardUserDefaults setObject:strPassword forKey:#"Password"];
[standardUserDefaults synchronize];
}
}
And you can retrive them like this:
-(NSArray*)retrieveFromUserDefaults
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if (standardUserDefaults) {
NSString *userName = (NSString*)[standardUserDefaults objectForKey:#"UserName"];
NSString *password = (NSString*)[standardUserDefaults objectForKey:#"Password"];
}
NSArray* credentials = [NSArray arrayWithObjects:userName, password, nil];
return credentials;
}
Cannot set NSUserDefaults field
Posted my code from link to stay assured that answer is still useful to community even if the above mentioned post is removed or deleted in future.
Code:
You can try this code. I am very sure that it will work for you.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *uid=#"1";
[defaults setObject:uid forKey:#"init_val"];
[defaults synchronize];
For Retrieving Data You Should Use The Following Code :
NSString *initVal=[[NSUserDefaults standardUserDefaults] valueForKey:#"init_val"];
OR
NSString *initVal=[[NSUserDefaults standardUserDefaults] objectForKey:#"init_val"];
EDIT:
If still it gives nil, then you can use the following code:
NSString *initVal=[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] valueForKey:#"init_val"]];
OR
NSString *initVal=[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"init_val"]];
In the above link, you will find my answer and replace "init_val" in my code there with your "username" and "password" as keys
Hope this helps you.
Good Answers are already given But here is a clean way of Saving/Loading/Deleting User Credentials in the keychain. Consider this, you can create a separate class and include the following code:
.h
#import <Foundation/Foundation.h>
#interface KeychainUserPass : NSObject
+ (void)save:(NSString *)service data:(id)data;
+ (id)load:(NSString *)service;
+ (void)delete:(NSString *)service;
#end
.m
#import "KeychainUserPass.h"
#implementation KeychainUserPass
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass,
service, (__bridge id)kSecAttrService,
service, (__bridge id)kSecAttrAccount,
(__bridge id)kSecAttrAccessibleAfterFirstUnlock, (__bridge id)kSecAttrAccessible,
nil];
}
+ (void)save:(NSString *)service data:(id)data {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}
+ (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
#try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
}
#catch (NSException *e) {
NSLog(#"Unarchive of %# failed: %#", service, e);
}
#finally {}
}
if (keyData) CFRelease(keyData);
return ret;
}
+ (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
}
#end

Best way to save to nsuserdefaults for custom class?

If I have a custom class Person which has three variables (which are propertized and synthesized):
NSString* theName;
float* theHeight;
int theAge;
Person instances are stored in an NSArray 'Group'. There is only one Group. What is the best way of storing and loading the Group in NSUserDefaults? (bearing in mind that float and int are not legal for NSUserDefaults)
#Brad Smith's answer is not complete, and even is incorrect in some sense. We have to use NSKeyedArchiver and NSKeyedUnarchiver as follows:
Make your class (for example in this case Person) to conform to protocol NSCoding and implement both the methods as:
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if(self) {
self.name = [decoder decodeObjectForKey:<key_for_property_name>];
// as height is a pointer
*self.height = [decoder decodeFloatForKey:<key_for_property_height>];
self.age = [decoder decodeIntForKey:<key_for_property_age>];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:<key_for_property_name>];
//as height is a pointer
[encoder encodeFloat:*self.height forKey:<key_for_property_height>]
[encoder encodeInt:self.age forKey:<key_for_property_age>];
}
Using NSUserDefaults
// Write to NSUserDefaults
NSData *archivedObject = [NSKeyedArchiver archivedDataWithRootObject:<your_class_object>];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:archivedObject forKey:<key_for_archived_object>];
[defaults synchronize];
// Read from NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *archivedObject = [defaults objectForKey:<key_for_archived_object>];
<your_class> *obj = (<your_class> *)[NSKeyedUnarchiver unarchiveObjectWithData:archivedObject];
I find implementing encodeWithCoder and initWithCoder quite boring, especially if you have many attributes in your class, and many classes to save to NSUserDefaults.
I create a library RMMapper (https://github.com/roomorama/RMMapper) to help save custom object into NSUserDefaults easier and more convenient.
To mark a class as archivable, just use: #import "NSObject+RMArchivable.h"
To save a custom object into NSUserDefaults:
#import "NSUserDefaults+RMSaveCustomObject.h"
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults rm_setCustomObject:user forKey:#"SAVED_DATA"];
To get custom obj from NSUserDefaults:
user = [defaults rm_customObjectForKey:#"SAVED_DATA"];