Objective-C for Dummies: How do I loop through an NSDictionary inside of an NSDictionary?
Alright guys, I'm quite confused. So, I have an NSDictionary which is populated by a JSON string which looks like:
{"Success":true,"Devices":[{"UDId":"...","User":"...","Latitude":0.0,"Longitude":0.0}]}
Now, I know how to check if Success
is true
, but I need to loop through the array of Devices
(JSON object) and create an internal array of Devices
(internal app object) and I have no idea how to do that. Can someone please explain how to do it?
Here's my Device.m/h
:
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>
@interface Device : NSObject {
NSString *udId;
NSString *name;
NSNumber *latitude;
NSNumber *longitude;
}
@property (nonatomic, retain) NSString *udId;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSNumber *latitude;
@property (nonatomic, retain) NSNumber *longitude;
#pragma mark -
#pragma mark MKAnnotation Properties
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@end
----
#import "Device.h"
@implementation Device
@synthesize udId, name, latitude, longitude;
- (CLLocationCo开发者_StackOverflow中文版ordinate2D)coordinate {
CLLocationCoordinate2D internalCoordinate;
internalCoordinate.latitude = [self.latitude doubleValue];
internalCoordinate.longitude = [self.longitude doubleValue];
return internalCoordinate;
}
- (void)dealloc {
[udId release];
udId = nil;
[name release];
name = nil;
[latitude release];
latitude = nil;
[longitude release];
longitude = nil;
[super dealloc];
}
@end
And here's the methods where I should be reading the response and converting it to objects I can use:
- (void)requestFinished:(ASIHTTPRequest *)request {
if (![request error]) {
NSError *jsonError = nil;
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithJSONString:[request responseString] error:&jsonError];
if (!jsonError || ([[jsonDictionary objectForKey:@"Success"] intValue] == 1)) {
// READ "DEVICES" AND CONVERT TO OBJECTS
} else {
// AUTHORIZATION FAILED
}
}
}
I'd really appreciate some help on this. I just can't seem to wrap my head around it...
Thanks in advance!
You are almost there. In your code where you say:
// READ "DEVICES" AND CONVERT TO OBJECTS
do this:
NSArray * devices = [jsonDictionary objectForKey:@"Devices"];
for(NSDictionary * deviceInfo in devices) {
Device * d = [[[Device alloc] init] autorelease];
[d setLatitude:[deviceInfo objectForKey:@"Latitude"]];
[d setLongitude:[deviceInfo objectForKey:@"Longitude"]];
[d setName:[deviceInfo objectForKey:@"User"]];
[d setUdId:[deviceInfo objectForKey:@"UDId"]];
// do some stuff with d
}
What's going on here: I didn't see what JSON library you are using to convert, but presuming it works like TouchJSON or SBJSON, the JSON array is automatically turned into an NSArray instance, while the inner hashes of the NSArray are NSDictionary objects. At the point that you have deserialized that JSON string, everything you're dealing with will be instances of NSString, NSNumber, NSArray and NSDictionary (and depending on the library, NSNull to represent null values).
First you need to define your initializer/constructor for your Device class.
Device.h
- (id)initWithUdid:(NSString *)udid name:(NSString *)name latitude:(NSNumber *)lat longitude:(NSNumber *)lon;
Device.m
- (id)initWithUdid:(NSString *)udid name:(NSString *)name latitude:(NSNumber *)lat longitude:(NSNumber *)lon {
if (self = [super init]) {
self.udid = udid;
self.name = name;
self.latitude = lat;
self.longitude = lon;
}
return self;
}
Then you can initialize a new object like:
Device *dev = [[Device alloc] initWithUdid:@"a udid" name:@"the name" latitude:latNum longitude:lonNum];
So, you should be able to iterate the array and build your Device objects like so:
NSArray *devicesArray = [dict objectForKey:@"Devices"];
for (NSDictionary *d in devicesArray) {
Device *dev = [[Device alloc] initWithUdid:[d objectForKey:@"UDId"]
name:[d objectForKey:@"User"]
latitude:[NSNumber numberWithDouble:[d objectForKey:@"Latitude"]]
longitude:[NSNumber numberWithDouble:[d objectForKey:@"Latitude"]]];
}
You want to access the array of device dictionaries from the top-level dictionary just as you did the Success value. Then iterating over the dictionaries you can use each's -keyEnumerator
method to iterate over its keys.
- (void)requestFinished:(ASIHTTPRequest *)request {
if (![request error]) {
NSError *jsonError = nil;
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithJSONString:[request responseString] error:&jsonError];
if (!jsonError || ([[jsonDictionary objectForKey:@"Success"] intValue] == 1)) {
NSArray* deviceArray = [jsonDictionary objectForKey:@"Devices"];
for(NSDictionary* dict in deviceArray)
{
for(NSString* key in [dict keyEnumerator])
{
NSLog(@"%@ -> %@", key, [dict objectForKey:key]);
}
}
// READ "DEVICES" AND CONVERT TO OBJECTS
} else {
// AUTHORIZATION FAILED
}
}
}
Sounds like you need to reuse your line:
[jsonDictionary objectForKey:@"Success"]
try having a look at
[jsonDictionary objectForKey:@"Devices"]
You really need to figure out what type it returns.
If you're lucky, it returns an NSDictionary
, or alternately something that you can easily turn into an NSDictionary
.
精彩评论