IOS: NSUserDefault for an array of UIImage - ios

I want to store an array of UIImage and I do this:
//in didFinishLaunchingWithOption
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:#"theKey"];
if (data == NULL) arrayImage = [[NSMutableArray alloc] init];
else {arrayImage = [[NSMutableArray alloc] init]; arrayImage = [NSKeyedUnarchiver unarchiveObjectWithData:data];}
NSLog(#"arrayImage:%#", arrayImage);
//and in applicationDidEnterBackground
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arrayImage];
[defaults setObject:data forKey:#"theKey"];
NSLog(#"arrayImage:%#", arrayImage);
when app run in didFinishLaunchingWithOption in nslog I see all object in my array, but when I use it, I have a crash that say "[__NSArrayM count]: message sent to deallocated instance" why?

I'm not completely sure, but I think that
+(id)unarchiveObjectWithData:(NSData *)data
gives you an autoreleased object, so you may retain it. And I think it will give you a non-mutable object, so when you will try to add or remove objects from it you will get an error (I'm no sure about this, but I think I once was in this situation...)
I would rewrite some part of your code:
...
if (data == nil)
{
arrayImage = [[NSMutableArray alloc] init];
} else
{
//arrayImage = [[NSMutableArray alloc] init]; //why to allocate and initialize if you are goind to unarchive it?
//arrayImage = [[NSKeyedUnarchiver unarchiveObjectWithData:data] retain]; //note the retain here
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data]; //the unarchive won't mantain mutability (I guess).
arrayImage = [NSMutableArray arrayWithArray:arr]; //create a mutable copy
}
...

I assume you're not using ARC. The problem is in:
if (data == NULL)
arrayImage = [[NSMutableArray alloc] init];
else {
arrayImage = [[NSMutableArray alloc] init];
// HERE
arrayImage = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
At HERE, you replace the value in arrayImage with a new instance for the keyed unarchiver. The value you init'd just previously is lost (in fact, leaked). The value from the unarchiver is an autoreleased object, so will be released when the pool is drained. This is before the applicationDidEnterBackground call is made.
The correct solution is to retain the value from the unarchiver. Viz:
if (data == nil)
arrayImage = [[NSMutableArray alloc] init];
else
arrayImage = [[NSKeyedUnarchiver unarchiveObjectWithData:data] retain];

Related

userDefaults and comparing arrays

I got problem with saving and comparing data. First I download data and save my data (array,dict)to userDefaults. After redownloading I need to compare if my new array have some new data which I haven't saved in userDefaults. So its mean I should find the data that is not the same inside my old data and add them to my new array.
NSMutableDictionary* tmpDict = [NSMutableDictionary new];
NSMutableDictionary* copyDict = [NSMutableDictionary new];
NSMutableArray *dataGroupsArr = [NSMutableArray new];
NSMutableDictionary *dataGroupsDict = [NSMutableDictionary new];
dataGroupsDict[#"name"] = #"FirstGroup"; // I dont need groups at the moment
NSMutableArray *datas = [[NSMutableArray alloc]init];
FOR ........ (parser)
{
NSMutableDictionary *data = [[NSMutableDictionary alloc]init];
data[#"dataID"] = [#"some data from parser"];
[datas addObject:data];
}];
dataGroupsDict[#"datas"] = datas;
[dataGroupsArr addObject:dataGroupsDict];
tmpDict[#"dataGroups"] = dataGroupsArr;
After I save data Im trying to load them from userdefualts
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
copyDict = [userDefaults objectForKey:#"dataDownloadArr"];
//data never added
if(copyDict == nil){
[userDefaults setObject:tmpDict forKey:#"dataDownloadArr"];
[userDefaults synchronize];
} else {
for (int i = 0; i< [copyDict[#"dataGroups"][0][#"datas"]count]; i++){
NSLog(#"%#", copyDict[#"dataGroups"][0][#"datas"][i][#"dataID"]);
}
}
Now I don't know how to compare data, and if there is new data in my new array how to add it to old one.
Did you try to use NSData instance method isEqualToData?
Two data objects are equal if they hold the same number of bytes, and
if the bytes at the same position in the objects are the same.
https://developer.apple.com/documentation/foundation/nsdata/1409330-isequaltodata
I was also facing same issue what I did is I asked the backend developer to send a value as modified_date and create a dictionary containing dataArray and modified_date. So after re-downloading you can just check for modified_date and replace the dataArray instead of comparing every array element.

Add multiple objects under key in NSMutableDictionary

What I am trying to achieve is the following, store one value (keyword) under the key (account) in one dictionary and then store that dictionary under another dictionary with the key (list) and finally that dictionary under another dictionary under the key (allKeys).
- (void)addFilterForAccount:(NSString *)account forKeyword:(NSString *)keyword inList:(NSString *)list {
//Set properties for NSStrings
account = _accountName;
keyword = _textField2.text;
list = _listName;
//Clear the textField
_textField2.text = #"";
//Store this information into a dictionary/array
_keys = [[NSMutableDictionary alloc] init];
[_keys setObject:keyword forKey:account];
_keywords = [[NSMutableDictionary alloc] init];
[_keywords setObject:_keys forKey:list];
_filters = [[NSMutableDictionary alloc] init];
[_filters setValue:_keywords forKey:#"allKeys"];
//nomenclature would be:
//
//_filters[#"allKeys"][#"//listName\\"][#"//accountName\\"]
NSLog(#"%#", _filters);
}
I have the following code that should do what I want, but the problem at this time is that it doesn't allow for multiple keys. So if I want to store multiple keywords under one list, when I log out it should be like this:
2014-09-07 18:31:12.562 Filterfeed[4050:124143] {
allKeys = {
"Breaking News" = (
{
BreakingNews = romney
obama
bush
clinton;
}
);
};
}
But right now it is just one name, and it gets replaced each time I invoke this method.
What actually prints out:
2014-09-07 18:31:12.562 Filterfeed[4050:124143] {
allKeys = {
"Breaking News" = (
{
BreakingNews = romney;
}
);
};
}
You want this method to be:
- (void)addFilterForAccount:(NSString *)account forKeyword:(NSString *)keyword inList:(NSString *)list {
//Set properties for NSStrings
account = _accountName;
keyword = _textField2.text;
list = _listName;
//Clear the textField
_textField2.text = #"";
//Store this information into a dictionary/array
_keys = [[NSMutableDictionary alloc] init];
NSMutableArray *array = [NSUserDefualts standardUserDefaults] objectForKey: list];
[array addObject: keyword];
[[NSUserDefualts standardUserDefaults] setObject: array forKey: list];
[[NSUserDefualts standardUserDefaults] synchronize];
NSMutableArray *array2 = [NSUserDefualts standardUserDefaults] objectForKey: list];
[_keys setObject:array2 forKey:account];
_keywords = [[NSMutableDictionary alloc] init];
[_keywords setObject:_keys forKey:list];
_filters = [[NSMutableDictionary alloc] init];
[_filters setValue:_keywords forKey:#"allKeys"];
//nomenclature would be:
//
//_filters[#"allKeys"][#"//listName\\"][#"//accountName\\"]
NSLog(#"%#", _filters);
}

Why would my NSMutableDictionary be nil?

I am trying to store an array in a NSMutableDictionary. However the NSMutableDictionary is null after i have set objects to it. Here is my code any help is appreciated:
NSMutableArray *arrTemp = [[NSMutableArray alloc] init];
NSMutableDictionary *dTemp = [[NSMutableDictionary alloc] init];
STStockData *stockData = [[STStockData alloc] init];
for (int i = 0; i < [_arrTickers count]; i++) {
// get the ticker from its json form
dTemp = [_arrTickers objectAtIndex:i];
NSLog(#"Ticker: %#",[dTemp objectForKey:#"ticker"]);
// gets current data for ticker
[arrTemp addObjectsFromArray:[stockData getCurrentStockDataForTicker:[dTemp objectForKey:#"ticker"]]];
NSLog(#"Price %#",[arrTemp objectAtIndex:1]); // just to prove the array isnt nil.
// adds it to the dictionary
[_dStockData setObject:arrTemp forKey:[dTemp objectForKey:#"ticker"]];
NSLog(#"Dictionary %#",_dStockData);
// remove all objects so can reuse.
[arrTemp removeAllObjects];
dTemp = nil; // can't remove objects using [removeAllObjects] method. believe its due to it holding inside NSArrays which are immutable.
}
Here is the console output:
Initialize _dStockData
_dStockData = [[NSMutableDictionary alloc] init];
It is nil because use initialize stockData
STStockData *stockData = [[STStockData alloc] init];
and print _dStockData
NSLog(#"Dictionary %#",_dStockData);

how to save an NSMutableArray to local storage

I want to save an NSMutableArray to a file and load it every time my program runs. What is the best solution for this?
This is my example:
// I add a new item to ARRAYLIST
NSString *textNewCategory = [alert textFieldAtIndex:0].text;
[ARRAYLIST insertObject:textNewCategory atIndex:0];
// I save ARRAYLIST
userCategory = [NSUserDefaults standardUserDefaults];
[userCategory setObject:ARRAYLIST forKey:#"newCategory"];
NSLog(#"ARRAYLIST 1:%d", ARRAYLIST.count); // EX: In this case, it has count : 30
//In viewdidload, I get array that I saved before
userCategory = [NSUserDefaults standardUserDefaults];
arrayNewCategory = [[NSMutableArray alloc] initWithArray: [userCategory objectForKey:#"newCategory"]];
ARRAYLIST = arrayNewCategory;
NSLog(#"ARRAYLIST 2:%d", ARRAYLIST.count); // In this moment, it only has count: 29.
I don't understand why the re-loaded array has only 29 items instead of the 30 that I expect.
Save the array to a plist:
[array writeToFile:path atomically:NO]
and retrieve it:
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];

MutableDictionary turns immutable

In my first function i create an NSMutableDictionary and saves it in an array.
NSMutableArray* tempPlayersArray = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: #"kgpsTempArray"]];
NSMutableDictionary *tempPlayerDictArray = [[NSMutableDictionary alloc] init];
if (!(userDeviceName)) {
[tempPlayerDictArray setValue:userDeviceName forKey:#"DeviceName"];
}else{
[tempPlayerDictArray setValue:#"empty" forKey:#"DeviceName"];
}
[tempPlayersArray addObject:tempPlayerDictArray];
[defaults setObject:tempPlayersArray forKey:#"kgpsTempArray"];
[defaults synchronize];
In my second function i get it as NSCFDictionary - which is not mutable.
NSMutableArray* tempPlayersArray = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: #"kgpsTempArray"]];
NSMutableDictionary *dictionaryForSearching = [[NSMutableDictionary alloc] init];
NSLog(#"%#",[dictionaryForSearching class]);
dictionaryForSearching = [tempPlayersArray objectAtIndex:index];
NSLog(#"%#",[[tempPlayersArray objectAtIndex:index] class]);
NSLog(#"%#",[dictionaryForSearching class]);
The first log shows "NSDictionaryM".
The second log shows "NSCFDictionary".
And the third shows "NSCFDictionary" as well...
Can anyone explain me why? And how to fix it?
NSUserDefaults works with inmutable objects, so that's the reason that when you return your dictionary it's changed.
You can try this:
dictionaryForSearching = [[NSMutableDictionary alloc] initWithDictionary:[tempPlayersArray objectAtIndex:index]];
Yes, NSUserDefaults is free to copy, persist, and deserialize as it likes. Assume it does not return mutable objects. If you need a mutable object, make a mutable copy.
Every thing depends from here:
NSMutableArray* tempPlayersArray = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] arrayForKey: #"kgpsTempArray"]];
Reading NSUserDefaults always give you Immutable object.

Resources