NSMutableArray only has copies of the last object - ios

I am using NSXML to parse out an XML document and add the results to an array of objects. The array has the correct number of objects, but they are full of data from the last object.(i.e. the object at index 0 has the same data as at index 3). I am getting good data back from my server.
//set up my objects and arrays higher in my structure
SignatureResult *currentSignatureResult = [[SignatureResult alloc]init];
Document *currentDoc = [[Document alloc]init];
Role *currentRole = [[Role alloc]init];
NSMutableArray *roleArray = [[NSMutableArray alloc] init];
NSMutableArray *doclistArray2 = [[NSMutableArray alloc] init];
.....there is more parsing up here
//role is defined as an NSXML Element
for (role in [roleList childrenNamed:#"role"]){
NSString *firstName =[role valueWithPath:#"firstName"];
NSString *lastName = [role valueWithPath:#"lastName"];
currentRole.name = [NSString stringWithFormat:#"%# %#",firstName, lastName];
for (documentList2 in [role childrenNamed:#"documentList"])
{
SMXMLElement *document = [documentList2 childNamed:#"document"];
currentDoc.name = [document attributeNamed:#"name"];
[doclistArray2 addObject:currentDoc];
}
currentRole.documentList = doclistArray2;
[roleArray addObject:currentRole];
///I've logged currentRole.name here and it shows the right information
}//end of second for statemnt
currentSignatureResult.roleList = roleArray;
}
///when I log my array here, it has the correct number of objects, but each is full of
///data from the last object I parsed

The cause is that the addObjects: retains for your currentRole object and not creates a copy from that. You can create your new currentRole object inside of the for or you can create a copy from that and add it to the array.
I recommend the following:
for (role in [roleList childrenNamed:#"role"]){
Role *currentRole = [[Role alloc] init];
NSString *firstName =[role valueWithPath:#"firstName"];
NSString *lastName = [role valueWithPath:#"lastName"];
currentRole.name = [NSString stringWithFormat:#"%# %#",firstName, lastName];
for (documentList2 in [role childrenNamed:#"documentList"])
{
SMXMLElement *document = [documentList2 childNamed:#"document"];
currentDoc.name = [document attributeNamed:#"name"];
[doclistArray2 addObject:currentDoc];
}
currentRole.documentList = doclistArray2;
[roleArray addObject:currentRole];
///I've logged currentRole.name here and it shows the right information
[currentRole release];
}//end of second for statemnt

Related

How to retrieve specific value of key in json?

this is my json content.
[
{
"sha":"30eae8a47d0203ac81699d8fc2ab2632de2d0bba",
"commit":{
"author":{
"name":"Madhura Bhave",
"email":"mbhave#pivotal.io",
"date":"2017-03-23T23:14:32Z"
},
"committer":{
"name":"Madhura Bhave",
"email":"mbhave#pivotal.io",
"date":"2017-03-23T23:14:32Z"
},
"message":"Merge branch '1.5.x'",
}
}
]
and this is my main.i just want to retrieve key value from message and name,email,date from committer dictionary.i got stuck how to do that.
NSMutableArray *CommitArray = [[NSMutableArray alloc] init];
for (NSDictionary *CommitDictionary in CommitJson) {
CommitDict *commitDictObj = [[CommitDict alloc] init];
commitDictObj.message = [CommitDictionary objectForKey:#"message"];
for (NSDictionary *CommitterDictionary in [CommitDictionary objectForKey:#"committer"]) {
Committer *author = [[Committer alloc] init];
author.name = [CommitterDictionary objectForKey:#"name"];
author.email = [CommitterDictionary objectForKey:#"email"];
author.date = [CommitterDictionary objectForKey:#"date"];
}
[CommitArray addObject:commitDictObj];
}
for (int i =0 ; i < [CommitArray count] ; i++){
CommitDict *commitDictObj = [CommitArray objectAtIndex:i];
NSLog(#"Commit Message: %#", commitDictObj.message);
}
return 0;
}
}
i try fetch the json and display it value of message,name,email and date.how can i log the value of message, name, email and date?
Your array contains a dictionary, and that dictionary contains the commit dictionary, not the commit dictionary directly. Replace that part of your code:
for (NSDictionary *CommitDictionary in CommitJson) {
CommitDict *commitDictObj = [[CommitDict alloc] init];
With that:
for (NSDictionary *shaCommitDictionary in CommitJson) {
CommitDict *commitDictObj = [[CommitDict alloc] init];
NSDictionary *CommitDictionary = [shaCommitDictionary objectForKey:#"commit"];
(1) Convert JSON to NSDictionary
NSData *jsonData= ... // Assume you got the data already loaded
NSError *error = nil;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
(2) Access the dictionary values (fast enumeration available by now!!
NSString *message = dictionary[#"message"];
NSDictionary *author = dictionary[#"author"];
NSString *name = author[#"author"];
NSString *email = author[#"author"];
NSString *date = author[#"author"];
// OR:
// NSString *name = dictionary[#"author"][#"author"];
// NSString *email = dictionary[#"author"][#"author"];
// NSString *date = dictionary[#"author"][#"author"];
And thats it. I think the tricky thing is to get the JSON Data to the NSDictionary?
See here: https://stackoverflow.com/a/30561781/464016

Unable to retrieve the data from Dictionary

In my project I am getting response from the server in the form
response:
<JKArray 0x7fa2e09036b0>(
{
id = 23;
name = "Name1";
},
{
id = 24;
name = "Name2";
}
)
From this response array i am retrieving the objects at different indexes and then adding them in a mutableArray and then into a contactsDictionary.
self.contactsDictionary = [[NSMutableDictionary alloc] init];
for(int i=0 ; i < [response count] ; i++)
{
NSMutableArray *mutableArray=[[NSMutableArray alloc] init];
[mutableArray addObject:[response objectAtIndex:i]];
[self.contactsDictionary setObject:mutableArray forKey:[NSString stringWithFormat:#"%i",i]];
}
I want to retrieve data for Key #"name" from the contactsDictionary at some other location in the project. So how to do it.
Thanks in advance....
this is the wrong way like you are setting your contactsDictionary.
replace below line
[self.contactsDictionary setObject:mutableArray forKey:[NSString stringWithFormat:#"%i",i]];
with
[self.contactsDictionary setObject:[mutableArray objectAtIndex :i] forKey:[NSString stringWithFormat:#"%i",i]];
becuase everytime your array have new objects so your contacts dictionary's first value have one object then second value have two object. so you shouldn't do that.
now, if you want to retrieve name then call like
NSString *name = [[self.contactsDictionary objectForKey : #"1"]valueForKey : #"name"];
avoid syntax mistake if any because have typed ans here.
Update as per comment:
just take one mutablearray for exa,
NSMutableArray *arr = [[NSMutableArray alloc]init];
[arr addObject : name]; //add name string like this
hope this will help :)
Aloha from your respond I can give you answer Belo like that according to you response.
for(int i=0;i<[arrRes count];i++);
{
NSString *strId = [NSString stringWithFormat:#"%#",[[arrRes obectAtIndex:i]objectForKey:#"id"]];
NSString *StrName = [NSString stringWithFormat:#"%#",[[arrRes objectAtIndex:i]objectForKey:#"name"]];
NSLog(#"The ID is -%#",strId);
NSLog(#"The NAME is - %#",strName);
}

How to split NSString and Rejoin it into two NSStrings?

I have a NSString like this one:
NSString* allSeats = #"1_Male,2_Female,3_Female,4_Male";
I want to split the NSString based on the keywords _Male & _Female and then make two separate strings like these:
NSString* maleSeats = #"1,4";
NSString* femaleSeats = #"2,3";
based on the contents of allSeats variable declared above.
How it will be possible to split NSString and then make 2 seperate strings?
You have to do it yourself. There is no "all done" solution. There are a few ways to do it.
Note: I didn't try my code, I just wrote it, it may don't even compile. But the important thing is that you get the whole idea behind it.
One way could be this one:
NSString *maleSufffix = #"_Male";
NSString *femaleSufffix = #"_Female";
NSMutableArray *femaleSeatsArray = [[NSMutableArray alloc] init];
NSMutableArray *maleSeatsArray = [[NSMutableArray alloc] init];
NSArray *array = [allSeats componentsSeparatedByString:#","];
for (NSString *aSeat in array)
{
if ([aSeat hasSuffix:maleSuffix])
{
[maleSeatsArray addObject:[aSeat stringByReplacingOccurencesOfString:maleSuffix withString:#""]];
}
else if ([aSeat hasSuffix:femaleSuffix])
{
[femalSeatsArray addObject:[aSeat stringByReplacingOccurencesOfString:femaleSuffix withString:#""]];
}
else
{
NSLog(#"Unknown: %#", aSeat);
}
}
NSString *maleSeats = [maleSeatsArray componentsJoinedByString:#","];
NSString *femaleSeats = [femaleSeatsArray componentsJoinedByString:#","];
Of course, you could use different methods on array, enumerating it, use a NSMutableString instead of a NSMutableArray (for femaleSeatsArray or maleSeatsArray, and use adequate methods then in the for loop).
I derived an idea from Larme's Clue and it works as :
Make a method as and call it anywhere :
-(void)seperateSeat
{
maleSufffix = #"_Male";
femaleSufffix = #"_Female";
femaleSeatsArray = [[NSMutableArray alloc] init];
maleSeatsArray = [[NSMutableArray alloc] init];
array = [self.selectedPassengerSeat componentsSeparatedByString:#","];
for (aSeat in array)
{
if ([aSeat hasSuffix:maleSufffix])
{
aSeat = [aSeat substringToIndex:[aSeat length]-5];
NSLog(#"%# is value in final seats ::",aSeat );
[maleSeatsArray addObject:aSeat];
}
else if ([aSeat hasSuffix:femaleSufffix])
{
aSeat = [aSeat substringToIndex:[aSeat length]-7];
NSLog(#"%# is value in final seats ::",aSeat );
[femaleSeatsArray addObject:aSeat];
}
}
totalMales = [maleSeatsArray componentsJoinedByString:#","];
totalFemales = [femaleSeatsArray componentsJoinedByString:#","];
NSLog(#"maleSeatsAre::::%#",totalMales);
NSLog(#"maleSeatsAre::::%#",totalFemales);
}

Trying to create an array of dictionaries, keep getting the same dictionary repeated in the array

I'm trying to use NSData to pull information out of a text file, and then load it into a dictionary.
First I create a string of the text file, and load each record into an array.
Then I break apart the each record into individual data elements.
The problem I'm having is that when the dictionary is fully populated, I then use addObject to load it into the array, which it does do successfully. The problem is that when the next loop creates a new dictionary, the same dictionary gets loaded into the array, and I end up an array of all the same dictionaries, instead of multiple different dictionary objects.
I'm guessing there is some simple mistake I'm making that is causing this error. Any help would be appreciated.
NSString *clientListFile = [NSURL URLWithString: #"/textfile"];
NSData *clientListDataFile = [NSData dataWithContentsOfFile:clientListFile];
NSString *clientListString = [[NSString alloc]initWithBytes:[clientListDataFile bytes] length:[clientListDataFile length] encoding:NSUTF8StringEncoding];
NSString *returnDelimiter = #"\n";
NSString *commaDelimiter = #",";
NSString *exclamationDelimiter = #"!";
NSArray *keysAndObjects = [[NSArray alloc]init];
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
NSMutableArray *clientListOfDictionaries = [[NSMutableArray alloc]init];
NSArray *sentenceArray = [clientListString componentsSeparatedByString:returnDelimiter];
for (int i = 0; i < [sentenceArray count]; i=i+1) {
[clientList removeAllObjects]; //to start with a fresh dictionary for the next iteration
NSString *recordSentence = [sentenceArray objectAtIndex:i];
NSArray *attributes = [recordSentence componentsSeparatedByString:commaDelimiter];
for (int j = 0; j < [attributes count]; j = j+1) {
NSString *pairsOfItems = [attributes objectAtIndex:j];
//a small arry, of only two objects, the first is the key, the second is the object
keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
[clientList setObject:[keysAndObjects lastObject] forKey:[keysAndObjects firstObject]];
}
[clientListOfDictionaries addObject:clientList];
}
When I used NSLog to see what's in the dictionary, I mulitple objects of the same dictionary repeated, even though up earlier in the iteration, I can see that the code is creating separate and unique dictionaries.
Instead of this line
[clientListOfDictionaries addObject:clientList];
you can have
[clientListOfDictionaries addObject:[[NSArray alloc] initWithArray:clientList];
That way you will be adding new arrays to clientListOfDictionaries instead of the same one.
Move this line:
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
to just after the first for loop line and then delete the line:
[clientList removeAllObjects];
It's important to create a new dictionary for each iteration.
You should also delete the following line:
NSArray *keysAndObjects = [[NSArray alloc]init];
and change:
keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
to:
NSArray *keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
You are allocated and initialising your clientList dictionary outside of the for loop, so you only have one dictionary, which you are storing in your array multiple times. Adding the dictionary to the array does not copy it, it merely adds a pointer to the object.
you need to move
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
inside your first for loop in place of
[clientList removeAllObjects];
Also, componentsSeparatedByString: returns an NSArray, so you don't need to allocate and initialise one. You can simply define the variable -
NSArray *keysAndObjects;
Because you're using the same clientList variable for each iteration of the loop. You need to create a whole new dictionary object each time.
Try this modified code:
NSData *clientListDataFile = [NSData dataWithContentsOfFile:clientListFile];
NSString *clientListString = [[NSString alloc]initWithBytes:[clientListDataFile bytes] length:[clientListDataFile length] encoding:NSUTF8StringEncoding];
NSString *returnDelimiter = #"\n";
NSString *commaDelimiter = #",";
NSString *exclamationDelimiter = #"!";
NSArray *keysAndObjects = nil;
NSMutableArray *clientListOfDictionaries = [[NSMutableArray alloc] init];
NSArray *sentenceArray = [clientListString componentsSeparatedByString:returnDelimiter];
for (NSUInteger i = 0; i < [sentenceArray count]; ++i) {
NSMutableDictionary *clientList = [[NSMutableDictionary alloc] init]; //to start with a fresh dictionary for the next iteration
NSString *recordSentence = [sentenceArray objectAtIndex:i];
NSArray *attributes = [recordSentence componentsSeparatedByString:commaDelimiter];
for (NSUInteger j = 0; j < [attributes count]; ++j) {
NSString *pairsOfItems = [attributes objectAtIndex:j];
//a small arry, of only two objects, the first is the key, the second is the object
keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
[clientList setObject:[keysAndObjects lastObject] forKey:[keysAndObjects firstObject]];
}
[clientListOfDictionaries addObject:clientList];
}
An alternate option, though likely less efficient, is to to change the line:
[clientListOfDictionaries addObject:clientList];
to
[clientListOfDictionaries addObject:[clientList copy]];
That lets you keep using the same clientList variable, since you're adding a copy of it to the clientListOfDictionaries array. I just point that out because it might help you understand what's going on.
Also, note that I changed this line for you:
NSArray *keysAndObjects = [[NSArray alloc]init];
to
NSArray *keysAndObjects = nil;
Because it's just a pointer that is set by your call to componentsSeparatedByString, you don't need to allocate an array for it. That array will just vanish in your first iteration of the loop.
Should be added the new dictionary to array. Otherwise it will not add to an array. Every object in array have same dictionary mapping. So it will give you the same dictionary value. Create new dictionary for every object and add to array.
for (int i = 0; i < [sentenceArray count]; i=i+1) {
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
NSString *recordSentence = [sentenceArray objectAtIndex:i];
NSArray *attributes = [recordSentence componentsSeparatedByString:commaDelimiter];
for (int j = 0; j < [attributes count]; j = j+1) {
NSString *pairsOfItems = [attributes objectAtIndex:j];
//a small arry, of only two objects, the first is the key, the second is the object
NSArray *keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
[clientList setObject:[keysAndObjects lastObject] forKey:[keysAndObjects firstObject]];
}
[clientListOfDictionaries addObject:clientList];
}

NSMutableArray from NSArray

i have the following code and i want to use NSMutable arrays instead of NSArray
could you tell me how to load the NSMutable array, as the current method does not work.
-(void) whatever{
NSData *htmlData = [[NSString stringWithContentsOfURL:[NSURL URLWithString: #"http://www.objectgraph.com/contact.html"]] dataUsingEncoding:NSUTF8StringEncoding];
TFHpple *xpathParser = [[TFHpple alloc] initWithHTMLData:htmlData];
NSArray *titles = [xpathParser search:#"//h3"]; // get the page title - this is xpath notation
TFHppleElement *title = [titles objectAtIndex:0];
NSString *myTitles = [title content];
NSArray *articles = [xpathParser search:#"//h4"]; // get the page article - this is xpath notation
TFHppleElement *article = [articles objectAtIndex:0];
NSString *myArtical = [article content];
i have tried :
NSMutableArray *titles = [xpathParser search:#"//h3"];
but it does load the values?
You can invoke mutableCopy on an NSArray object to return to you an NSMutableArray.
Note that the callee will obtain ownership of this object since the method name contains "copy".
(Apple's memory management guide states that a method name containing the words "alloc", "new" or "copy" should by convention return an object which you own, and as such must relinquish ownership of at some point.)
Simply like this:
NSArray* someArray = [xpathParser search:#"//h3"];
NSMutableArray* mutableArray = [someArray mutableCopy];
That's quite literally, it.
Assuming [xpathparser ...] returns an NSArray, you can use:
NSMutableArray *titles = [NSMutableArray arrayWithArray:[xpathParser search:#"//h3"]];

Resources