views:

98

answers:

3

I'm using the JSON Framework addon for iPhone's Objective-C to catch a JSON object that's an array of Dictionary-style objects via HTTP. Here's my connectionDidFinishLoading function:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
   [connection release];
 NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
 [loadingIndicator stopAnimating];

 NSArray *responseArray = [responseString JSONValue]; // Grab the JSON array of dictionaries
 NSLog(@"Response Array: %@", responseArray);
 if ([responseArray respondsToSelector:@selector(count)]) {
  NSLog(@"Returned %@ items", [responseArray count]);
 }
 [responseArray release];
 [responseString release];
}

The issue is that the code is throwing a EXC_BAD_ACCESS error on the second NSLog line. The EXC_BAD_ACCESS error I think indicates that the variable got released from memory, but the first NSLog command works just fine (and shows that the data is all there); it seems that only when calling the count message is causing the error, but the respondsToSelector call at least thinks that the responseArray should be able to respond to that message. When running with the debugger, it crashes on that second line, but the stack shows that the responseArray object is still defined, and has 12 objects in it (so the debugger at least is able to get an accurate count of the contents of that variable).

Is this a problem with the JSON framework's creation of that NSArray, or is there something wrong with my code?

+2  A: 

count returns an NSUInteger, not an object. Per the Apple Documentation you should use %lu and cast to unsigned long in this case instead to display it:

NSLog(@"Returned %lu items", (unsigned long)[responseArray count]);

With %@, NSLog() tries to interpret the value as a pointer to an object and to send a description message to it.
It is highly unlikely that there is accidentally a valid object at that memory location, so the code is bound to fail badly or show unpredictable results.

Georg Fritzsche
Ah goodness; hate it when the dumb things trap me; I usually use `%@` as a catch-all, presuming that even base variable types like `NSInteger` are really an object in Objective-C, and can hence output something with that call, but apparently not in this case.
MidnightLightning
@Midnight, only instances of Objective-C class types are objects. You have to remember that Objective-C only extends C.
Georg Fritzsche
@gf is there a listing of which classes are "Objective-C" types as opposed to "C" types? I had thought `NSUInteger` (what gets returned from the `NSArray` 'count' method) was an Objective-C type, as opposed to the `int` type (which is a basic C type) and therefore should be able to respond to a "description" message (even if that's not the most proper way of handling it)?
MidnightLightning
@Midnight: None that i know of. There aren't so many non-class-types though, you should get accustomed to them. Note that *a)* you can always jump to the definition of a type in Xcode and *b)* pointers to non-class-types are rarely used in Cocoa.
Georg Fritzsche
+1  A: 

Simple typo: Your format string in the second NSLog contains an %@ instead of %d.

Nikolai Ruhe
`%u` actually, `count` returns an unsigned integer.
Georg Fritzsche
@gf You’re right, I have this lazy habit of not using the right format specifiers. But while we're at it: `count` returns an `NSUInteger` which, on iPhone OS, is typedef'ed to `unsigned int`. On LP64 (Mac OS 64 Bit) it is typedef'ed to an `unsigned long`. Therefore I'd argue to use `%lu` as a format specifier. That should work in all cases.
Nikolai Ruhe
`%lu` is what the docs recommend, IIRC.
Wevah
Nikolai, good point.
Georg Fritzsche
+2  A: 

In addition to what gf and Nikilai said, [responseArray release]; over releases

If those guys got their method naming right, NSArray *responseArray = [responseString JSONValue]; returns an autoreleased instance.

Rengers
And in another addition to this: It seems like you shouldn't `release` the `connection`. You should **never** have to think about `release`ing **any** variables you get inside a method.
bddckr
Good point; I hadn't gotten that far to trigger an over-release error!
MidnightLightning
@ChriB; the release of the connection variable I got as part of the boilerplate code I went off of from http://www.mobileorchard.com/tutorial-json-over-http-on-the-iphone/
MidnightLightning
Still sounds like unnecessary to me. Had a look at the docs and it doesn't seem to be needed.
bddckr
@ChriB: Well afaik you need to release the connection somewhere. Either in the delegate methods (like he has now), or in the dealloc method if you made it an ivar.
Rengers