NSURLConnection delegate is not call when call from NSThread's function - iphone

I sent NSURLConnection request it is working fine. Now I want to refresh the information i.e. resend the NSURLConnection.Refresh is working when call from IBAction of button. But is not working from NSThread method. How to I solve this problem. Here NSThread function for running the system time. When the time is equal to 1:00 am I want to refresh the API. But it is not call the delegate of NSURLConnection.
This is NSURLConnection code:
-(void)displays:(model *)place
{
NSString *strs=[#"http://www.earthtools.org/timezone-1.1/" stringByAppendingString:[NSString stringWithFormat:#"%#/%#",place.latitude,place.longitude]];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:strs]];
NSURLConnection *reqTimeZone=[NSURLConnection connectionWithRequest:request delegate:self];
[reqTimeZone start]; //here request not get start
}
Above code is with in function called "displays" argument is one instance of class it has all place details.
NSthread function code:
- (void) setTimer {
//assign current time
[self countDown];
}
- (void) countDown {
//count the current time
if(hrs==12&& meridian==#"pm")
[self display:(placedetails)];//it calls the displays function but NSURLConnection is not get start.
[NSThread detachNewThreadSelector:#selector(setTimer) toTarget:self withObject:nil];
}
Above display function is called placedetails assigned but NSURLConnection delegate is not called.

For the delegate methods to be called, you need to attach your thread's runloop to NSURLConnection. Since you are creating a thread and not attaching NSURLConnection to thread's RunLoop, connection delegate methods won't get fired.
Here is an example:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// I am creating a button and adding it to viewController's view
UIButton *bttn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[bttn setFrame:CGRectMake(100.0f, 200.0f, 120.0f, 50.0f)];
[bttn setTitle:#"Download" forState:UIControlStateNormal];
[bttn addTarget:self action:#selector(spawnThreadForDownload) forControlEvents:UIControlEventTouchUpInside];
[[self view] addSubview:bttn];
}
- (void)spawnThreadForDownload
{
[NSThread detachNewThreadSelector:#selector(downloadAndParse) toTarget:self withObject:nil];
}
- (void)downloadAndParse
{
#autoreleasepool {
NSURL *url = [NSURL URLWithString:#"http://apple.com"];
NSURLRequest *req = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:20.0f];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
// Run the currentRunLoop of your thread (Every thread comes with its own RunLoop)
[[NSRunLoop currentRunLoop] run];
// Schedule your connection to run on threads runLoop.
[conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
}
// NSURLConnectionDelegate methods
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Connection failed with error: %#",[error localizedDescription]);
}
// NSURLConnectionDataDelegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Connection finished downloading");
}

Related

How do I start an Asynchronous NSURLConnection inside an NSOperation?

I want to do an Asynchrous NSURLConnection inside of an NSOperation on a background thread.
it is because I'm doing some very expensive operations on the data as they come back.
This is a very similar question to what they asked here:
How do I do an Asynchronous NSURLConnection inside an NSOperation?
but the difference is that I run the connection in another class.
Here is my first attempt:
In my MainViewController:
#property (nonatomic, strong) NSOperationQueue *requestQueue;
#pragma mark - Lazy initialization
- (NSOperationQueue *)requestQueue
{
if (!_requestQueue) {
_requestQueue = [[NSOperationQueue alloc] init];
_requestQueue.name = #"Request Start Application Queue";
_requestQueue.maxConcurrentOperationCount = 1;
}
return _requestQueue;
}
-(void)callToServer
{
URLJsonRequest *request = [URLRequestFactory createRequest:REQUEST_INTERFACE_CLIENT_VERSION
delegate:self];
RequestSender *requestSender = [[RequestSender alloc]initWithPhotoRecord:request delegate:self];
[self.requestQueue addOperation:requestSender];
}
Here is my operation:
- (id)initWithPhotoRecord:(URLJsonRequest *)request
delegate:(id<RequestSenderDelegate>) theDelegate{
if (self = [super init])
{
self.delegate = theDelegate;
self.jsonRequest = request;
}
return self;
}
- (void)main {
//Apple recommends using #autoreleasepool block instead of alloc and init NSAutoreleasePool, because blocks are more efficient. You might use NSAuoreleasePool instead and that would be fine.
#autoreleasepool
{
if (self.isCancelled)
return;
[self.jsonRequest start];
}
}
Here is my Request start function:
-(void) start
{
NSURL *url = [NSURL URLWithString:#"http://google.com"];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
urlConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self]autorelease];
[urlConnection start];
[theRequest release]
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"Received reponse from connection");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
}
I do not get a response from the server.
A couple of approaches:
Schedule the NSURLConnection in the main run loop, by using the startImmediately parameter of NO, set the run loop, and only then should you start the connection, e.g.:
urlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:NO];
[urlConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[urlConnection start];
Create a dedicated thread for the the connection and schedule the connection in the run loop you create for that thread. See AFURLConnectionOperation.m in AFNetworking source for an example of this.
Actually use AFNetworking, which gives you NSOperation based operations that you can add to your queue, and takes care of this run loop stuff for you.
So, AFNetworking does something like:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
#autoreleasepool {
[[NSThread currentThread] setName:#"NetworkingThread"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self
selector:#selector(networkRequestThreadEntryPoint:)
object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
So I do something like the following. First I have a few private properties:
#property (nonatomic, readwrite, getter = isExecuting) BOOL executing;
#property (nonatomic, readwrite, getter = isFinished) BOOL finished;
#property (nonatomic, weak) NSURLConnection *connection;
Then the network operation can then do something like:
#synthesize executing = _executing;
#synthesize finished = _finished;
- (instancetype)init {
self = [super init];
if (self) {
_executing = NO;
_finished = NO;
}
return self;
}
- (void)start {
if (self.isCancelled) {
[self completeOperation];
return;
}
self.executing = YES;
[self performSelector:#selector(startInNetworkRequestThread)
onThread:[[self class] networkRequestThread]
withObject:nil
waitUntilDone:NO];
}
- (void)startInNetworkRequestThread {
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request
delegate:self
startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
self.connection = connection;
}
- (void)completeOperation {
self.executing = NO;
self.finished = YES;
}
- (void)setFinished:(BOOL)finished {
if (finished != _finished) {
[self willChangeValueForKey:#"isFinished"];
_finished = finished;
[self didChangeValueForKey:#"isFinished"];
}
}
- (void)setExecuting:(BOOL)executing {
if (executing != _executing) {
[self willChangeValueForKey:#"isExecuting"];
_executing = executing;
[self didChangeValueForKey:#"isExecuting"];
}
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isAsynchronous {
return YES;
}
// all of my NSURLConnectionDataDelegate stuff here, for example, upon completion:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// I call the appropriate completion blocks here, do cleanup, etc. and then, when done:
[self completeOperation];
}
-(void)start
{
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
NSURL* url = [[NSURL alloc] initWithString:#"http://url.to/feed.xml"];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20];
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; // ivar
[request release];
[url release];
// Here is the trick
NSPort* port = [NSPort port];
NSRunLoop* rl = [NSRunLoop currentRunLoop]; // Get the runloop
[rl addPort:port forMode:NSDefaultRunLoopMode];
[_connection scheduleInRunLoop:rl forMode:NSDefaultRunLoopMode];
[_connection start];
[rl run];
}
More details can be found here: link
I know this post is over a year old, but I wanted to add some suggestions for people who may run the same problem trying to create own async network operation.
You need to add runloop to operation that runs in background and you should stop it when the operations has finished.
There actually 2 simple options:
Option 1 - using NSRunLoop
NSPort *port = [NSPort port];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:port forMode:NSDefaultRunLoopMode];
[self.connection scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode];
[self.connection start];
[runLoop run];
and you need to stop when the operation is finished:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
NSDate *date = [NSDate distantFuture];
while (!runLoopIsStopped && [runLoop runMode:NSDefaultRunLoopMode beforeDate:date]);
Option 2 - using CF
You need to add
CFRunLoopRun();
when you start operation
and call
CFRunLoopStop(CFRunLoopGetCurrent());
when you finish operation.
Read the following post: CFRunLoopRun() vs [NSRunLoop run]

NSURLConnection delegate methods are called in Simulator but not in Device

I created a NSObject, which downloads some data from a php web service. The problem is that when i run the app in the simulator works well, but in the device the delegate methods are not called. I don´t know why. I write all the delegates methods but none of them are called. This is a part of the NSObject code:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:hostStr]];
NSLog(#"%# URL Engine",hostStr);
dispatch_async(dispatch_get_main_queue(), ^{
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
// while(!finished) {
// [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate distantFuture]];
//}
[_connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[_connection start];
});
It's tricky about call dispatch_async to get the connection run on the main thread queue.
Try this if you want to let your delegates get called on the main thread:
[self performSelectorOnMainThread:#selector(startConnection)
withObject:Nil
waitUntilDone:NO];
If you want to let your delegates get called on the other thread, try:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[connection scheduleInRunLoop:currentRunLoop forMode:NSRunLoopCommonModes];
[connection start];
[currentRunLoop run];
});

NSURLConnection Delegate methods are not getting called

I have had this problem and i went through so many posts here on stack overflow and everywhere else and couldnt find a solution. Im running it on the main thread as well. Code as follows.
#interface JsonViewController : UIViewController <UIActionSheetDelegate,UIWebViewDelegate,NSURLConnectionDelegate>
{
....
}
#implementation JsonViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
rssFeedDetailViewConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"PRINTING RSS FEED %#", rssFeedDetailViewConnection);
[rssFeedDetailViewConnection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[rssFeedDetailViewConnection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Hello");
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"Hello");
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Hello");
[responseData release];
[connection release];
// Show error message
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Hello");
// Use responseData
[responseData release];
[connection release];
}
Any help would be greatly appreciated. Ive been stuck with this for two days now..
You don't need these statements:
[rssFeedDetailViewConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[rssFeedDetailViewConnection start];
since you're using initWithRequest:delegate:. This call already starts loading the data.
What happens if you remove these particular statements?
More info on the NSURLConnection.
Have a boolean called finished and add this code where ever you have written your NSURLConnection Code.
while(!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
and in your connectionDidFinishLoading just add this
finished = TRUE;
and that works. Its not the best solution i understand but it works.

iOS 5 NSURLConnection with NSOperationQueue - Providing UI Feedback

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"?

Second asynchronous NSURLConnection doesn't call delegate methods

From my ApplicationDelegate, I'm doing an NSURLConnection fetch over the network (it's wrapped in a class, as you'll see below). This one seems to work correctly: I get all the data in didReceiveData and I get the completion call connectionDidFinishLoading. At the end of connectionDidFinishLoading, I instantiate one or more of a slightly different kind of wrapper class, but they're essentially the same thing. The problem is that the second NSURLConnection's delegate is never having it's methods called.
I've looked at many different answers, but all to no avail. I'm not spawning any new threads and all the [NSThread isMainThread] checks I've littered throughout the code return true.
I'm stumped. Can anyone help me out? Here's the relevant code:
App Delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ConnectionWrapper* w = [[ConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<url>]];
[w beginFetch];
return YES;
}
...
-(void)fetchCompleted:(NSURL*)url directory:(NSString*)directory
{
NSLog(#"fetch completed");
}
-(void)fetchFailed:(NSURL*)url
{
NSLog(#"fetch failed");
}
...
ConnectionWrapper:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"append");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
-(void)fetchCompleted:(NSURL*)URL
{
NSLog(#"completed: %#", URL);
}
-(void)fetchFailed:(NSURL*)URL
{
NSLog(#"failed");
}
DifferentConnectionWrapper:
-(id)initWithParams:(id)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"append");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"got response");
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"got data");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
NSLog(#"image saver completed: %#", connURL);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"error");
}
ConnectionWrapper and DifferentConnectionWrapper have similar functions, but there's other logic that I've omitted here for brevity.
thanks for the help. I appreciate it.
A couple of things: I don't see a didFailWithError: in your first wrapper class, and (a little off topic) are you leaking memory with your DifferentConnectionWrapper *w ?
Anyway, what I would try is: see if you can invoke DifferentConnectionWrapper directly from the appDelegate instead of the ConnectionWrapper.
And I would try to decouple the two calls in any event. When the first one finishes, and calls appDelegate, can't you launch your DifferentConnectionWrapper from there?
I realize this doesn't explain your problem, but you might get it working (and which of THOSE two things is more important, is an entirely different debate.)
I believe the problem is that you’re releasing the URL connection in -beginFetch:
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
The URL connection object should be kept alive and released when the connection has finished loading:
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
// *** Release the connection and whatever data you’ve kept related to
// this particular connection
[connection release];
[responseData release];
// *** or [responseData setLenght:0]; depending on how you’re
// managing responseData
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
or when there’s been an error:
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
// *** Release the connection and whatever data you’ve kept related to
// this particular connection
[connection release];
[responseData release];
// *** or [responseData setLenght:0]; depending on how you’re
// managing responseData
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
Edit: Your initialiser is a tad weird:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
There’s no way to know what happens unless we see the code for -init and, at any rate, this should be the designated initialiser, so it shouldn’t be sending -init to self anyway. Furthermore, you should be retaining the url object that’s being passed to the initialiser.
The following makes more sense:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
self = [super init];
if (self) {
delegate = d;
connURL = [url retain];
}
return self;
}
Don’t forget to release the url object in -dealloc or when you’re assigning another value to connURL.
OK. It turns out that this bug was caused by something I missed. I was going into a hard spin right after that second request, which would probably screw up just about anything. Once I fixed that problem, everything worked just fine.
Thanks for the help.