NSError *theError = nil;
NSArray *keys = [NSArray arrayWithObjects:#"password", #"userId", nil];
NSArray *objects = [NSArray arrayWithObjects:passwordTextField.text, userNameTextField.text, nil];
NSDictionary *requestDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSString *JSONString =[requestDictionary JSONRepresentation];
NSData *JSONData =[JSONString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"JSONString :%#", JSONString);
NSLog(#"JSONData :%#", JSONData);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://153.20.32.74/11AprP306/passenger/jsonitem"]];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:JSONData];
[request setHTTPMethod:#"POST"];
NSURLResponse *theResponse =[[NSURLResponse alloc]init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&theError];
NSLog(#"response : %#", theResponse);
NSLog(#"error : %#", theError);
NSLog(#"data : %#", data);
NSMutableString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"string: %#", string);
[string release];
//[theResponse release]; // this statement crashes the app
Has it got something with to do with this statement :NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&theError];
I see a & symbol used. What does it means?
I'll post this as a new answer as you edited your question.
You are doing it the wrong way.
It is the responsability of sendSynchronousRequest:returningResponse:error: to create the response for you (or the error if something went wrong)
This is why you need to pass a pointer to theResponse and a pointer to theError
When the call to sendSynchronousRequest:returningResponse:error: is done, theResponse will be created and most importantly autoreleased (by sendSynchronousRequest:returningResponse:error) !!
So in the end you are back to the autorelease/over release issue.
The correct code is:
NSURLResponse *theResponse = nil; // no need to init it will be done later on
NSError *theError = nil; // no need to init either
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&theResponse
error:&theError];
if (aError != nil) { } // handle error
else {} // handle your response data
//no need to release theResponse
Well, you autorelease theResponse when you instantiate it, so releasing it twice is causing your problem. Either don't make the autorelease call or don't make the release call.
Personally, I'd get rid of the autorelease. release gives finer-grained control over the run of your program.
Oh, and the & there is nothing to worry about -- it just passes the address of the variable it proceeds. In this case, you need to pas an NSURLResponse**. Since you have an NSURLResponse*, you pass a reference to it.
This is because theResponse has sent the message autorelease in:
NSURLResponse *theResponse =[[[NSURLResponse alloc]init] autorelease];
If you release an object that has been autoreleased you will cause your application to crash for the Garbage Collector will over release the object.
The & simply means "give me the address of theError and theResponse (basically you are passing a pointer of pointer which is required by the method sendSynchronousRequest:returningResponse:error:)
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
returningResponse:(NSURLResponse **)response
error:(NSError **)error
The NSURLResponse ** and NSError ** means 'address of address' so give them only theError or theResponse (without the &) would simply give the method 'their address' when it is expecting something else.
Related
My app crashed (iOS/iPhone) after the execution of the following snippet:
NSHTTPURLResponse *urlResponse = nil;
NSError *error = [[NSError alloc] init];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if ([urlResponse statusCode] ==500 ) {
...
}
} else {
NSLog(#"Response ==> status= %d", [urlResponse statusCode];
}
[result release];
[error release];
The code reached at the else statement, the statusCode is "0" and the code crashes with the
information that [CFError release] was sent to an deallocated instance. I commented out the
line [error release] and the crashed did not happen again. However we introduce a leak here.
What goes wrong with the error variable? Is it being used from sendSynchonousRequest?
What is the optimal way to resolve the problem?
The error object passed to an other method most not be initialized, the method you pass it on to will create the error object if an error accours. Since this method created the error object you are not the owner of that object and you are over releasing the error. The error object is created as autorelease.
Change :
NSError *error = [[NSError alloc] init];
to
NSError *error = nil;
and remove the
[error release];
Its is not necessary create error object. when you set the object to NSURLConnection, it automatic create autorelease error object. thats why your code crash, because there are also error release
try this:
NSHTTPURLResponse *urlResponse = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if ([urlResponse statusCode] ==500 ) {
...
}
} else {
NSLog(#"Response ==> status= %d", [urlResponse statusCode];
}
[result release];
I've got a question about instance variables in combination with blocks & arc in Objective C with IOS5.
Shortly, when i access this code, the iPhone gives me an EXC_BAD_ACCESS and terminates:
- (void) doRequest: (void (^)(XMLTreeNode*) )completionHandler {
NSString * urlString = [NSString stringWithFormat:#"blablaurl=%#&", action];
for( NSString* key in parameters ){
urlString = [urlString stringByAppendingFormat:#"&%#=%#", key, [parameters objectForKey:key]];
}
NSURL * url = [NSURL URLWithString:urlString];
NSLog( #"Visiting: %#", [url absoluteString] );
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"GET"];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * response, NSData * data, NSError * err) {
NSLog( #"Params=%#", parameters );
completionHandler(e);
}];
}
The exc_bad_access occurs on:
NSLog( #"Params=%#", parameters );
(parameters is an instance variable of the class).. Just defined in the header file, no special property or what-so-ever..
Why does it crash and how can i prevent it? Thanks!
My guess is that it crashes because the objects lifetime is over after the doRequest call, and thus ARC cleans up all variables (and with that the parameter var).. When the urlconnection completes and calls the block, the instance variables are aready cleaned up..
parameters is clean up by ARC.
2 case here:
Your main object isn't released before the block completion: Just create an strong,nonatomic property for "parameters". Using the "strong" keyword in your property say to ARC that you need "parameters" during all your main object life
Your main object is released before the block completion: create a new __block pointer to your object
__block blockParameters = parameters;
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * response, NSData * data, NSError * err) {
NSLog( #"Params=%#", blockParameters );
completionHandler(e);
}];
Using the "__block" keyword say to ARC that you need "blockParameters" during all your block life
You have only the parameters of the block at your disposal, i.e. response, data and error in this case. You could use [response URL] to get at the parameters.
NSString *path = [[response URL] path];
NSString *secondPartOfURL = [[path componentsSeparatedByString:#"?"] objectAtIndex:1];
NSArray *keyValuePairs = [secondPartOfURL componentsSeparatedByString#ยด:#"&"];
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
for (NSString *pair in keyValuePairs) {
NSArray *keyValue = [pair componentsSeparatedByString:#"="];
[parameters setValue:[keyValue objectAtIndex:1]
forKey:[keyValue objectAtIndex:0]];
}
NSLog(#"Params=%#", parameters);
Never touched json before. I'm trying to access some variables within the Wunderground weather API for Melbourne. For example, let's say I want to access the "wind_dir":"East" variable. This is my code thus far:
NSString *urlString =
[NSString stringWithFormat:
#"http://api.wunderground.com/api/key/geolookup/conditions/forecast/q/-33.957550,151.230850.json"];
NSLog(#"URL = %#", urlString);
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSArray *weatherInfo = [parser objectWithString:json_string error:nil];
for (NSDictionary *weatherString in weatherInfo)
{
NSLog(#"some weather info = %#", [[[weatherString objectForKey:#"response"] objectForKey:#"current_observation"] objectForKey:#"wind_dir"]);
}
My code reaches the for loop and crashes with this error: -[NSCFString objectForKey:]: unrecognized selector sent to instance.
I'm not 100% sure what's causing the crash, and whether my path to the "wind_dir" variable is correct, though they could well be the same problem.
Thanks in advance for any help.
either the "response" property or the "current_observation" propery is string and not dictionary.
the error you are getting is that you are trying to call "objectForKey" on a string.
after looking at the result of the API, it seems that you are not getting an array.
You should do something like this:
NSDictionary *weatherInfo = [parser objectWithString:json_string error:nil];
NSLog(#"some weather info = %#", [[weatherInfo objectForKey:#"current_observation"] objectForKey:#"wind_dir"]);
instead of your for statement.
Below is my code..
NSString *strResponce = [[NSString alloc] initWithData:JsonData encoding:NSASCIIStringEncoding];
here string has some data.
[JsonData release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
ArrayWebContent=[json objectWithString:strResponce error:&error];
But array is null.
any suggestion....
check your json data first put the content of the string strResponce in to the url
Checking json data are proper for parsing
if it gonna generate the parse error than you should check the content of the ws as it may content special charactor for which iphone can not support parsing
good luck
Try with below functions.
- (id) objectWithUrl:(NSURL *)url
{
SBJSON *jsonParser = [SBJSON new];
NSString *jsonString = [self stringWithUrl:url];
// Parse the JSON into an Object
return [jsonParser objectWithString:jsonString error:NULL];
}
- (NSString *)stringWithUrl:(NSURL *)url
{
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30];
// Fetch the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
// Construct a String around the Data from the response
return [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
}
Let me know for any difficulty.
Should I be retaining the responseData that I am returning
// METHOD
-(NSData *)dataFromTurbine:(NSString *)pathToURL {
NSURL *url = [[NSURL alloc] initWithString:pathToURL];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
[request release];
[url release];
return responseData;
}
.
// CALLED
NSData *newData = dataFromTurbine(kTurbineDataPath);
[doSomething newData];
Since the method name doesn't start with init, new or copy, dataFromTurbine should return an autoreleased instance of NSData. (Which is already true now for responseData)
The calling method then has ownership, and should retain if needed.
In a word, no.
The NSData object you get from NSURLConnection is autoreleased, so you should retain/release it only if you need to keep it. Otherwise, it will be automatically released for you at the next pass of the run loop.