iOS JSON twitter response, convert to mutable - twitter

I have an app that is requesting a users list of followers. I would like to be able to change some of the data inside of the array I am getting back from twitter, but I can't seem to get it to become a proper mutable copy.
Here is my code:
NSMutableDictionary *theData = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
NSMutableDictionary *TWData = [[NSMutableDictionary alloc] init];
TWData = [theData mutableCopy];
NSMutableArray *data = [TWData objectForKey:#"users"];
The order this is in and doing a mutable copy FIRST is the last thing I tried. This is the code that throws an error:
[[data objectAtIndex:2] setObject:#"indeed" forKey:#"following"];
And here is the typical error message:
[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
I understand WHY it is giving me the error, my question is how can I make EVERYTHING (all child dictionaries and array, and all of their child dictionaries and array, etc.) mutable so I can alter the data.
Any help is great, thanks!

You can use CFPropertyListCreateDeepCopy from Core Foundation:
NSMutableDictionary* mutableData = (NSMutableDictionary*) CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFPropertyListRef) theData, kCFPropertyListMutableContainers));
See the CFPropertyList reference for more info. In particular, the Property List Mutability Options can be used to control what is mutable in the returned copy.

Related

How to change value in object of object from NSMutableDictionary? (Objective-C) [duplicate]

I'm reading into my application a plist which at the top level is an array. It's simple enough to make sure the array starts as mutable
self.plistData = [[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"myDataSource" ofType:#"plist"]] mutableCopy];
Within each element of the array is another array, each of those contains a dictionary.
Based on a tablecell selection I'm changing attributes for the dictionary at the selected index:
[self.cellDescriptors[indexPath.section][indexOfTappedRow] setValue:#"YES" forKey: #"isSelected"];
I'm getting the error '-[__NSCFDictionary removeObjectForKey:]: mutating method sent to immutable object' when I attempt to change a dictionary value. The error makes sense if the NSDictionary read in by the plist is immutable.
Is there any way to read in content from a plist and make sure any arrays or dictionaries are read in as mutable versions?
The simplest approach is to use NSPropertyListSerialization and passing the proper options to get mutable containers.
NSString *path = [[NSBundle mainBundle] pathForResource:#"myDataSource" ofType:#"plist"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSMutableArray *array = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainers format:nil error:nil];
self.plistData = array;
Ideally you will make use of the error parameter and do proper error checking but this will get you started.
This code will load the plist and return a mutable array and every contained array and dictionary will also be mutable.

NSPropertyListSerialization returning nil instead of serialized data

I am putting two NSMutableArray objects into an NSDictionary and trying to serialize, but the method call is returning nil. One array, addresses, is an array of NSString objects. The other, engines is an array of objects that each contain several data types. I am attempting to serialize using the following code:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:engAddr forKey:#"engAddr"];
[dictionary setObject:trainList forKey:#"engines"];
NSData *data = [NSPropertyListSerialization dataFromPropertyList:dictionary
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
Stepping through, the debugger shows the arrays are properly added to the dictionary, but after the line that should serialize the dictionary it shows data = (NSData *) nil.
Where am I going wrong? Thank you for your help!
What kind of objects does engines contain?
Plist supports only specific objects below.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PropertyLists/AboutPropertyLists/AboutPropertyLists.html#//apple_ref/doc/uid/10000048i-CH3-54303
If you want to serialize a custom object, convert it to NSData by NSKeyedArchiver.
To do that, objects must conform NSCoding protocol.

Parse json Data in iOS

I know it's a common question, but I am stuck with is API
How to Parse data from this API : http://dl.bahramradan.com/api/1/get/ig
it contain 20 Object and in every object there are 3 other Objects called "image",date" and "caption"
how can I store all "date" values in an NSMUtableArray in ios?
I did this :
NSString *urlStr = [NSString stringWithFormat:#"http://dl.bahramradan.com/api/1/get/ig"];
NSURL *url = [NSURL URLWithString:urlStr];
NSData *json = [NSData dataWithContentsOfURL:url];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:json options:0 error:NULL];
NSArray *dateArray = [dict objectForKey:#"date"];
But when I run my app, it crashs on the last line, what is wrong ?
I did not check, if your JSON is valid. But there is one obvious mistake in your code: If the JSON consists of 20 objects, I assume those being contained in an array, rather than in a dict!
So first thing to change is
NSArray *array = [NSJSONSerialization JSONObjectWithData:json options:0 error:NULL];
Then, you want to extract the 'date' values for all items and combine these in another array.
Easiest way to achieve that, is by using a KVC Collection Operator
NSArray *dateArray = [array valueForKeyPath:#"#unionOfObjects.date"];
So, what '#unionOfObjects.date' does, is: going through all the objects in the array, look for each of their 'date' value and combine them in the returned array.
Check out this excellent post about KVC Collection Operators!

NSMutableArray removeAllObjects results in a crash

I have an NSMutableArray in my ViewController which is the datasource for my UITableView defined like so:
NSMutableArray *messageArray;
I have a method to reload the tableView data, before which, I want to clear the existing table data.
If I use the following code:
[messageArray removeAllObjects];
[self.tableView reloadData];
I get the following exception:
2013-02-12 14:20:30.378 appname[20998:907] * Terminating app due to
uncaught exception 'NSInternalInconsistencyException', reason:
'-[__NSCFArray removeObjectAtIndex:]: mutating method sent to
immutable object'
* First throw call stack: (0x3939e3e7 0x35dd6963 0x3939e307 0x393200e7 0x392eb5e5 0x7cda3 0x3a236047 0x3a2360d1 0x3a236047
0x3a235ffb 0x3a235fd5 0x3a23588b 0x3a235d79 0x3a15e5c9 0x3a14b8b1
0x3a14b1bf 0x336305f7 0x33630227 0x393733e7 0x3937338b 0x3937220f
0x392e523d 0x392e50c9 0x3362f33b 0x3a19f291 0x79c11 0x39be4b20)
libc++abi.dylib: terminate called throwing an exception
But if I use the following code, it works.
NSMutableArray *emptyArray = [NSMutableArray new];
messageArray = emptyArray;
[self.tableView reloadData];
Why am I getting an error for removeAllObjects?
Could this be the culprit?
NSMutableDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
messageArray = responseDictionary[#"data"];
Could this be the culprit?
NSMutableDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
messageArray = responseDictionary[#"data"];
Yes, you want to use the option for mutable containers:
NSMutableDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options: NSJSONReadingMutableContainers error:NULL];
It looks like your "NSMutableArray" is actually an NSArray cast to NSMutableArray.
Search your code for something like this:
messageArray = (NSMutableArray *)[obj methodReturningNSArray];
removeAllObjects will only work on a true NSMutableArray, as the error "mutating method sent to immutable object" states.
you has to change this line:
messageArray = responseDictionary[#"data"];
to:
messageArray = [responseDictionary[#"data"] mutableCopy];
by default the objects that you get from a dictionary are non-mutables
The messageArray returned by your data reload is not an NSMutableArray, but is instead an NSArray. If you place a debugger stop after the reload you can verify this. Use .mutableCopy when setting messageArray.
How to find the spot with the error:
Check if you #synthesize a property named messageArray. If this property is of NSArray type or declared with the copy modifier the synthesized setter is the culprit.
If not, redeclare the ivar NSMutableArray *const messageArray. Now the compiler will show you each assignment. Check for NSArray assigments. Don't forget to revert the declaration after that.
When done, rename the ivar to _messageArray to find direct accesses faster in the future.
Somewhere you have set NSMutableArray to an instance of NSArray, not NSMutableArray or you declared NSMutableArray as a property of type NSArray vs. NSMutableArray.
Cocoa documentation uses the word immutable to refer to read-only, can't-be-changed-after-initialization objects.
Also, you should follow Cocoa / Objective-C naming conventions. Namely, class names start with upper case; variables take the form myArray (or something more descriptive, preferably).
You can find more detail of the copyWithZone reference and in the NSMutableCopying protocol reference.

Cannot access NSDictionary

I created a JSON using a PHP script.
I am reading the JSON and can see that the data has been correctly read.
However, when it comes to access the objects I get unrecognized selector sent to instance...
Cannot seem to find why that is after too many hours. Any help would be great!
My code looks like that:
NSDictionary *json = [[NSDictionary alloc] init];
json = [NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&error];
NSLog(#"raw json = %#,%#",json,error);
NSMutableArray *name = [[NSMutableArray alloc] init];
[name addObjectsFromArray: [json objectForKey:#"name"]];
The code crashes when reaching the last line above.
The output like this:
raw json = (
{
category = vacancies;
link = "http://blablabla.com";
name = "name 111111";
tagline = "tagline 111111";
},
{
category = vacancies;
link = "http://blobloblo.com";
name = "name 222222222";
tagline = "tagline 222222222";
}
),(null)
2012-06-23 21:46:57.539 Wind expert[4302:15203] -[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0xdcfb970
HELP !!!
json is an array from what you've shown, not a dictionary. I can tell this because of the parentheses surrounding the whole of the log output for json. Inside the array are dictionaries, which I can tell by the fact that they are surrounded by braces.
So, it looks like you want something like this:
NSError *error = nil;
NSArray *json = [NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&error];
NSLog(#"raw json = %#,%#",json,error);
NSMutableArray *name = [[NSMutableArray alloc] init];
for (NSDictionary *obj in json) {
[name addObject:[obj objectForKey:#"name"]];
}
As an aside you will notice I have removed the unnecessary initialisation of json to an object before overwriting in the next line with JSONObjectWithData:options:error:. In an ARC world it wouldn't be a leak but it's still completely unnecessary to allocate an object just to get rid of it again a moment later. Also I added in the NSError *error = nil; line since that was not there and was obviously necessary to compile.
The problem appears to be that the root level of your JSON is an array, not a dictionary (note the parenthesis instead of curly brace as the first character in the logged output). Arrays do not have objectForKey selector. Perhaps you intend to take objectAtIndex:0 first, or else iterate over all the the items?
As an aside, the first line of your code makes a completely wasted initialization of an NSDictionary. It is simply overwritten and deallocated on the very next line.

Resources