NSURLConnection delegate methods not getting called - iphone

I am having a Server Class which has delegate methods of NSURLConnection. And I am having another class named SendRequest which will send the NSMutableURLRequest to the Server Class.
In Server Class I am having two methods called
- (void)executeAsync:(NSMutableURLRequest)urlRequest timeOutInterval:(int)timeOut
{
_urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:YES];];
}
- (void)executeSync:(NSMutableURLRequest)urlRequest
{
NSData* respData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
}
Everything works fine until here , I am able to call the above executeAsync method from SendRequest class, which is calling the delegate methods.
Now I have added a new method in the SendRequest class which will call the executeRequest method in Server class.
- (void)executeRequest:(NSMutableURLRequest)urlRequest
{
_urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:YES];];
}
This time , I got trapped . executeRequest method is getting called but it is not calling its delegate methods while processing the URL request. I am struck here for many hours.
Everything seems to be correct , I am sending the urlRequest the same way I used to send before. But I don't know why it is not working. Feel free comment , but please help me. I am really worried
EDIT :
I need to post a request to the server and get a response . If I try with synchronous it is working fine,but it is blocking the main thread. Thats the reason I am going for the asynchronous. Through delegate methods I am trying to get the response data.

I think your description of the system doesn't match the posted code, and it explains the problem you described. The SendRequest class ought to rely on the Server class to perform the server request.
It looks like the SendRequest class sets the connection delegate to self. I'm guessing all of those delegate methods are implemented on the Server class.
Try doing what your description suggested....
// SendRequest.m
- (void)executeRequest:(NSMutableURLRequest)urlRequest
{
// however you get ahold of your server...
Server *myServer = [Server sharedInstance];
// let it do the work. it has the delegate methods
[myServer executeAsync:urlRequest];
}
Alternatively, the SendRequest code can stay as it is, but set the delegate to an instance of Server class (again, assuming that's where the delegate methods are implemented). I think this second idea is worse, since the Server already knows how to start a request.

I finally solved it. Hope this will help some-one. I made code clean up and declared methods properly and finally while creating the object for the class , I have to use initwithDelegate:self . And finally NSURLConnection delegate methods are called .

set NSURLConnectionDelegate to your .h
then run the following code in .m function
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[connection start];

Related

NSURLConnection connection:didReceiveData: is not called on ios5

A weird problem.
I wanna load an image from web, so i use NSURLConnection to do it.
Everything is ok when i do testing my code on ios4.3.
But when i'm launch my app on ios5.0, i found the connection:didreceiveData haven't been called whatever what i did.
otherelse functions is called normally, just like connectionDidFinishLoading in ios4.3 and connectionDidFinishDownloading in ios5.0.
so u guys, who can help me, thanks advanced!
-(void)load
{
if(isDownloading){
return;
}
if(conn != nil){
[conn release];
}
if(data != nil){
[data release];
data = nil;
}
[self isDownloading:YES];
ImageDownloadData* imageDownloadData = [imageList objectAtIndex:count];
NSURL* url = [imageDownloadData url];
NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(conn){
[conn start];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)rd
{
NSLog(#"data");
if(!data){
data = [[NSMutableData alloc] initWithData:rd];
return;
}
[data appendData:rd];
}
I can't be sure if this is the same problem you're having, but I had a similar issue, and resolved it by taking out the in methods and references to NSURLConnectionDownloadDelegate. Apparently delegates of NSURLConnection can only implement one of the two protocols that are derived from NSURLConnectionDelegate at a time.
There's been some odd API changes between 4.3 and 5.0. Apple changed the NSURLConnectionDelegate from an informal protocol to a formal one, and branched out some of the methods into two additional subprotocols: NSURLConnectionDataDelegate and NSURLConnectionDownloadDelegate. (Oddly though, they depreciated the identical methods in NSURLConnectionDelegate but didn't document where they moved to.)
I've been noticing when compiling my code against the 6.0 API that I've been having trouble getting Cocoa Touch to call connection: didReceiveData: if I Implement methods from both NSURLConnectionDataDelegate and NSURLConnectionDownloadDelegate. All the other methods I implemented were called as expected.

check which request is which from NSURLConnection delegate

What is the best way to check which request is which inside the delegate method:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}
Right now I have a NSURLConnection that I set to the NSURLConnection before making a request and inside didReceiveResponse I do:
if (self.tempConnection == connection)
however there is a possiblity this won't work for race conditions. Is there a better way to do this?
There is a better way in OS5. Forget about all those bothersome delegate messages. Let the connection build the data for you, and put your finished code right in line with your start code:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.site.com"]];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"got response %d, data = %#, error = %#", [httpResponse statusCode], data, error);
}];
I've looked at a bunch of different ways to do this, and I've found that by far the cleanest and easiest in order to manage is to use a block pattern. That way you are guaranteed to be responding to the right request upon completion, avoid race conditions, and you don't have any issues with variables or objects going out of scope during the asynchronous call. It's also a lot easier to read/maintain your code.
Both ASIHTTPRequest and AFNetworking APIs provide a block pattern (however ASI is no longer supported so best to go with AFNetworking for new stuff). If you don't want to use one of these libraries, but want to do it yourself, you can download the source for AFNetworking and review their implementation. However, that seems like a lot of extra work for little value.
Consider creating a separate class to serve as the delegate. Then, for each NSURLConnection spawned, instantiate a new instance of the delegate class to for that NSURLConnection
Here's some brief code to illustrate this:
#interface ConnectionDelegate : NSObject <NSURLConnectionDelegate>
...then implement the methods in the .m file
Now, I'm guessing you probably have the code you posted in a UIViewController subclass (or some other class serving different purposes)?
Wherever you are kicking off the requests, use this code:
ConnectionDelegate *newDelegate = [[ConnectionDelegate alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"<url here">]];
[NSURLConnection connectionWithRequest:request delegate:newDelegate];
//then you can repeat this for every new request you need to make
//and a different delegate will handle this
newDelegate = [[ConnectionDelegate alloc] init];
request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"<url here">]];
[NSURLConnection connectionWithRequest:request delegate:newDelegate];
// ...continue as many times as you'd like
newDelegate = [[ConnectionDelegate alloc] init];
request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"<url here">]];
[NSURLConnection connectionWithRequest:request delegate:newDelegate];
You might consider storing all the delegate objects in a NSDictionary or some other data structure to keep track of them. I'd consider using an NSNotification in connectionDidFinishLoading to post a notification that the connection is done, and to serve whatever object created from the response. Lemme know if you want code to help you visualize that. Hope this helps!

NSURLConnection does not call delegate connection:willSendRequest:redirectResponse:

I am trying to detect an http response code of 302. This is my request line:
urlConnection = [[NSURLConnection connectionWithRequest:request delegate:response] retain];
The response variable is an instance of a class I created which implements:
- (NSURLRequest *)connection:(NSURLConnection *)inConnection:
willSendRequest:(NSURLRequest *)inRequest
redirectResponse:(NSURLResponse *)inRedirectResponse
{
NSLog(#"redirect");
return inRequest;
}
But for some reason this is not being hit. I'm 100% sure the service call is being hit and is returning a 302. Is there something else I am missing not written in the documentation in order to get this delegate called?
You've got an extra colon:
...(NSURLConnection *)inConnection: willSend...
Remove that and you should be good to go.
(Remember, colons are part of method names; you have to get them exactly right!)

ASIHTTPRequest Asynchronous Crash When Changing Views

I'm using ASIHttpRequest to recieve data from an xml file. However during an asynchronous request as soon as i change the view (back to the previous view using the navigation controller) the application crashes with a EXC_BAD_ACCESS on the main.m
This only happens while the request is being made.
Below is my code:
-(void)ProcessXML{
//Set url from string to url
NSURL *theurl = [NSURL URLWithString:#"http://twitter.com/statuses/user_timeline/2smssupport.xml"];
asirequest = [ASIHTTPRequest requestWithURL:theurl];
[asirequest setDelegate:self];
[asirequest startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSLog(#"Saving to Defaults");
NSData *responseData = [request responseData];
xmlSaved = responseData;
prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:responseData forKey:#"xmlDownload"];
rssParser = [[RssParser alloc] loadXMLbyURL:xmlSaved];
[self.tableView reloadData];
NSLog(#"%#",[prefs dataForKey:#"xmlDownload"]);
}
The Process XML method triggers the request and the then received data is processed in the RequestFinished.
There must be something i'm missing with the ASIHTTPRequest but i don't know what it is?
Thanks
This block of code should fix it:
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[request clearDelegatesAndCancel]
}
If the view is being release then the delegate you set on the request is now invalid. Make sure you set the delegate to nil on the view dealloc and also stop the request.
The asirequest object isn't being retained anywhere, so it's being deallocated after ProcessXML returns.
NSZombieEnabled helps you a lot. You can tell which object is causing EXC_BAD_ACCESS.
Are you deallocating the ASIHTTPRequest object when you leave the current view? My guess is that the delegate methods are being called after your view controller has been released.
--
#Simon is right that you do need to set the delegate to nil. What I would do is:
Create an ASIHTTPRequest property in your class and set that property in your ProcessXML method. This simplifies memory management and ensures that the request object will stick around while you need it.
In both your dealloc method and your requestFinished methods, set the request delegate to nil and set self.request = nil;
At the very least, you should set the delegate to nil in your requestFinished method, but you need to remember to stop your request from running if you navigate away from this view controller before it returns, hence setting it to nil in the dealloc method as well.

How to create something like NSURLConnection?

NSURL *URL = [NSURL URLWithString:#"http://www.stackoverflow.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
With code as simple as that, I can load a webpage in my application. I don't have to worry about retaining or releasing the NSURLConnection, it will autorelease when it's done loading.
I'm creating some sort of wrapper around NSURLConnection, JSONConnection. It allows me to load a JSON value from a webpage and automatically parse that in a NSDictionary. Right now, I have to use it like this:
JSONConnection *tempJSONConnection = [[JSONConnection alloc] initWithURLString:#"http://www.stackoverflow.com" delegate:self];
self.JSONConnection = tempJSONConnection;
[tempJSONConnection release];
Then, when it's done loading, I call self.JSONConnection = nil;.
What I want, is to do this:
JSONConnection *connection = [JSONConnection connectionWithURLString:#"http://www.stackoverflow.com" delegate:self];
I know how to create this method. I just don't know how to keep connection alive when the runloop is finished and the autorelease pool is drained, and make sure connection is deallocated when it's done loading. In other words, I don't how to duplicate the exact behavior of NSURLConnection.
To all intents and purposes, from the outside, NSURLConnection effectively retains itself. This was either done by sending
[self retain];
when starting the connection and then
[self release];
when finished and after informing the delegate; or it was done by placing itself in a pool of currently open connections and removing it from that pool on completion.
You don't actually have to do any of this. NSURLConnection retains its delegate, so your JSON connection class should create an NSURLConnection passing itself as the NSURLConnection's delegate. That way it will live at least as long as the NSURLConnection. It should parse the JSON into a dictionary in the method -connectionDidFinishLoading: and pass the dictionary on to its delegate before returning. After returning the NSURLConnection will release and possibly deallocate itself and also release your JSON connection.
Someone should trac connection's live time in any case. It is a bad solutions to trac it inside the connection.
IMO the right way to do it is use singleton class to perform connections
#protocol JSONDataProviderDelegate <NSObject>
- (void) JSONProvider:(JSONDataProvider*) provider didLoadJSON:(JSONObject*) object;
- (void) JSONProvider:(JSONDataProvider*) provider didFainWithError:(NSError*) error;
#end
#interface JSONDataProvider : NSObject
+ (void) provideJSON:(NSURL*) url delegate:(id<JSONDataProviderDelegate>) delegate;
+ (void) removeDelegate:(id<JSONDataProviderDelegate>delegate);
#end
Usage:
- (void) onSomeEvent
{
[JSONDataProvider provideJSON:[NSURL URLWithString:#"http://example.com/test.json"] delegate:self];
}
- (void) JSONProvider:(JSONDataProvider*) provider didLoadJSON:(JSONObject*) object
{
NSLog(#"JSON loaded: %#", object);
}
- (void) dealloc
{
[JSONDataProvider removeDelegate:self];
[super dealloc];
}