I am trying to use NSURLConnection in asynchronous mode and wait for completion.
During the wait, I use NSRUNLOOP to handle events. Its works in most cases (3G and WIFI)
but the application hangup randomly in GSM DATA and EDGE environment.
My code:
(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
_requestCompleted = TRUE;
CFRunLoopStop(CFRunLoopGetCurrent());
}
(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_response = (NSHTTPURLResponse *)response;
[ _response retain];
}
(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
/* Append the new data to the received data. */
[_receivedData appendData:data];
}
(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
_requestError = error;
NSLog(#"request error - cause : %#", [_requestError localizedDescription ]);
_requestCompleted = TRUE;
[_requestError retain];
CFRunLoopStop(CFRunLoopGetCurrent());
}
(NSString*)downloadFileFromURL:(NSString*)url
{
NSURLRequest *request = nil;
NSString *contents = nil;
NSData *response = nil;
int tries;
NSURLConnection *URLConnection = nil;
int i = 0;
NSDate* dateLimit;
[_mutex lock];
NSLog(#"url = %#", url);
NSString *requestWithEscaping = [ url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ];
request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestWithEscaping]
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
for (tries = 0; tries < HTTP_REQUESTS_TRIES && response == nil ; tries ++) {
[_receivedData setLength:0];
_requestCompleted = FALSE;
_requestError = nil;
_requestTimeout = FALSE;
if (URLConnection == nil)
URLConnection = [ NSURLConnection connectionWithRequest:request delegate:self];
else {
[URLConnection cancel ];
[URLConnection start];
}
if (URLConnection == nil) {
NSLog(#"No connection ! maybe mistake in Request Format ?");
continue;
}
for (i = 0; ; i++) {
dateLimit = [[NSDate date] addTimeInterval:INTERVALL_LOOP];
[ [NSRunLoop currentRunLoop] runUntilDate:dateLimit];
if (_requestCompleted == TRUE)
break;
if (i > (int)(HTTP_TIMEOUT_FIRE * (1 / INTERVALL_LOOP))) {
_requestTimeout = TRUE;
break;
}
}
if (_requestTimeout) {
[ URLConnection cancel];
NSLog(#"request timeout");
continue;
}
if (_requestError) {
NSLog(#"request error");
continue;
}
NSLog(#"Request success");
break;
}
if (_requestTimeout) {
_lastErrorType = ServicesRequestManager_error_Network;
[ _lastErrorString setString:#"Délai de connexion depassé"];
[ _mutex unlock];
return nil;
}
if (_requestError) {
NSLog(#"ERROR Cannot get %# - cause : %#",url, [ _requestError localizedDescription ]);
_lastErrorType = ServicesRequestManager_error_Network;
[_lastErrorString setString:#"Impossible de se connecter" ];
[ _mutex unlock];
return nil;
}
if ([ _response statusCode] != 200 ) {
NSLog(#"ERROR Download file %# HTTP response - code : %d", url, [ _response statusCode]);
[_lastErrorString setString:[ NSString stringWithFormat:#"Error http code : %d", [_response statusCode]]];
_lastErrorType = ServicesRequestManager_error_Service;
[_lastErrorString setString:#"Le service n'est pas disponible actuellement" ];
[ _mutex unlock];
return nil;
}
contents = [[NSString alloc] initWithData:_receivedData encoding:NSUTF8StringEncoding];
[ _mutex unlock];
return contents;
}
NSURLConnection is already asynchronous. Simply implement the delegate methods. If you want to update the UI on the MainThread (e.g. a progress bar), you can do so in didReceiveData.
I use NSNotificationor that puspose. In DidFinishLoading method post a notification,
[[NSNotificationCenter defaultCenter] postNotificationName:#"Name" object:someObject];
and handle this notification in anyclass by
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleMethod:) notificationName:#"Name" object:nil];
and implement
-(void)handleMethod:(NSNotification *)ntf
Related
I am working on one of my projects which is in maintenance phase so I do not have much liberty to change a major chunk at one go, While working on this I get to see this random crash on both Simulator as well as Device while the application Syncs with server. The Flow being
Login-> Upload Local Data to Server -> Download data from Server.
The only point upto which I am able to debug is the screenshot I have attached from which I am not able to draw much of any inferences.
The Network communication is facilitated via a Custom Class which is as follows
httpClient.h -------
#define TIMEOUT_SEC 30.0
#protocol HttpClientEventHandler_iPhone
#optional
- (void)requestSucceeded;
- (void)requestFailed:(NSError*)error;
#end
#class Reachability;
#interface HttpClient_iPhone : NSObject{
NSURLConnection *connection;
NSMutableData *recievedData;
int statusCode;
id delegate;
Reachability* hostReachable;
BOOL networkChecked;
}
#property (nonatomic, retain) NSMutableString *previousRequest;
#property (readonly) NSMutableData *recievedData; // XX should be (readonly, retain)
#property (readonly) int statusCode;
#property (nonatomic, assign) id delegate;
+ (NSString*)stringEncodedWithBase64:(NSString*)str;
+ (NSString*) stringOfAuthorizationHeaderWithUsername:(NSString*)username password:(NSString*)password;
- (NSMutableURLRequest*)makeRequest:(NSString*)url;
- (NSMutableURLRequest*)makeRequest:(NSString*)url username:(NSString*)username password:(NSString*)password;
- (void)prepareWithRequest:(NSMutableURLRequest*)request;
- (void)requestGET:(NSString*)url;
- (void)requestPOST:(NSString*)url body:(NSString*)body type:(NSString*)type;
- (void)requestGET:(NSString*)url username:(NSString*)username password:(NSString*)password;
- (void)requestPOST:(NSString*)url username:(NSString*)username password:(NSString*)password body:(NSString*)body type:(NSString*)type;
- (void)requestPOST:(NSString*)url username:(NSString*)username password:(NSString*)password bodydata:(NSData*)body contenttype:(NSString*)type;
- (void)uploadImage:(NSString*)requesturl
username:(NSString*)username
password:(NSString*)password
imagename:(NSString*)imagename
contenttype:(NSString*)contenttype
imagedata:(NSData*)imagedata;
- (void)cancelTransaction;
- (void)reset;
- (BOOL)checkNetworkStatus;
#end
//HttpClient.m -----------
#import "HttpClient_iPhone.h"
#import "Base64.h"
#import "Reachability.h"
#import "SyncLiteral.h"
#implementation HttpClient_iPhone
#synthesize recievedData, statusCode;
#synthesize delegate,previousRequest;
- (id)init {
if (self = [super init]) {
[self reset];
delegate = nil;
networkChecked = NO;
}
return self;
}
- (void)dealloc {
[connection release];
[recievedData release];
[super dealloc];
}
- (void)reset {
[recievedData release];
recievedData = [[NSMutableData alloc] init];
[connection release];
connection = nil;
statusCode = 0;
networkChecked = NO;
}
+ (NSString*)stringEncodedWithBase64:(NSString*)str {
static const char *tbl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char *s = [str UTF8String];
int length = [str length];
char *tmp = malloc(length * 4 / 3 + 4);
int i = 0;
int n = 0;
char *p = tmp;
while (i < length) {
n = s[i++];
n *= 256;
if (i < length) n += s[i];
i++;
n *= 256;
if (i < length) n += s[i];
i++;
p[0] = tbl[((n & 0x00fc0000) >> 18)];
p[1] = tbl[((n & 0x0003f000) >> 12)];
p[2] = tbl[((n & 0x00000fc0) >> 6)];
p[3] = tbl[((n & 0x0000003f) >> 0)];
if (i > length) p[3] = '=';
if (i > length + 1) p[2] = '=';
p += 4;
}
*p = '\0';
NSString *ret = [NSString stringWithCString:(const char*)tmp encoding: NSUTF8StringEncoding];
free(tmp);
return ret;
}
#pragma mark - HTTP Request creating methods
- (NSMutableURLRequest*)makeRequest:(NSString*)url {
NSString *encodedUrl = (NSString*)CFURLCreateStringByAddingPercentEscapes(
NULL, (CFStringRef)url, NULL, NULL, kCFStringEncodingUTF8);
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:encodedUrl]];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
[request setTimeoutInterval:TIMEOUT_SEC];
[request setHTTPShouldHandleCookies:FALSE];
[encodedUrl release];
return request;
}
- (NSMutableURLRequest*)makeRequest:(NSString*)url username:(NSString*)username password:(NSString*)password {
NSMutableURLRequest *request = [self makeRequest:url];
[request setValue:[HttpClient_iPhone stringOfAuthorizationHeaderWithUsername:username password:password]
forHTTPHeaderField:#"Authorization"];
return request;
}
+ (NSString*) stringOfAuthorizationHeaderWithUsername:(NSString*)username password:(NSString*)password {
return [#"Basic " stringByAppendingString:[HttpClient_iPhone stringEncodedWithBase64:
[NSString stringWithFormat:#"%#:%#", username, password]]];
}
- (void)prepareWithRequest:(NSMutableURLRequest*)request {
// do nothing (for OAuthHttpClient)
}
#pragma mark -
#pragma mark HTTP Transaction management methods
/* Sending the Http Request for "GET" */
- (void)requestGET:(NSString*)url {
//Reseting the http client
[self reset];
//Checking the internet connection
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
//Sending the http requqest
NSMutableURLRequest *request = [self makeRequest:url];
[self prepareWithRequest:request];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"GET Requested API - %#\n",url];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
/* Sending the Http Request for "POST" */
- (void)requestPOST:(NSString*)url body:(NSString*)body type:(NSString*)type {
//Reseting the http client
[self reset];
//Checking the internet connection
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
//Sending the http requqest
NSMutableURLRequest *request = [self makeRequest:url];
[request setHTTPMethod:#"POST"];
if (type != nil && ![type isEqualToString:#""])
[request setValue:type forHTTPHeaderField:#"Content-Type"];
if (body) {
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
}
[self prepareWithRequest:request];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"Post Requested API - %#\n",url];
[self.previousRequest appendFormat:#"Post Data - %#\n",body];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
/* Sending the Http Request for "GET" with username and password */
- (void)requestGET:(NSString*)url username:(NSString*)username password:(NSString*)password {
//Reseting the http client
[self reset];
//Checking the internet connection
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
//Sending the http requqest
NSMutableURLRequest *request = [self makeRequest:url username:username password:password];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"Post Requested API - %#\n",url];
[self.previousRequest appendFormat:#"Authorization user - %#\n",username];
[self.previousRequest appendFormat:#"Authorizating password - %#\n",password];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
/* Sending the Http Request for "POST" with username and password */
- (void)requestPOST:(NSString*)url username:(NSString*)username password:(NSString*)password body:(NSString*)body type:(NSString*)type {
//Reseting the http client
[self reset];
//Checking the internet connection
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
//Sending the http requqest
NSMutableURLRequest *request = [self makeRequest:url username:username password:password];
[request setHTTPMethod:#"POST"];
if (type != nil && ![type isEqualToString:#""])
[request setValue:type forHTTPHeaderField:#"Content-Type"];
if (body) {
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
}
[self prepareWithRequest:request];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"Post Requested API - %#\n",url];
[self.previousRequest appendFormat:#"Authorization user - %#\n",username];
[self.previousRequest appendFormat:#"Authorizating password - %#\n",password];
[self.previousRequest appendFormat:#"Post Data - %#\n",body];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
/* Sending the Http Request for "POST" with username and password */
- (void)requestPOST:(NSString*)url username:(NSString*)username password:(NSString*)password bodydata:(NSData*)body contenttype:(NSString*)type {
//Reseting the http client
[self reset];
//Checking the internet connection
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
//Sending the http requqest
NSMutableURLRequest *request = [self makeRequest:url username:username password:password];
[request setHTTPMethod:#"POST"];
if (type != nil && ![type isEqualToString:#""])
[request setValue:type forHTTPHeaderField:#"Content-Type"];
if (body) {
[request setHTTPBody:body];
}
if (body != nil && [body length] > 0){
NSString* length_str = [NSString stringWithFormat:#"%d", [body length]];
[request setValue:length_str forHTTPHeaderField:#"Content-Length"];
}
[self prepareWithRequest:request];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"Post Requested API - %#\n",url];
[self.previousRequest appendFormat:#"Authorization user - %#\n",username];
[self.previousRequest appendFormat:#"Authorizating password - %#\n",password];
[self.previousRequest appendFormat:#"Post Data - %#\n",[[[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]autorelease]];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
/* Sending the Http Request for uploading the image from database */
- (void)uploadImage:(NSString*)requesturl
username:(NSString*)username
password:(NSString*)password
imagename:(NSString*)imagename
contenttype:(NSString*)contenttype
imagedata:(NSData*)imagedata {
//Reseting the http client
[self reset];
//Checking the internet connection
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
//Sending the http requqest
NSString *boundary = #"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
NSURL *url = [NSURL URLWithString:requesturl];
NSMutableURLRequest *request = [self makeRequest:requesturl username:username password:password];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
NSMutableData *postbody = [NSMutableData data];
[postbody appendData:[[NSString stringWithFormat:#"--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[[NSString stringWithFormat:#"Content-Disposition: form-data; name=\"uploadfile\"; filename=\"%#\"\r\n", imagename] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[#"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
NSData* encoded_data = [Base64 encode:imagedata];
[postbody appendData:[NSData dataWithData:encoded_data]];
[postbody appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[encoded_data release];
[request setHTTPBody:postbody];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
/* Canceling the HTTP Transaction */
- (void)cancelTransaction {
[connection cancel];
[self reset];
}
#pragma mark -
#pragma mark NSURLConnectionDelegate methods
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
return nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
statusCode = [(NSHTTPURLResponse*)response statusCode];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[recievedData appendData:data];
#ifdef _DEBUG
NSLog(#"Receieved the http body data : \n%#\n", [[[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding] autorelease]);
#endif
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
#ifdef DEBUG
NSLog(#"Receieved the http body data : \n%#\n", [[[NSString alloc] initWithData:recievedData
encoding:NSASCIIStringEncoding] autorelease]);
#endif
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestSucceeded)]){
[self.delegate performSelector:#selector(requestSucceeded) withObject:nil];
}
[self reset];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError*) error {
#ifdef _DEBUG
NSLog(#"didFailWithError \n %#",[error description]);
#endif
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:error];
}
[self reset];
}
//check network status chages
- (BOOL)checkNetworkStatus {
BOOL result = NO;
Reachability* reachability = [Reachability reachabilityWithHostName:SERVER_ADDRESS];
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];
if(remoteHostStatus == NotReachable) {
#ifdef _DEBUG
NSLog(#"\nNetwork Status : not reachable\n");
#endif
result = NO;
}else if (remoteHostStatus == ReachableViaWWAN) {
#ifdef _DEBUG
NSLog(#"\nNetwork Status : reachable via wwan\n");
#endif
result = YES;
}else if (remoteHostStatus == ReachableViaWiFi) {
#ifdef _DEBUG
NSLog(#"\nNetwork Status : reachable via wifi\n");
#endif
result = YES;
}
return result;
}
#end
If someone could guide me in right direction it will be of great help. The Project makes use of SDK 6.1 with Deployment target 4.3.
// EDIT to my question
The current implementation is as follows
#interface HttpClient_iPhone : NSObject{
NSURLConnection *connection;
NSMutableData *recievedData;
int statusCode;
id delegate;
Reachability* hostReachable;
BOOL networkChecked;
}
#property (retain,atomic) NSMutableString *previousRequest;
#property (retain,readonly) NSMutableData *recievedData;
#property (readonly) int statusCode;
#property (nonatomic, assign) id delegate;
It's corresponding .m is now
#implementation HttpClient_iPhone
#synthesize recievedData, statusCode;
#synthesize delegate,previousRequest;
- (id)init {
if (self = [super init]) {
[self reset];
delegate = nil;
networkChecked = NO;
}
return self;
}
- (void)dealloc {
if (connection) {
[connection cancel];
}
[connection release];
connection = nil;
if (recievedData) {
[recievedData release];
recievedData = nil;
}
[super dealloc];
}
- (void)reset {
if (recievedData) {
[recievedData release];
recievedData = nil;
}
recievedData = [[NSMutableData alloc] init];
if (connection) {
[connection cancel];
[connection release];
connection = nil;
}
statusCode = 0;
networkChecked = NO;
}
- (void)requestGET:(NSString*)url {
//Reseting the http client
[self reset];
//Checking the internet connection
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
NSMutableURLRequest *request = [self makeRequest:url];
[self prepareWithRequest:request];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"GET Requested API - %#\n",url];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
- (void)requestPOST:(NSString*)url body:(NSString*)body type:(NSString*)type {
[self reset];
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
NSMutableURLRequest *request = [self makeRequest:url];
[request setHTTPMethod:#"POST"];
if (type != nil && ![type isEqualToString:#""])
[request setValue:type forHTTPHeaderField:#"Content-Type"];
if (body) {
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
}
[self prepareWithRequest:request];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"Post Requested API - %#\n",url];
[self.previousRequest appendFormat:#"Post Data - %#\n",body];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)requestGET:(NSString*)url username:(NSString*)username password:(NSString*)password {
[self reset];
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
NSMutableURLRequest *request = [self makeRequest:url username:username password:password];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"Post Requested API - %#\n",url];
[self.previousRequest appendFormat:#"Authorization user - %#\n",username];
[self.previousRequest appendFormat:#"Authorizating password - %#\n",password];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
- (void)requestPOST:(NSString*)url username:(NSString*)username password:(NSString*)password body:(NSString*)body type:(NSString*)type {
[self reset];
if ([self checkNetworkStatus] == NO){
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:nil];
}
return;
}
NSMutableURLRequest *request = [self makeRequest:url username:username password:password];
[request setHTTPMethod:#"POST"];
if (type != nil && ![type isEqualToString:#""])
[request setValue:type forHTTPHeaderField:#"Content-Type"];
if (body) {
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
}
[self prepareWithRequest:request];
if(![[url lastPathComponent] isEqualToString:#"pda_errorlogs"])
self.previousRequest = [NSMutableString string];
[self.previousRequest appendFormat:#"Post Requested API - %#\n",url];
[self.previousRequest appendFormat:#"Authorization user - %#\n",username];
[self.previousRequest appendFormat:#"Authorizating password - %#\n",password];
[self.previousRequest appendFormat:#"Post Data - %#\n",body];
[self.previousRequest appendFormat:#"\n\n\n"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)requestPOST:(NSString*)url username:(NSString*)username password:(NSString*)password bodydata:(NSData*)body contenttype:(NSString*)type {
[self reset];
}
- (void)cancelTransaction {
[self reset];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
statusCode = [(NSHTTPURLResponse*)response statusCode];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[recievedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestSucceeded)]){
[self.delegate performSelector:#selector(requestSucceeded) withObject:nil];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError*) error {
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(requestFailed:)]){
[self.delegate performSelector:#selector(requestFailed:) withObject:error];
}
}
// Images for Crash Logs as reported on Crashlytics
Part 1 of 2
Part 2 of 2
Two comments:
1) change the recievedData property type in the header to "retain" (even though its not used as a property in your code)
2) before you release a NSURLConnection, you should send it cancel, ie [connection cancel]. You release it in dealloc and in reset. Also, make that cancel the first thing you do - don't go releasing data that might be used by it beforehand.
EDIT: based on your current code, your reset method still does cancel before it modifies the mutable data. I modified your code as you can see below, to mirror your dealloc method (where you don't need the nil statement):
- (void)reset {
if (connection) {
[connection cancel];
[connection release];
connection = nil;
}
if (recievedData) {
[recievedData release];
recievedData = nil;
}
recievedData = [[NSMutableData alloc] init];
statusCode = 0;
networkChecked = NO;
}
- (void)dealloc {
if (connection) {
[connection cancel];
[connection release];
}
if (recievedData) {
[recievedData release];
}
[super dealloc];
}
Try that.
Run instruments with the Zombies instrument. Most of the time this will give you everything you need to troubleshoot an issue like this, though sometimes if you're hitting a bug deep within the framework it's not of much help. Looking at the information you've provided that is POSSIBLE but isn't likely. Adding a crash log would help.
I would move away from using ivars and switch to using synthesized properties. Direct ivar access should only be done in init and dealloc - everywhere else, use the property.
Make sure you have a good reason to implement an NSURLConnection delegate. If sendAsynchronousRequest:queue:completionHandler: meets your needs, use that - you won't have to deal with the complexities of a delegate. I have seen an awful lot of crashes occur because of mistakes made when people implement connection:didReceiveData: to buffer into an NSMutableData instance, or not handling cancel correctly (after cancel is called you will not get any more delegate callbacks - which may prevent your delegate from cleaning up properly).
I see you are taking a username and password for each of these requests and it looks like you are building your own HTTP Basic authentication header.
Don't.
Instead use NSURLCredential to manage the authentication credentials. When NSURLConnection gets an authentication challenge it will look at the NSURLCredentialStorage for a credential to apply. This is seamless to your application and will save you a lot of potential pain.
Here is a short example of how to create and set a credential. You only need to do this once, not for each connection:
NSURLCredential *credential = nil;
NSURLProtectionSpace *protectionSpace = nil;
protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:[url host] port:[[url port] integerValue] protocol:[url scheme] realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic];
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace];
[protectionSpace release];
Note that you have different persistence options available to you, NSURLCredentialPersistencePermanent will store the credential in the keychain permanently (you can remove it later if you want).
I need to make multiple NSURLConnections to a JSON Web Service. I would like each WS call to keep in UI informed, probably with a UIActivityIndicatorView and label. So far I've created a NSURLConnection helper class to handle the connection and placed the URL delegates in the View. This works great for updating the UI with a single WS call.
For multiple calls, I'm trying to use an NSOperationQueue. I'd like to setMaxConcurrentOperationCount to one on the queue so that each Operation executes one at a time. Here's the relevant code on my View Controller:
ViewController.m
#import "URLOperationHelper.h"
#implementation ViewController
- (IBAction)showPopup:(id)sender
{
// Dictonary holds POST values
NSMutableDictionary *reqDic = [NSMutableDictionary dictionary];
// Populate POST key/value pairs
[reqDic setObject:#"pw" forKey:#"Password"];
[reqDic setObject:#"ur" forKey:#"UserName"];
operationQueue = [[NSOperationQueue alloc] init];
[operationQueue setMaxConcurrentOperationCount:1];
[operationQueue cancelAllOperations];
[operationQueue setSuspended:YES];
URLOperationHelper *wsCall1 = [[URLOperationHelper alloc] initWithURL:#"urlString1" postParameters:reqDic urlDelegate:self];
URLOperationHelper *wsCall2 = [[URLOperationHelper alloc] initWithURL:#"urlString2" postParameters:reqDic urlDelegate:self];
[operationQueue addOperation:wsCall1];
[operationQueue addOperation:wsCall2];
}
// Did the URL Connection receive a response
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"Did receive response: %#", response);
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode];
// Handle status code here
webData = [[NSMutableData alloc]init];
}
// Did the URL Connection receive data
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"Did receive data: %#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
assert(webData != nil);
[webData appendData:data];
}
// Did the connection fail with an error?
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"%#", error);
}
// Executes after a successful connection and data download
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Connection finished");
}
#end
And here is my URLOperationHelper.m
#implementation URLHelper
- (id)initWithURL:(NSString *)urlPath
postParameters:(NSMutableDictionary *)postParameters
urlParentDelegate:(id) pDelegate
{
if(self = [super init])
{
connectionURL = urlPath;
postParams = postParameters;
parentDelegate = pDelegate;
}
return self;
}
- (void)done
{
// Cancel the connection if present
if(urlConnection)
{
[urlConnection cancel];
urlConnection = nil;
}
// Alert
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
executing = NO;
finished = YES;
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
}
- (void)cancel
{
// Possibly add an NSError Property
[self done];
}
- (void)start
{
// Make sure this operation starts on the main thread
if(![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
// Make sure that the operation executes
if(finished || [self isCancelled])
{
[self done];
return;
}
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
[self main];
[self willChangeValueForKey:#"isExecuting"];
}
- (void)main
{
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:postParams options:NSJSONWritingPrettyPrinted error:&error];
// Convert dictionary to JSON
NSString *requestJSON = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"JSONRequest: %#", requestJSON);
// Declare Webservice URL, request, and return data
url = [[NSURL alloc] initWithString:connectionURL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSData *requestData = [NSData dataWithBytes:[requestJSON UTF8String] length:[requestJSON length]];
// Build the request
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:requestData];
// Connect to Webservice
// Responses are handled in the delegates below
urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:parentDelegate startImmediately:YES];
}
- (BOOL)isConcurrent
{
return YES;
}
- (BOOL)isExecuting
{
return executing;
}
-(BOOL)isFinished
{
return finished;
}
#end
The problem that I'm having is the Start method for the URLOperation is never called. The OperationQueue is created and the Operations are called, but nothing happens after that, execution or thread wise.
Also, is this a correct line of thinking to provide UI feedback using NSOperationQueues like this? I.E. calling the NSURLDelegates from the Operation?
If you set setSuspended to YES before adding the Operations then your Operations will be queued into a suspended queue.. i suggest not to suspend the queue at
furthermore, your operation never ends anyway. You need to assign the operation itself as the delegate and implement all necessary delegate methods. In these methods you can forward the messages to your parentDelegate and decide when you are finished and call your done method when appropriate (i suggest connection:didFailWithError: and connectionDidFinishLoading:)
There is a good tutorial here: http://blog.9mmedia.com/?p=549
You are also not completely implementing key-value-coding compilant properties correct. Whenever you call willChangeValueForKey: you also need to call didChangeValueForKey afterwards:
- (void)start
{
...
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
[self didChangeValueForKey:#"isExecuting"];
[self main];
}
and:
- (void)done
{
...
// Alert
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
executing = NO;
finished = YES;
[self didChangeValueForKey:#"isFinished"];
[self didChangeValueForKey:#"isExecuting"];
}
See this Q/A for KVC: when to use "willChangeValueForKey" and "didChangeValueForKey"?
I am a fresher. I don't know how to use JSON for Parsing .I am really very confuse because the tutorial i have read are out dated because apple has deprecated all the API's and documents .Thats what i found .So anyone can give me the start to play with JSON?
You can use SBJSON
You can find code at GITHUB
Here's some links on "Picking the best JSON library":
Comparison of JSON Parser for Objective-C (JSON Framework, YAJL, TouchJSON, etc)
Best JSON library to use when developing an iPhone application?
And now for the shameless plug for my own JSON parsing solution, JSONKit:
What's the most efficient way of converting a 10 MB JSON response into an NSDictionary?
Cocoa JSON parsing libraries, part 2
You need to use third-party code to parse JSON. Three popular libraries/frameworks are:
SBJSON, aka json-framework
TouchJSON
yajl-objc
Choose one of them, download its source code and add it do your project.
You can use your custom framwork for it just as below
#import <Foundation/Foundation.h>
#import "SVProgressHUD.h"
#protocol JsonDataDelegate <NSObject>
#required
- (void) JsonprocessSuccessful: (NSString *)receivedData;
-(void) JsonprocessFail;
#end
#interface JsonRest : NSObject
{
id <JsonDataDelegate> delegate;
NSURLConnection *theConnection;
NSMutableData *webData;
BOOL HadGotResponse;
BOOL HasFailedConnection;
UIAlertView *alert;
}
#property (retain) id delegate;
#property(nonatomic,retain) NSURLConnection *theConnection;
#property (nonatomic)BOOL HadGotResponse;
#property (nonatomic)BOOL HasFailedConnection;
-(void)GetServiceCall:(NSString *)url Paraqmeter:(NSString*)parameter;
-(void)Set2Defaults;
#end
#import "JsonRest.h"
#define BASE_URL #"http://www.abc.com"
#define DOMAIN #"GETLIST"
#implementation JsonRest
#synthesize delegate,HadGotResponse,HasFailedConnection,theConnection;
- (id)init
{
if (self)
{
// Initialization code.
//appdel = (ReachCastAppDelegate*)[[UIApplication sharedApplication]delegate];
}
return self;
}
-(void)GetServiceCall:(NSString *)url Paraqmeter:(NSString*)parameter
{
[SVProgressHUD startActivity : #"Loading..."];
NSString *strUrl=[NSString stringWithFormat:#"%#%#?%#",BASE_URL,url,parameter];
NSURL *url1=[NSURL URLWithString:strUrl];
NSLog(#"domainURL :: %#",strUrl);
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url1];
[req setTimeoutInterval:60.0];
[req setHTTPMethod:#"GET"];
// if([HttpMethod isEqualToString:#"GET"])
// {
// [req setHTTPMethod:HttpMethod];
//
// }
// else if([HttpMethod isEqualToString:#"PUT"])
// {
// NSData *requestData = [NSData dataWithBytes: [BodyString UTF8String] length: [BodyString length]];
//
// [req setValue:valueforput forHTTPHeaderField:#"Content-type"];
// [req setHTTPMethod:HttpMethod];
// [req setHTTPBody: requestData];
//
// }
// else if ([HttpMethod isEqualToString:#"POST"]){
//
// NSData *requestData = [NSData dataWithBytes: [BodyString UTF8String] length: [BodyString length]];
//
// [req setValue:valueforput forHTTPHeaderField:#"Content-type"];
// [req setHTTPMethod:HttpMethod];
// [req setHTTPBody: requestData];
//
// }
if(theConnection)
[self Set2Defaults];
theConnection=[[NSURLConnection alloc]initWithRequest:req delegate:self];
if(theConnection)
webData=[[NSMutableData data]retain];
else
NSLog(#"Connection Failed !!!");
NSLog(#"Has got response");
}
-(void)Set2Defaults {
if (webData != nil){
[webData release];
webData = nil;
}
if (theConnection != nil) {
[theConnection release];
if (theConnection != nil)
theConnection = nil;
}
}
#pragma mark -
#pragma mark NSURL Connection Delegate methods
-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *) respons{
[webData setLength: 0];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)respons;
int statusCode = [httpResponse statusCode];
NSLog(#"statusCode ---- >> %d",statusCode);
if (200 != statusCode) {
// if (401 == statusCode) {
}
}
-(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data {
[webData appendData:data];
}
-(void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error {
[SVProgressHUD stopActivity];
[self Set2Defaults];
self.HadGotResponse=NO;
self.HasFailedConnection=YES;
// txtWindSpeed.text = #"";
[[self delegate] JsonprocessFail];
NSLog(#"Connection Failed!!!");
//[self HideLoadingDialogue];
alert = [[[UIAlertView alloc] initWithTitle:#"ERROR" message:#"Internet Connection Failed.Please try again." delegate:self cancelButtonTitle:nil otherButtonTitles:nil] autorelease];
//alert.frame=CGRectMake(alert.frame.origin.x, alert.frame.origin.y, alert.frame.size.width, 130);
NSLog(#"%F",alert.frame.origin.y);
[alert show];
alert.frame=CGRectMake(alert.frame.origin.x, alert.frame.origin.y+25, alert.frame.size.width, 130);
//[noConnect release];
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(timerCall) userInfo:nil repeats:NO];
}
-(void)timerCall
{
[alert dismissWithClickedButtonIndex:0 animated:TRUE];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[SVProgressHUD stopActivity];
self.HasFailedConnection=NO;
NSString *theXML;
theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSASCIIStringEncoding];
//NSLog(#"theXML Values : %#", theXML);
//self.ResponseDict = [theXML JSONValue];
[[self delegate] JsonprocessSuccessful:theXML];
[theXML release];
}
-(void)dealloc
{
if (webData != nil){
[webData release];
webData = nil;
}
if (theConnection != nil) {
[theConnection release];
if (theConnection != nil)
theConnection = nil;
}
[super dealloc];
// [ResponseDict release];
}
#end
You can use this using below
-(void)getJsonCalling
{
#try {
NSString *strParameter=[NSString stringWithFormat:#"param1=%#¶m2=%#",param1,param2];
objJsonRest=[[JsonRest alloc]init];
[objJsonRest setDelegate:self];
[objJsonRest GetServiceCall:DOMAIN Paraqmeter:strParameter];
[objJsonRest release];
}
#catch (NSException *exception) {
NSLog(#"Exception in %s %#",__FUNCTION__,exception);
}
}
- (void) JsonprocessSuccessful: (NSString *)receivedData
{
}
-(void) JsonprocessFail;
{
NSLog(#"FAIL");
}
I need to use an NSTimer to cancel my NSURLRequest before 75 seconds (the time I measured regardless of the timeout I set). I'm using the XMLRPC classes by Eric Czarny. The XMLRPCConnection is basically an image of the NSURLConnection class.
Here's the interface and the implementation file:
#import <Foundation/Foundation.h>
#class XMLRPCRequest, XMLRPCResponse;
/* XML-RPC Connecion Notifications */
extern NSString *XMLRPCRequestFailedNotification;
extern NSString *XMLRPCSentRequestNotification;
extern NSString *XMLRPCReceivedResponseNotification;
#interface XMLRPCConnection : NSObject {
NSURLConnection *_connection;
NSString *_method;
NSMutableData *_data;
id _delegate;
UIViewController* _requester;
}
#property(nonatomic, retain) NSMutableData* _data;
- (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate;
- (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate requester:(UIViewController*)requester;
- (void) timedOut;
#pragma mark -
+ (XMLRPCResponse *)sendSynchronousXMLRPCRequest: (XMLRPCRequest *)request;
#pragma mark -
- (void)cancel;
#end
#pragma mark -
#interface NSObject (XMLRPCConnectionDelegate)
- (void)connection: (XMLRPCConnection *)connection didReceiveResponse: (XMLRPCResponse *)response
forMethod: (NSString *)method;
- (void)connection: (XMLRPCConnection *)connection didFailWithError: (NSError *)error
forMethod: (NSString *)method;
#end
Implementation file:
#import "XMLRPCConnection.h"
#import "XMLRPCRequest.h"
#import "XMLRPCResponse.h"
NSString *XMLRPCRequestFailedNotification = #"XML-RPC Failed Receiving Response";
NSString *XMLRPCSentRequestNotification = #"XML-RPC Sent Request";
NSString *XMLRPCReceivedResponseNotification = #"XML-RPC Successfully Received Response";
#interface XMLRPCConnection (XMLRPCConnectionPrivate)
- (void)connection: (NSURLConnection *)connection didReceiveData: (NSData *)data;
- (void)connection: (NSURLConnection *)connection didFailWithError: (NSError *)error;
- (void)connectionDidFinishLoading: (NSURLConnection *)connection;
- (void) timedOut;
#end
#pragma mark -
#implementation XMLRPCConnection
#synthesize _data;
- (id)initWithXMLRPCRequest: (XMLRPCRequest *)request delegate: (id)delegate requester:(UIViewController*)requester {
if (self = [super init])
{
_connection = [[NSURLConnection alloc] initWithRequest: [request request] delegate: self];
_delegate = delegate;
_requester = requester;
// set the timer for timed out requests here
NSTimer* connectionTimer = [NSTimer timerWithTimeInterval:10.0f target:self selector:#selector(timedOut) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:connectionTimer forMode:NSDefaultRunLoopMode];
if (_connection != nil)
{
_method = [[NSString alloc] initWithString: [request method]];
_data = [[NSMutableData alloc] init];
[[NSNotificationCenter defaultCenter] postNotificationName:
XMLRPCSentRequestNotification object: nil];
}
else
{
if ([_delegate respondsToSelector: #selector(connection:didFailWithError:forMethod:)])
{
[_delegate connection: self didFailWithError: nil forMethod: [request method]];
}
return nil;
}
}
return self;
}
- (void) timedOut {
NSLog(#"connection timed out now!");
}
#pragma mark -
+ (XMLRPCResponse *)sendSynchronousXMLRPCRequest: (XMLRPCRequest *)request
{
NSURLResponse *urlres;
//NSHTTPURLResponse *urlres;
NSError *err = NULL;
// set the timer for timed out requests here
NSTimer* connectionTimer = [NSTimer timerWithTimeInterval:10.0f target:self selector:#selector(timedOut) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:connectionTimer forMode:NSDefaultRunLoopMode];
NSData *data = [NSURLConnection sendSynchronousRequest: [request request]
returningResponse: &urlres error: &err];
if ([urlres isKindOfClass:[NSHTTPURLResponse class]]) {
NSLog(#"Received status code: %d %#", [(NSHTTPURLResponse *) urlres statusCode],
[NSHTTPURLResponse localizedStringForStatusCode:[(NSHTTPURLResponse *) urlres statusCode]]) ;
NSDictionary* headerFields = [(NSHTTPURLResponse*)urlres allHeaderFields];
NSArray* cookie = [NSHTTPCookie cookiesWithResponseHeaderFields:headerFields forURL:[request host]];
if ([cookie count] != 0) {
NSString* cookieName = [[cookie objectAtIndex:0] name];
NSString* cookieValue = [[cookie objectAtIndex:0] value];
NSLog(#"cookie name=value: %#=%#", cookieName, cookieValue );
[[User getInstance] setCookieID:[NSString stringWithFormat:#"%#=%#", cookieName, cookieValue] ];
} else {
NSLog(#"cookie array empty!");
}
}
// if an error occured while processing the request, this variable will be set
if( err != NULL )
{
//TODO: we may need to create a XMLRPCResponse with the error. and return
return (id) err;
}
if (data != nil)
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"response is: %#",str);
if ( ! str ) {
str = [[NSString alloc] initWithData:data encoding:[NSString defaultCStringEncoding]];
data = [str dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
}
//Check for HTML code 400 or greater in response statusCode (from header) and throw error if so
if ([urlres isKindOfClass:[NSHTTPURLResponse class]]) {
// HTTP codes equal or higher than 400 signifies an error
if ([(NSHTTPURLResponse *) urlres statusCode] >= 400) {
// NSLog(#"Received status code: %d %#", [(NSHTTPURLResponse *) urlres statusCode],
// [NSHTTPURLResponse localizedStringForStatusCode:[(NSHTTPURLResponse *) urlres statusCode]]) ;
NSString *errorIntString = [NSString stringWithFormat:#"%d", [(NSHTTPURLResponse *) urlres statusCode]];
NSString *stringForStatusCode = [NSHTTPURLResponse localizedStringForStatusCode:[(NSHTTPURLResponse *) urlres statusCode]];
NSString *errorString = [[errorIntString stringByAppendingString:#" "] stringByAppendingString:stringForStatusCode];
NSInteger code = -1; //This is not significant, just a number with no meaning
NSDictionary *usrInfo = [NSDictionary dictionaryWithObject:errorString forKey:NSLocalizedDescriptionKey];
err = [NSError errorWithDomain:#"org.wordpress.iphone" code:code userInfo:usrInfo];
return (id) err;
}
}
//[str release];
return [[[XMLRPCResponse alloc] initWithData: data] autorelease];
}
return nil;
}
#pragma mark -
- (void)cancel
{
[_connection cancel];
[_connection autorelease];
}
#pragma mark -
- (void)dealloc
{
[_method autorelease];
[_data autorelease];
[super dealloc];
}
#end
#pragma mark -
#implementation XMLRPCConnection (XMLRPCConnectionPrivate)
....
#end
The timer set in the initWithXMLRPCRequest method works fine, but if it's set in the sendSycnhronousXMLRPCRequest method, I get the following error:
2010-01-29 11:36:40.442 ActiveE[1071:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[XMLRPCConnection timedOut]: unrecognized selector sent to class 0x32610'
2010-01-29 11:36:40.443 ActiveE[1071:207] Stack: (
31044699,
2497855305,
31426811,
30996086,
30848706,
609709,
30829248,
30825544,
39135117,
39135314,
3100675
)
I don't understand, I did declare the timeOut method in the implementation file?
I think your timedOut method should be a public one. Not hidden in a category with private methods.
The method that the timer calls has to be of the form:
- (void)timerFireMethod:(NSTimer*)theTimer;
The name is arbitrary but you must return void and must accept a timer. I suspect that is the source of your error. In any case, you should change it to the standard form.
I have code running good in 3.0 and 3.1 but when I use the SDK 3.1.2 is crash at the didReceiveAuthenticationChallenge method says a log "obj_msgSend" . It happens always when using didReceiveAuthenticationChallenge .
Also I have all the other methods in that class
didreceive response
connectionfinishloading
didfailwitherror etc
Please help me out
I got the answer do not release the [newCredential release];
in didreceiveauthentiationchallenge
I am posting the twitter request class method , which is calling the twitter XML API URL for sending messages .
Which require authentication .
-(void)statuses_update:(NSString *)status delegate:(id)requestDelegate requestSelector:(SEL)requestSelector; {
isPost = YES;
// Set the delegate and selector
self.delegate = requestDelegate;
self.callback = requestSelector;
// The URL of the Twitter Request we intend to send
NSURL *url = [NSURL URLWithString:#"http://twitter.com/statuses/update.xml"];
requestBody = [NSString stringWithFormat:#"status=%#",status];
[self request:url];
}
-(void)request:(NSURL *) url {
theRequest = [[NSMutableURLRequest alloc] initWithURL:url];
if(isPost) {
NSLog(#"ispost");
[theRequest setHTTPMethod:#"POST"];
[theRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[theRequest setHTTPBody:[requestBody dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]];
[theRequest setValue:[NSString stringWithFormat:#"%d",[requestBody length] ] forHTTPHeaderField:#"Content-Length"];
}
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData that will hold
// the received data
// receivedData is declared as a method instance elsewhere
receivedData=[[NSMutableData data] retain];
} else {
// inform the user that the download could not be made
}
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge {
//NSLog(#"challenged %#",[challenge proposedCredential] );
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential;
newCredential=[NSURLCredential credentialWithUser:[self username] password:[self password] persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
[newCredential release];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password
// in the preferences are incorrect
NSLog(#"Invalid Username or Password");
isFirstTime==NO;
UIAlertView * userNameAlert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"Invalid credentials. Please check your login details !" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK",nil];
[userNameAlert show];
if(delegate && callback) {
if([delegate respondsToSelector:self.callback]) {
[delegate performSelector:self.callback withObject:nil];
} else {
NSLog(#"No response from delegate");
}
}
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// this method is called when the server has determined that it
// has enough information to create the NSURLResponse
// it can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is declared as a method instance elsewhere
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//NSLog([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
// append the new data to the receivedData
// receivedData is declared as a method instance elsewhere
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
[theRequest release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
if(errorCallback) {
[delegate performSelector:errorCallback withObject:error];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// do something with the data
if(delegate && callback) {
UIAlertView * userNameAlert = [[UIAlertView alloc]initWithTitle:#"Congratulation" message:#"Your Message is successfully posted to twitter !" delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK",nil];
[userNameAlert show];
isLoginChanged =YES;
isFirstTime==NO;
if([delegate respondsToSelector:self.callback]) {
[delegate performSelector:self.callback withObject:receivedData];
} else {
NSLog(#"No response from delegate");
}
}
// release the connection, and the data object
[theConnection release];
[receivedData release];
[theRequest release];
}