Passing an NSArray as a parameter? - iphone

I am trying to get JSON data loaded from a NSURLConnection delegate to send the array of objects back to the tableview that called it.
The delegate object is initialized with callback to send back to
NSArray *returnArray;
ResultsTableRoot *callback;
JSON handling method
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[[SBJSON alloc] init] autorelease];
returnArray = [json objectWithString:responseString
error:&error];
[responseString release];
//////////////////////////////////////////////
// Send data back to table view
[callback resultsArrayReciever:returnArray];
}
The array can't be accessed from here, the tableview I want to have the information, however the method is called
-(void)resultsArrayReciever:(NSArray *)array {
// Code executed
if(array) {
// Code never executes, array isnt there
}
}
If you have a better way to go about this whole thing, it is more than welcome!!

The returnArray is probably autoreleased. Try retain/releasing it in your methods.
If it is autoreleased the contents will be released in your run-loop and therefore disappear by the time you want to access it.

Check the NSError instance to see if there wasn't some problem while deserializing the JSON;
Try retaining the object:
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
returnArray = [[json objectWithString:responseString error:&error] retain];
[responseString release];
[callback resultsArrayReciever:returnArray];
[returnArray release];

Related

json object UITableView

Server returns json object shown as below: its around 51 objects
[{"location":"Location1","email":"sriharsha#yahoo.com","phone":"123456"},{"location":"Location2","email":"sriharsha.mandya#gmail.com","phone":"123456789"},
.
.
..
..
..51]
I want to assign this value first tableview to locations and detailview with email and phone number...
code I used is below:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSDictionary *dictionary = [responseString JSONValue];
NSArray *response = [dictionary objectForKey:#"location"];
exercises = [[NSArray alloc] initWithArray:response];
[table reloadData];
}
where am I wrong please suggest...
From first glance the response string looks like an array of dictionaries
to access the the data try something like
NSArray* arrayOfDictionaries = [responseString JSONValue];
NSDictionary* firstDictionary = [arrayOfDictionaries objectAtIndex:0];

parsing JSON of webservice on objective c array

I'm developing an iphone app and I have a JSON from web service as below:
[
{
"0":"test_w",
"assignment_title":"test_w",
"1":"2011-11-02 04:02:00",
"assignment_publishing_datetime":"2011-11-02 04:02:00",
"2":"2011-11-02 01:53:00",
"assignment_due_datetime":"2011-11-02 01:53:00",
"3":"course_math.png",
"course_icon":"course_math.png",
"4":null,
"submission_id":null
},
{
"0":"\u062a\u0637\u0628\u064a\u0642 \u0631\u0642\u0645 3",
"assignment_title":"\u062a\u0637\u0628\u064a\u0642 \u0631\u0642\u0645 3",
"1":"2011-08-08 00:00:00",
"assignment_publishing_datetime":"2011-08-08 00:00:00",
"2":"2011-08-25 00:00:00",
"assignment_due_datetime":"2011-08-25 00:00:00",
"3":"course_math.png",
"course_icon":"course_math.png",
"4":null,
"submission_id":null
}
]
also I have a tableview and I need to parser assignment_title only on the tableview cells , also I'm using SBJSON library.
so what is the best way to extract assignment_title and put them on cells?
I find the solution from your answers as below:
I created a method with 2 parameters (json_path , field [that i need to show in tableview cell])
- (NSMutableArray*)JSONPath:(NSString *)path JSONField:(NSString *)field{
SBJSON *parser = [[SBJSON alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:path]];
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSArray *statuses = [parser objectWithString:json_string error:nil];
NSMutableArray * tempMutArray = [[[NSMutableArray alloc] init] autorelease];
int i;
for (i=0; i<[statuses count]; i++) {
[tempMutArray addObject:[[statuses objectAtIndex:i] objectForKey:field]];
}
return [tempMutArray copy];
}
after that i call it in cell as following:
//in viewDidLoad
NSArray * homework = [self JSONPath:#"http://....." JSONField:#"assignment_title"];
//In cellForRowAtIndexPath
cell.textLabel.text = [homework objectAtIndex:indexPath.row];
Thanks to all
If you are doing it through NSJSONSerialization you can get array of assignment_title using this simple method ;)
NSError *error = nil;
NSData *jsonData = [NSData dataWithContentsOfURL:apiURL];
id jsonObjectFound = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
NSArray* assignmentTitles = [jsonObjectFound valueForKey:#"assignment_title"];
If performance matters, you might consider using an ASIHTTPRequest to fetch the json asynchronously, then inside the requestFinished: you might do something like:
- (void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
//assuming you created a property instance variable NSArray *myArrAssignmentTitles
NSArray *tempArray = [responseString JSONValue];
//making an array of assignment_title
NSMutableArray *tempMutArray = [[NSMutableArray alloc] init];
int i;
for(i = 0;i < [tempArray count];i++){
[tempMutArray addObject:[[tempArray objectAtIndex:i] objectForKey:#"assignment_title"]];
}
//assign the data to the instance variable NSArray *myArrAssignmentTitles
self.myArrAssignmentTitles = tempMutArray;
//release tempMutArray since the instance variable has it
[tempMutArray release];
//call the reload table
[self.tableView reloadData];//i think this is how to reload the table
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
}
So, your myArrAssignmentTitles has all the values assignment_title from json
all you do is just apply the array data for the cell e.g.
cell.textLabel.text = [self.myArrAssignmentTitles objectAtIndex:indexPath.row];
its a long code sorry about that. But, thats works for me xD; it fetches the json asynchronously after that it creates an array of assignment_title hopes it helps.

When release methods local variables in Obj-C

I'm developing an iPhone application and I've just created this method (it's in a singleton class):
- (NSDictionary *)getLastPosts
{
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:http://example.org/last/]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *data_dict = [parser objectWithString:json_string error:nil];
// release stuff
[parser release];
[request release];
[response release];
[json_string release];
return data_dict;
}
I'm a newbie obj-c developer so I'm not sure of this two things:
Is it correct the four vars release in the method's end?
When should I release the NSDictionary data_dict?
UPDATE 1
If data_dict was NSDictionary *data_dict = [[NSDictionary alloc] init] when I'll should release it?
UPDATE 2
In the caller I have this:
- (void)callerMethod
{
NSDictionary *tmpDict = [mySingleton getLastPosts];
NSLog(#"retain count: %d", [tmpDict retainCount]);
}
and the debug console prints:
retain count: 2
Why "Xcode Analyze" says me these lines?
And why the retain count it's 2?
In general, it is good to release objects you do not need any more.
But remember
- Only things that have alloc, new or copy in their initialization need to be released. Otherwise they are already autoreleased.
So, it is ok to release the parser, not ok to release the request, not ok to release the response, ok to release the json_string.
SBJsonParser *parser = [[SBJsonParser alloc] init];
You called init, then you own the instance and you need to release it.
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:http://example.org/last/]];
You called a class method that returns an autoreleased instance which will be added to the autorelease poll.
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
Autoreleased.
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
You called init, you will need to release it.
NSDictionary *data_dict = [parser objectWithString:json_string error:nil];
Returned instance, autoreleased.
Thus you just need to release two of them:
[parser release];
[json_string release];
if NSDictionary *data_dict = [[NSDictionary alloc] init] then you would need to autorelease it yourself: the convention is that any instance returned by a method is autoreleased.
By the way by autoreleasing it you make sure that it will be available until the autorelease pool is emptied (unless you call release on it).
To autorelease it:
return [data_dict autorelease];
It is correct to release parser and json_string because these are created with methods containing "alloc". It is incorrect to release the others because they are autoreleased.
You never have to release data_dict in this method, since it is autoreleased.
Please read the Objective-C memory management rules.

Creating a new NSURLConnection inside of connectionDidFinishLoading

I have a NSURLConnection that gets data from a JSON web service, and everything works fine. I'm using it to post something to the server and get a success response.
After that call I want to initiate another NSURLConnection to refresh the data, so I'm doing so inside the connectionDidFinishLoading method, however this second connection isn't calling connectionDidFinishLoading when it is done loading.
Can I not initiate a NSURLConnection from inside the connectionDidFinishLoading method?
EDIT: Below is the code. I subclassed NSURLConnection to include a Tag NSString, calling the new class NSURLConnectionHelper. I'm using this to differentiate which connection has called the connectionDidFinishLoading.
- (void)connectionDidFinishLoading:(NSURLConnectionHelper *)connection
{
if([connection.Tag isEqual:#"NewMessage"]){
NSString *jsonString = [[NSString alloc] initWithData:receivedNewMessageData encoding:NSASCIIStringEncoding];
NSDictionary *results = [jsonString JSONValue];
[jsonString release];
[connection release];
if ([[results objectForKey:#"MessageAdded"] isEqual:#"True"]) {
User *newUser = [[User alloc] init];
[newUser retrieveFromUserDefaults];
if([newUser IsLoggedIn]){
Message *message = (Message *)[messages objectAtIndex: 0];
NSString *urlAsString = // url for webservice goes here
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnectionHelper *connection1 = [[NSURLConnectionHelper alloc] initWithRequest:request delegate:self];
connection1.Tag = #"GetLatestMessages";
[request release];
if (connection1) {
receivedLatestMessagesData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
}
}
}else if([connection.Tag isEqual:#"GetLatestMessages"]){
//do some other stuff but this code is never reached
}
}
I'm not familiar with NSURLConnectionHelper but it looks like you're never starting the connection.
I ended up having a space in my web service url, once I corrected that it worked.

Objective-c for the iphone: Mystery memory leak

My application seems to have 4 memory leaks (on the device, running instruments).
The memory leaks seems to come from this code:
NSURL *url = [self getUrl:destination];
[destination release];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"GET"];
[request addValue:#"application/json" forHTTPHeaderField:#"content-type"];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
[request release];
[connection release];
EDIT: added code for getUrl
- (NSURL *)getUrl:(NSString *)actionUrl
{
NSString *rawUri = [[NSString alloc]initWithFormat:#"%#/%#", kBaseUrl, actionUrl];
NSURL *url = [[[NSURL alloc] initWithString:rawUri] autorelease];
[rawUri release];
return url;
}
I am releasing all my objects as far as I can see but it's still showing this as the source of the 4 memory leaks.
This is on the Device running 3.1.3
Is it acceptable to have a few memory leaks in your app or do they all have to go?
EDIT: I've added autorelease to getUrl. However it still shows up with memory leaks
EDIT2: The behaviour is rather strange. I launch the app and hit the button that makes this call once. 4 leaks are discovered. I press back and hit the button again, and keep doing this a few times, and still only 4 leaks. However, if I wait a few seconds and then press the button a gain a few more times, 9 leaks are discovered. It's not a small 128 byte leak, but it's 1.61KB at this point.
EDIT3: Here is the connectionDidFinishLoading
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
SBJSON *jsonParser = [[SBJSON alloc] init];
NSString *jsonString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
[receivedData setLength:0];
[receivedData release];
[self.delegate dataReceived:[jsonParser objectWithString:jsonString]]; // See method below
[jsonParser release];
[jsonString release];
}
The delegate gets the data, then transforms it (and in return passes it on to another delegate once the product is constructed)
- (void)dataReceived:(id)data
{
NSMutableArray *myObjects = [[NSMutableArray alloc]init];
ObjectFactory *objectFactory = [[ObjectFactory alloc]init];
// Only one object
if ([data isKindOfClass:[NSDictionary class]])
{
Object *object = [objectFactory buildObject:data];
[myObjects addObject:object];
[object release];
}
// Multiple objects
if ([data isKindOfClass:[NSArray class]])
{
for (NSDictionary *objectSrc in data)
{
Object *object = [objectFactory buildObject:post];
[myObjects addObject:object];
[object release];
}
}
[objectFactory release];
[self.delegate objectsReceived:myObjects];
}
EDIT4:
Something I did notice is that the object "ConnectionObject" that contains the NSUrlConnection, never seem to be deallocated.
I put a breakpoint on dealloc which calls [connection release]
This dealloc is never called. All the deallocs are called down the chain except for this one.
I tried [connection cancel] in the "connectionDidFinishLoading" call to see if that helped but not at all.
This sure is a mystery to me...
You are releasing something you shouldn't:
NSURL *url = [self getUrl:destination];
// the returned url should have been autoreleased by the getUrl: method
// so you shouldn't release it again
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[url release]; // don't do this!
Remember that you should only release objects that were created using alloc, new or retain . Objects returned from other methods are always in an auoreleased state (by convention).