NSThread terminating too early - iphone

I have an app that uploads to Google Spreadsheets via the GData ObjC client for Mac/iPhone. It works fine as is. I'm trying to get the upload portion on its own thread and I'm attempting to call the upload method on a new thread.
Look:
-(void)establishNewThreadToUpload {
[NSThread detachNewThreadSelector:#selector(uploadToGoogle) toTarget:self withObject:nil];
}
-(void)uploadToGoogle {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
//works fine
[helper setNewServiceWithName:username password:password];
//works fine
[helper fetchUserSpreadsheetFeed];
//inside the helper class, fetchUserSpreadsheet feed calls ANOTHER method, which
//calls ANOTHER METHOD and so on, until the object is either uploaded or fails
//However, once the class gets to the end of fetchUserSpreadsheetFeed
//control is passed back to this method, and
[pool release];
//is called. The thread terminates and nothing ever happens.
}
If I forget about using a separate thread, everything works like it's supposed to. I'm new to thread programming, so if there's something I'm missing, please clue me in!
Thanks!

I've had this problem and I have a solution, however, the solution kind of makes me cringe as it works, but something smells about it... it seems like their should be a better way.
I suspect somewhere within [helper fetchUserSpreadsheetFeed] you are using some form of NSURLConnection. If you are using an asynchronous http request (where you setup the delegate for callback functions and such) the thread may terminate before the connection has a chance to invoke those callback functions and silently fail. Here's my solution which keeps the thread alive until the callbacks set a 'finished' variable to YES. (I also seem to have trouble posting code in these text boxes so if those angels that run around editing stuff can help me out that'd be great!)
- (void)fetchFeed {
//NSLog(#"making request");
[WLUtilities makeHttpRequest:self.feedUrlString withHttpHeaders:nil withDelegate:self];
//block this thread so it's still alive when the delegates get called
while(!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
The problem I have with this solution is that spinning while loops are generally not good practice. I'm not sure as to the nature of the runloop business though, it may be properly sleeping and stuff but I'm not sure.
At any rate, you could give that a try and see what happens!
NOTE: my "WLUtilities" function is just a wrapper around the NSURLConnection function to create an asynchronous http request. Another solution you might try is simply using a synchronus request but I don't like this solution much either because the asynchronous call offers finer grained control over the connection.

Use the techniques in this answer:
How can I upload a photo to a server with the iPhone?

Related

Cocoa Touch begin command AFTER viewDidLoad

I have an application in which I am required to connect to the internet after a view is loaded. However, if I put this code in the viewDidLoad method the parent view freezes, and then unfreezes after the connection onto the new view. However, I would like the new view to load FIRST, and then to start the connection. I tried using viewDidAppear:, however I am getting the same issue.
Also, will any animations continue playing during the connection? Will the UI be responsive? If not, is multithreading the way to go?
Here is some of my code:
-(void)viewDidLoad {
[super viewDidLoad];
//Do some other view initialization
//Connect is a class I use to connect to the internet
[Connect getData:someString];
}
When I put the code in viewDidAppear the same thing happens.
Connection code:
NSMutableURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSHTTPURLResponse *response;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
Also, I forgot to mention that I am running a regular expression as well after the connection.
As the name of the method says, the view has already been loaded when viewDidLoad executes.
Generally, be sure to use asynchronous connections to connect to the internet. Never block the main thread.
it is easier than you may think.
All you need is some thread management. On the view did Do:
[NSThread detachNewThreadSelector:#selector(yourMethod:) toTarget:yourTarget withObject:yourObject];
and later in another part do:
- (void)yourMethod:(id)sender{
//download the info but do not update the GUI
[self performSelectorOnMainThread:#selector(updatingTheGUI:) withObject:yourObject waitUntilDone:NO]
}
- (void)updatingTheGUI:(id)sender{
//Update your GUI
}
You will notice that the viewDidLoad method documentation of UIViewController states:
...Called after the controller’s view is loaded into memory.
This doesn't necessarily mean that it's called after the view is displayed on screen.
To answer your other questions, if you make your network request the way you have described, no, animations will not continue playing while the request is in progress and no, you can't guarantee that the UI will be responsive. This is because the network request will take an unknown amount of time. Therefore, if you make the request on the main thread, the main thread will be blocked for that period of time, however long it takes.
And, as for the last question, is multithreading the way to go? As others have stated, the easiest and probably most popular way of handling this is to initialize the NSURLConnection with initWithRequest:delegate:. The delegate being your UIViewController or Connect class, or whatever class you want to conform to the NSURLConnectionDelegate protocol and use the NSURLConnectionDelegate methods to process the downloaded data. NSURLConnection will do the work asynchronously and keep the main thread free to handle animations, displaying the UI, etc.
I know it sounds a bad idea for your app. performance but try giving a delay or sleep in between to check if it works that way. Later try to implement the asynchronous call as someone earlier stated..

iphone - what is the logic of this kind of multithread operation

I am just trying to understand this: multithread is a way of firing a method in another thread, so it will not hang the main thread (when something heavy must be done). But I have seen stuff like this:
this goes on the main code:
[NSThread detachNewThreadSelector:#selector(createNewThread) toTarget:self withObject:nil];
and here goes the thread
-(void) createNewThread {
NSAutoreleasePool* p = [[NSAutoreleasePool alloc] init];
[self performSelectorOnMainThread:#selector(doSomeStuff) withObject:nil waitUntilDone:YES];
[p release];
}
My problem with this is: if the thread is intended to relieve the main thread from doing something, why is doSomeStuff being called using performSelectorOnMainThread? Isn't that insane? I mean, you fire a second thread just to run something on the main thread, a thread that in fact you shouldn't be using.
I have seen a lot of code on the web write this way.
I know that probably it is done that way because it is doing something that is not thread safe, but is doing this really useful? To me sounds that it is totally useless and it would be better to do something like
[self performSelector:#selector(doSomeStuff) withObject:nil afterDelay:0.01];
what do you guys think?
thanks in advance.
performSelectorOnMainThread:withObject:waitUntilDone: puts the call on a queue to perform on the next iteration of the run loop. performSelector:withObject:afterDelay: sets up a timer to perform the action. However, creating a new thread to call performSelectorOnMainThread makes no sense because it puts the call on the queue even if it is already on the main thread.
If that's the entire body of the createNewThread method then it makes no sense. But if other stuff actually happens in createNewThread then there might be a good reason. The most common scenario for having a background thread use performSelectorOnMainThread: is if the UI needs to update as a result of the background activity. Like if you're processing a large data set and you want to show the user how much progress has been made so far. UIKit is not thread-safe so you can't update the UI from the background thread. But you might do something like, have the background doing a lot of work in a loop, and at every pass through the loop (or every 5, or whatever) call back to the main thread to update the UI. This makes the code switch back to the main loop just long enough to update the UI before returning to the background for the heavy duty work.

Stop lazy-loading images?

Here's the issue – I followed along with the Apple lazy-load image sample code to handle my graphical tables. It works great. However, my lazy-load image tables are being stacked within a navigation controller so that you can move in and out of menus. While all this works, I'm getting a persistent crash when I move into a table then move immediately back out of it using the "back" button. This appears to be a result of the network connections loading content not being closed properly, or calling back to their released delegates. Now, I've tried working through this and carefully setting all delegates to nil and calling close on all open network connections before releasing a menu. However, I'm still getting the error. Also – short posting my entire application code into this post, I can't really post a specific code snippet that illustrates this situation.
I wonder if anyone has ideas for tasks that I may be missing? Do I need to do anything to close a network connection other than closing it and setting it to nil? Also, I'm new to debugging tools – can anyone suggest a good tool to use to watch network connections and see what's causing them to fail?
Thanks!
Have you run it through the debugger (Cmd-Y)? Does it stop at the place where the crash is happening? That should show you in code where the issue is happening. I'm betting the issue has to do with over-releasing something rather than cleaning up connections. Are you getting EXC_BAD_ACCESS? Check any delegates and make sure they are nil when -viewWillDisappear gets called. That way, if anything tries to call back to a delegate, it will just be a no-op.
You may also want to try enabling zombies (NSZombieEnabled) which will tell you when an object that has been released is being accessed again. It's very helpful in finding over-released objects.
Ah ha... after a large zombie hunt (thanks, Matt Long), I discovered that the issue stems from an error in Apple's LazyTableImages sample code. That example provides the following implementation for canceling all image loads, which I turned into a general-purpose stopAllImageLoads method...
From RootViewController.m in LazyTableImages sample code:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// terminate all pending download connections
NSArray *allDownloads = [self.imageDownloadsInProgress allValues];
[allDownloads performSelector:#selector(cancelDownload)];
}
There is in error in the last line of the above method where performSelector is called on an array of objects. The above implementation calls the selector on the array itself, rather that on each object in the array. Therefore, that last line should be this:
[allDownloads makeObjectsPerformSelector:#selector(cancelDownload)];
Once that line was changed, everything else fell into place. It turns out I wasn't calling my stopAllImageLoads method where I meant to – I had disabled it at one point because it was causing an error. Once that was back in place, the memory issues cleared up because image loads were successfully canceled before the table delegate was released.
Thanks all for your help.
If you're doing ANY asynchronous function (network requests, Core Location updates, etc), you run the risk that your view controller that is the delegate of that action is deallocated by the time the async function returns. i.e. you back out of the view and take the delegate target away from the background process. I've dealt with this several times.
Here's what you do. Use the ASIHTTPRequest library (which you should be doing anyway--it's brilliant). Create a synthesized property to hold your request. Then in viewWillDisappear, call -cancel on your request. To be safe, I also set its delegate to nil, but that should be unnecessary.
Here's a sketch of what you want to do. Note I typed this right here, haven't syntax-checked it or anything.
#implementation MyViewController
#synthesize req //this is an ASIHTTPRequest *req.
-(void)viewDidLoad
{
//make an NSURL object called myURL
self.req = [ASIHTTPRequest requestWithURL:myURL];
self.req.delegate = self;
[self.req startAsynchronous];
}
-(void)viewWillDisappear
{
[self.req cancel];
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSString *string = [request responseString];
}

Recommended thread layer to use for iPhone development?

I'm new to Objective C, and Mac development... It appears that I can use the Posix threads API in my app.. Is this the recommended way? Or is their some Apple API I should be using for mutexes, condition variables and threads instead?
I should add that I'm developing for the iPhone.
I'd like to add exactly what I'm trying to do. Basically, CoreLocation is asynchronous... You tell it to start updating you, and then it just calls an update method on you periodically...
The problem I have is that I need another thread to block until an update occurs... How can I make the main application thread block until at least one CoreLocation update occurs? Is their an NSConditionVariable? :)
I'd suggest an even easier way to get stuck into threads is to use the following call:
[self performSelectorInBackground:(#selector(myMethod)) withObject:nil];
This will automatically create a new background thread for you to run in. Incidentally make sure you do the following inside your background method:
-(void) myMethod {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// code you want to run in background thread;
[pool drain];
}
This is necessary because there isn't a default autorelease pool set up for any threads except the main one.
Finally, talking about blocking the main thread, you could use the following from your background thread to do this:
[self performSelectorOnMainThread:(#selector(myOtherMethod)) withObject:nil waitUntilDone:YES];
The optional third parameter will hold up the main thread for you if you want it to do so.
Hope that helps!
It depends on what you are trying to do, but I would start with NSOperation and NSOperationQueue. It makes it pretty simple to hand off background tasks. Take a look at Dave Dribin's blog post on NSOperation concurrency as well: http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
Instead of blocking the user interface by making it hang, I would suggest showing some kind of loading screen until you've received your first update. The could would look something like this:
- (void)viewDidLoad {
...
[myCLLocationManager beginUpdates];
[self showLoadingIndicator];
....
}
- (void)locationManager:(CLLocationManager *)manager didReceiveUpdates {
[self hideLoadingIndicator];
// Additionally load the rest of your UI here, if you haven't already
}
Don't quote me on those method calls verbatim, but that's how I suggest solving your problem, in essence.
Yes there is an NSCondition object, and it will probably do exactly what you want for the CoreLocation scenario you mentioned.

Is it acceptable to release object in a method of the object's class

Is it acceptable for a instance method of a class to release itself?
ie to have a method that calls:
[self release]
Assume that my code is not going to access self after calling [self release]
Is it acceptable for a instance method of a class to release itself?
ie to have a method that calls:
[self release]
Assume that my code is not going to access self after calling [self release]
First, I would want to have a really good reason to release myself. The only time I've done it is in a singleton that I dump to free up large chunks of memory on an iPhone. This is a rare event.
Your code is part of the class object. Hence, it is not really a problem to call [self release]. Of course, you are much safer, from an encapsulation perspective, if you call [self autorelease]. At least then, if someone up the call chain calls your methods, you don't cause an exception.
Andrew
You should only do this if you've done something like
[self retain];
But it's unclear why you would do that. The Cocoa Memory Management Documentation might help
While I doubt that immediately after your release, memory would move much, keep in mind that the code that your [self release] is in, resides in a memory block inside your object, self. Thus, it is possible that after returning from [self release], you end up in code that is no longer allocated and is being written over by some other process. Can't say for sure how probable that is, but it seems possible.
I have used this technique once before, for a similar situation (standalone object handling response from a web delegate that may outlive the view that launched the request).
It does work, but is actually rather tricky to get right. Since then I have found that using NSOperations in an NSOperationQueue is a much more solid and well-understood approach to encapsulating background actions that run independent of the requestors. Usually when an operation is done a notification is sent out on the main thread informing whatever caller might still be around that data is ready for pickup.
Plus for simple remote requests you can use the simpler synchronous URL calls in your Operation since they run in a separate thread and will not block the main thread while data is incoming (handy when fetching small images from URL's, for example).
You can do it. It works. It is a bit dangerous, especially since optimizing compilers can rearrange your code in ways you didn't intend them to.
A little bit safer is to call [self autorelease], which will release the current object at some point in the near future (the next time through the runloop typically) rather than right away.