skpsmtpmessage in different thread - iphone

I have just successfully implemented skpsmtpmessage into my iPhone app. This works fine, but it runs on the main thread, causing the UI to lock up until the operation is complete. Therefore I have tried moving it to a second thread:
[NSThread detachNewThreadSelector:#selector(launchJobWithJob:) toTarget:self withObject:jobDescription];
If I do this that way, the class seems to get stuck on the connecting right away, with the only NSLog output being:
C: Attempting to connect to server at: mail.example.com:25
If I launch the job just by going [self launchJobWithJob:jobDescription];, it works fine but as I said before, lags heavily.
How can I get this to work in a background thread? Has someone come across this?
Edit: I have tried NSOperationQueue as well - the same happens again, just the log output and nothing else!
NSOperationQueue*queue = [NSOperationQueue new];
NSInvocationOperation*operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(launchJobWithJob:) object:jobDescription];
[queue addOperation:operation];
[operation release];

I'm sure that it does its network connection stuff on the runloop, so let the runloop of the thread run until the operation is finished.
[[NSRunLoop currentRunLoop] run];

Must have some race condition, you can put some NSLog at you launchJobWithJob method to detect which code cause problem.

Related

perfomSelectorOnMainThread:withObject:waitUntilDone: randomly stops working

I'm running a selector on the background thread then I need to call the main thread and it works perfectly, but when there are a lot of selectors running on the background and they try to call a selector on the main thread sometimes it gets called, sometimes it doesn't. I can see the code is getting there because I'm printing with NSLog();
This is how I call the selector on the background:
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(getPath:)
object:datos];
[queue addOperation:operation];
[operation release];
And this is how the background method calls the main thread method:
NSLog(#"Arrives here");
[self performSelectorOnMainThread:#selector(setPath:) withObject:array waitUntilDone:YES];
Why does it sometimes work, and sometimes it doesn't?
How do you know it doesn't work?
Is there anything blocking your main thread? A modal session, per chance?
Note that "a lot of selectors running on the background" sounds scary; un-throttled concurrency is pretty much guaranteed to be the wrong answer. It is quite easy to create a system that storms the main event loop with so much noise that it looks like events are being dropped.

iPhone:UI blocked when downloading data using NSURLConnection

I am using the NSURLConnection to download a video file from the server, at the same time playing the video by passing different url link to the movieplayer.
The problem is some blocking of the UI. During downloading we are unable to interact with the UI, like player zoom, pause button are blocked.
Code is like this for connection:_
connection1=[[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]] delegate:self];
in same mithod we are calling the
[playerInstance Play]
Please can you explain me where the problem is.
I can't understand your problem exactly. But I think you doing the two works (downloadig, playing file) on a same thread, probably main thread. So this may happen. So try to run the two processes in a separate threads.
[self performSelectorOnMainThread:#selector(playfile:) withObject:nil waitUntilDone:NO];
[self performSelectorInBackground:#selector(downloadfile:) withObject:nil];
You should make function for NSUrl operation and if it is already made call this function in following way for asynchronous communication.
[self performSelector:#selector(method) withObject:nil afterDelay:1];

Asynchronous NSURLConnection on separate thread fails to call delegate methods

I am running a NSURLConnection on a separate thread (I am aware that it is asynchronous and works when running on the main thread), but it is not making delegate calls even when I pass the parent thread as the delegate. Does anyone know how to do this?
Code:
-(void)startConnectionWithUrlPath:(NSString*)URLpath {
//initiates the download connection - setup
NSURL *myURL = [[NSURL alloc] initWithString:URLpath];
myURLRequest = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[myURL release];
//initiates the download connection on a seperate thread
[NSThread detachNewThreadSelector:#selector(startDownloading:) toTarget:self withObject:self];
}
-(void)startDownloading:(id)parentThread {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
[NSURLConnection connectionWithRequest:myURLRequest delegate:parentThread];
//The delegate methods are setup in the rest of the class but they are never getting called...
[pool drain];
}
EDIT*
The reason I need to run NSURLConnection on a separate thread is because I am downloading something in my iPhone app and the download cancels when the user locks the screen (it continues fine if the user simply presses the home button and the app goes into the background). I understand this is due to my running the connection asynchronously on the main thread and not a separate one.
I have also tried this code (NOT in a separate thread) when initiating the NSURLConnection:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:myURLRequest delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];
[connection release];
But it I have the same problem with this regarding the download being cancelled on screen lock.
*UPDATE
To add to Thomas' answer below (Please note that James Webster's answer is also correct regarding the exiting of a thread) the Apple docs explain:
"Suspended state - The app is in the background but is not executing code. The system moves apps to this state automatically and does not notify them before doing so. While suspended, an app remains in memory but does not execute any code."
Since when the screen is locked by the user the app is put into the background state and than right away into the suspended state, all execution is stopped killing any downloads and no warning that this is about to happen is given... there may be a notification which tells me that the user has locked the screen but I haven't found one yet.
I therefore pause (save certain information and cancel the NSURLConnection) all downloads when the app goes into the background and resume it with the HTTP Range header when it gets active again.
This is a workaround which is ok but not ideal since the download is not occurring in the background which affects the user experience negatively... bummer.
Since your NSURLConnection is asynchronous, the end of your -startDownloading method is reached immediately, and the thread exits.
You should indeed schedule your connection on the main runloop (or use GCD).
The device lock is another issue. When the device is locked, your application is suspended to save battery life. You can probably ask for an extra amount of time when suspending in order to finish your download.
I think your problem might be that the NSURLConnection has been deallocated as soon as you exit the startDownloading: message (or more accurately when your autorelease pool is drained)
However I think your methodology might be a bit uncouth anyway. NSURLConnection the way you are using it is asynchronous and will appear to be threaded anyway.
Try this and see if it works as you expect it to (i.e. your app doesn't pause while your connection is busy)
-(void)startConnectionWithUrlPath:(NSString*)URLpath {
//initiates the download connection - setup
NSURL *myURL = [[NSURL alloc] initWithString:URLpath];
myURLRequest = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[myURL release];
[NSURLConnection connectionWithRequest:myURLRequest delegate:self];
}

Why is my NSOperationQueue not behaving correctly in iOS 4.0?

I have used NSOperationQueue in my iPhone app before in iPhone OS 3.0, but now in iOS 4.0 the code is not working properly. It runs properly only once and on all subsequent calls, it doesnt work. Have there been changes in NSOperationQueue in iOS 4.0?
The relevant code is as follows:
- (void) starteffectFunction {
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(starteffectProcessing)
object:nil];
[queue addOperation:operation];
[operation release];
[queue release];
[spinner startAnimating];
}
-(void) starteffectProcessing{
some code executes. code snippet. A
......
this code is note supposed to execute before A completes. But this executes before A.
}
You are creating an NSOperationQueue, adding an operation to it, then releasing the queue. This is not how NSOperationQueues were designed to work. An NSOperationQueue is supposed to persist, with you adding operations to it as necessary.
This is probably failing because you are deallocating the NSOperationQueue before it has a chance to fire off a thread for your operation. Perhaps on the older OS versions it was just able to do this due to some timing quirk.
I recommend allocating the effect processing queue when you first need it, or in the initialization of your controller object, then keeping that queue around as an instance variable of your controller object. This queue would be deallocated at the same time as your controller object, but you will probably want to cancel all current operations at that time and use NSOperationQueue's –waitUntilAllOperationsAreFinished method to make sure that you are completing all work before deallocation.

When NSThread returns to a released object? (iPhone)

I have got a memory bug that seems to boil down to something happening in a thread. I am having difficulties troubleshooting this.
I have a UIViewController, that when active, i.e. the user is using its view, retrieves updates from a web service in an NSThread.
This is done every 3 minutes and this delay is controlled by a:
[self performSelector:#selector(timerDone) withObject:nil afterDelay:180.0];
The timerDone method now starts the NSThread that retrieves the web service data and also it sends the performSelector message again. This is a little "check for updates, populate views, shut everything down, repeat" routine that works just fine.
Now, the user can of course suddenly tap a button an load up a second UIViewController. When this happens I call:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(timerDone) object:nil];
And do my cleaning up in the dealloc method.
My question is now: What happens if the NSThread was running while the user changed the view and set in motion the deconstruction of this object that is the starting point of the NSThread?
Should I keep a BOOL around that tells me if the NSThread is still active, and if so, what to do with the NSThread if this is the case.
The threading is done like this:
- (void) runTimer {
[self performSelector:#selector(timerDone) withObject:nil afterDelay:180];
}
- (void) timerDone {
[self performSelector:#selector(runTimer) withObject:nil afterDelay:2];
[NSThread detachNewThreadSelector:#selector(updateAllVisibleElements) toTarget:self withObject:nil];
}
- (void) updateAllVisibleElements {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//call approiate web service
[pool release];
}
You have two problems here: first, you're using performSelector:withObject:afterDelay: to do what an NSTimer does best (periodic callback). cancelPreviousPerformRequestsWithTarget:selector:object: can be quite expensive, and because of your threading is likely creating race conditions.
Second problem: each thread has its own run loop, and both mechanisms (performSelector:... and NSTimer) and are tied to the current thread's run loop.
Here's what I recommend: Create a single, long-lived NSThread with its own explicit run loop for all your update needs. Look at the Threading Programming Guide for some good example code of this. On that thread, set up a 3-minute repeating NSTimer. Every 3 minutes, update.
If you need to schedule an update outside the three-minute cycle, then you use performSelector:onThread:withObject:waitUntilDone: to call your updateAllVisibileElements. The way I generally do this is to encapsulate all of the thread logic into a single object (WebServiceController or whatever). It creates it own NSThread and saves it in an ivar. Then I use code like this:
- (void)requestUpdate
{
if ([NSThread currentThread] != self.thread)
{
[self performSelector:#selector(update) onThread:self.thread withObject:nil waitUntilDone:NO];
return;
}
else
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//call approiate web service
[pool drain];
}
}
One more note: you mention that the background thread "populates views." A background thread should never call into UIKit. UIKit is not thread safe and should only be called on the main thread. I typically achieve this by posting notifications onto the main thread which the view controllers observe. The "updating" object should not know anything about the UI. That breaks the Model-View-Controller paradigm of Cocoa.