I have an NSDictionary created by the AFNetworking class, but now I want to convert that NSDictionary into an array of objects of a class that I made. I have tried using the for-in loop as follows:
for (NSDictionary *item in results)
[_masterList addObject:[[MyObject alloc]initWithType:[item objectForKey:#"type"];
results by the way is my NSDictionary. There are no syntax errors, but when I run my program, nothing comes up. I tried NSLog-ing in the for-in, but didn't get anything, which means that the loop does not even run once. I'm pretty sure the NSDictionary is full, because I NSLoged the result during the AFNetworking process, and it was full:
(
{
address = "Sample Address";
}
)
Anyone have any ideas that I could use? Please express in the comments if I should add any more code. Thanks!
There are no key type, change it to address
for (NSDictionary *item in results)
[_masterList addObject:[[MyObject alloc]initWithType:[item objectForKey:#"address"];
results is a NSDictionary or a NSArray of dictionaries? If it is NSDictionary then you must loop like this:
// loop through each key in dictionary
// let say your key type is NSString
for (NSString* key in results) {
// access your object for key here
NSLog(#"%#", results[key]);
}
Not much of an answer but too big for a comment: you've made a mistake other than in the code presented. Try:
NSArray *results = #[
#{
#"address": #"Sample Address"
}
];
NSLog(#"%#", results);
for (NSDictionary *item in results)
NSLog(#"%# (%#)", item, [item objectForKey:#"address"]);
Output is:
2015-11-10 23:20:22.713 Untitled[1564:1904151] (
{
address = "Sample Address";
}
)
2015-11-10 23:20:22.715 Untitled[1564:1904151] {
address = "Sample Address";
} (Sample Address)
So, definitely the same dictionary, then the same iteration code, with correct results.
Addendum, which may or may not be helpful: one of the things Apple supplies to take advantage of Objective-C's reflective runtime is key-value coding which, assuming your properties obey certain rules, allows them to be written to by name. If you had a dictionary you wanted to commute to an object, and had performed suitable validation, then you might:
NSDictionary *inputDictionary = ... whatever ...
SomeObject *target = [[SomeObject alloc] init];
for (NSString *key in inputDictionary)
[target setValue:inputDictionary[key] forKey:key];
In contrast to Objective-C norms but consistently with most modern languages, that'll raise an exception if the key doesn't exist as a property on target. So in production code you probably want at least a try/catch block if the dictionary is coming from afar.
Related
I have a very strange behaviour with NSArray.
Firstly, i parsed an XML file and return a valid NSArray with NSDictionary inside:
NSArray *arrayOfDict = [parser parseWithXMLFile:filename];
In debugger it's fully valid. Then, i want to proccess all dictionaries in this array:
NSMutableArray* arrayOfProducts = [[NSMutableArray alloc] init];
for (NSDictionary* dict in arrayOfDict) {
Product* product = [[Product alloc] initWithName:dict[#"name"]
type:dict[#"type"]
imageName:dict[#"image"]
description:dict[#"description"]];
[arrayOfProducts addObject:product];
[product release];
}
And in this loop is a problem: a dict variable has value nil. And i don't know what to do with this. In debugger i evaluate value of arrayOfDict[someIndex] and get a right value, but in the programm itself it doesn't work.
May be it's the problem with MRR, i don't feel myself confidenly while using MRR and there is a mistake of using it.
P.S. I know that using MRR is stupid today, but in this project i must use it.
I am using below function to check whether if an object in an array is present in another array. If the object not present, then I will ADD that object to the new array, or else that object will NOT be included in the new array that I instantiated.
+ (NSMutableArray *)loadUngroupedSpeakerList
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *speakerList = [[NSMutableArray alloc] init];
NSArray *speakerIDList = [userDefaults objectForKey:DATA_SPEAKER_IDLIST];
NSArray *speakerIDListGrouped = [userDefaults objectForKey:DATA_SPEAKER_IDLIST_GROUPED];
//**** this is for checking the contents of speakerIDListGrouped ****//
for(NSString *speakerID in speakerIDListGrouped)
{
NSLog(#"FLOWCHECK~ loadUngroupedSpeakerList check content:%#", speakerID);
}
for(NSString *speakerID in speakerIDList)
{
if(![speakerIDListGrouped containsObject:speakerID])
{
NSLog(#"FLOWCHECK~ loadUngroupedSpeakerList: speakerID: %#", speakerID);
NSDictionary *speakerDict = [userDefaults dictionaryForKey:[NSString stringWithFormat:#"%#%#", DATA_SPEAKER_DICT, speakerID]];
[speakerList addObject:speakerDict];
}
}
return speakerList;
}
In the above code, speakerList contains all the speakerIDs. While speakerIDListGrouped only contains the speakerIDs that are used in a group. My function needs to eliminate all the speakerIDs used in a group so I did it in a way just like the above code.
My Problem:
When I run the code, I notice that even if speakerIDListGrouped contains the object in speakerIDList, these two lines would still be executed
NSDictionary *speakerDict = [userDefaults dictionaryForKey:[NSString stringWithFormat:#"%#%#", DATA_SPEAKER_DICT, speakerID]];
[speakerList addObject:speakerDict];
Whereas to I understand, It should not happen. Because I only allowed them to be executed only if speakerIDList does not contain that object.
This is the log when I execute the code:
2015-06-15 19:31:24.849 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList check content:72243140485836704
2015-06-15 19:31:24.850 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList check content:7782687177520836128
2015-06-15 19:31:24.850 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList: speakerID: 72243140485836704
2015-06-15 19:31:24.851 soulbeats[1936:433953] FLOWCHECK~ loadUngroupedSpeakerList: speakerID: 7782687177520836128
As can be seen, speakerIDListGrouped DOES contain the two objects. However, when I tried replacing the string inside the lower for loop by hardcoding it to one of the objects I printed on Log, which was 72243140485836704. The function now works properly, I mean it didn't execute the two lines I showed before.
I am now confused. What is the difference between the string I hardcoded and the one that was obtained from the array? The contents are the same.
Many Thanks!
I did the same thing it is working fine...
NSMutableArray *speakerList = [[NSMutableArray alloc] init];
NSArray *speakerIDList = #[#"a",#"b",#"c",#"d",#"e"];
NSArray *speakerIDListGrouped =#[#"a",#"b",#"f",#"g",#"h"];
for(NSString *speakerID in speakerIDListGrouped)
{
NSLog(#"%#", speakerID);
}
for(NSString *speakerID in speakerIDList)
{
if(![speakerIDListGrouped containsObject:speakerID])
{
NSLog(#"FLOWCHECK~ loadUngroupedSpeakerList: speakerID: %#", speakerID);
[speakerList addObject:speakerID];
}
}
There might be some issue with the objects inside the array....
This answer will help other's. It's very simple, use following method of NSArray
id commonObject = [array1 firstObjectCommonWithArray:array2];
Ref: https://developer.apple.com/documentation/foundation/nsarray/1408825-firstobjectcommonwitharray?language=objc
As you might expect, i'm fairly new to obj-C, and i'm constantly trying to build knowledge and experience. But i'm still struggling with a lot of concepts, and that includes JSON data 'catching'.
I've seen many tutorials and guides but i just can't translate them into what i need. Most of the time they layout data in arrays or get multiple values, and (of course) use different variables, which makes everything confusing and unclear to me, even though this should be stupidly simple.
I'm trying to do something very simple :
Get a single value from the open weather API, the temperature.
I'll show you my code which, according to my disgraceful knowledge, should be perfect, but apparently it doesn't work :D
#implementation HomeViewController
{
NSMutableArray *tableData;
NSDictionary *jsonDict;
NSMutableString *title;
}
-(void) viewDidLoad
{
[super viewDidLoad];
NSError *error;
//I create my data array and the string i'll store my value later on
tableData = [[NSMutableArray alloc] init];
title = [[NSMutableString alloc]init];
// Creating the link for the json api so it fits coordinates ; this works but i edited the locations out to clear the code
NSString *s = [[NSString alloc]initWithFormat:#"http://api.openweathermap.org/data/2.5/weather?lat=%.05f&lon=%.05f", _annotation.coordinate.latitude, _annotation.coordinate.longitude];
// I go online and catch the data of the url stored in S
NSData *jSonData = [NSData dataWithContentsOfURL:[NSURL URLWithString:s]];
// This is a dictionary where all my data is stored from jsonData, keys and values all the way
jsonDict = [NSJSONSerialization JSONObjectWithData:jSonData options:NSJSONReadingMutableContainers error:&error];
// I use the string created previously and assign it the value stored in that dictionary, in the TEMP 'folder', right under MAIN.
title = [[jsonDict objectForKey:#"main"]objectForKey:#"main.temp"];
// I assign that title to a label so it appears in my view.
self.tempLabel.text = title;
...
}
There you go. I'm probably missing something very simple but i've been stuck on this and even if i feel I know what i'm doing, i'm probably missing something. So it'd be great if with the answer you give me, you could also tell me what I did wrong :D
Thank you very much for your support and knowledge. This community is amazing :)
Put a breakpoint after assigning value to jsonDict and use
po jsonDict
in the console to print out what you are getting. Then, adjust the code that extracts the value. And use modern Objective-C syntax for it.
Example
title = jsonDict[#"main"][#"temp"];
Note
po is a debugger command that will print out the contents of an object. If you need to print out the contents of a primitive, use p instead.
My guess is
jsonDict = [NSJSONSerialization JSONObjectWithData:jSonData options:NSJSONReadingMutableContainers error:&error];
is trying to create an nsdictionary, but it the results are coming back as an array. Try this:
NSError *e = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: jsonDict options: NSJSONReadingMutableContainers error: &e];
if (!jsonArray) {
NSLog(#"Error parsing JSON: %#", e);
} else {
for(NSDictionary *item in jsonArray) {
NSLog(#"Item: %#", item);
}
}
This should set you right:
title = [[jsonDict objectForKey:#"main"]objectForKey:#"temp"];
To explain the issue, it seems you were referring to temp using a combination of dot syntax in the key.
EDIT: In response to your error:
That error appears when you're trying to find the length of a string on a value that is not of NSString type. Looks like temp is being returned as a number. So, to do what it looks like you're trying to do, you'll wanna convert [[jsonDict objectForKey:#"main"]objectForKey:#"temp"] to an NSString:
NSNumber *temp = [[jsonDict objectForKey:#"main"]objectForKey:#"temp"];
NSString *tempString = [temp stringValue];
OR
NSString *temp = [[[jsonDict objectForKey:#"main"]objectForKey:#"temp"] stringValue];
That will allow you to get the length: temp.length
**EDIT: Unless you're trying to get the length of the array of weather data...in which case i'd like to see more of that code
So I have an array with some objects (NSString, NSNumber, etc.) and I want to loop through it using a for loop. I thought I'd use the id for the type.
NSArray *myArray = [[NSArray alloc] initWithObjects:#"one string",#"another", #3, nil];
for (id *something in myArray) {
....
}
What's wrong with the for loop above? Why can't I use id and what would be the appropriate "type" to use.
I am a begginer in iOS dev.
id is intrinsically a pointer, hence all you need is:
for(id something in myArray) {
btw, using the constant object syntax makes such code more legible:
#[ #"one string", #"another", #3 ]
id as a type already is a pointer, so id * is a pointer to a pointer, which is incorrect here. Try this:
for (id something in myArray) {
}
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.