nsthread in iphone xcode - iphone

Good Day!
i want to use nsthreads in a project of xcode that will call a function which is for the network access and will check that if the network is there or not, so i need to have a thread which will execute after lets say 1 minutes to check the connectivity. and will continue run unless the app is closed.
[NSThread detachNewThreadSelector:#selector(startTheBackgroundJob) toTarget:self withObject:nil];
startTheBackgroundJob
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// wait for 3 seconds before starting the thread, you don't have to do that. This is just an example how to stop the NSThread for some time
[NSThread sleepForTimeInterval:5];
//[self performSelectorInBackground:#selector(checkNet) withObject:nil];
[self performSelectorOnMainThread:#selector(checkNet) withObject:nil waitUntilDone:YES];
[pool release];
it works only for the first time but not any other, i mean only 1 loop it makes
can somebody help me in this regard.
Thanks

You can use NStimer instead... With Property Repeated set to YES

Threads are especially useful when you need to perform a lengthy task, but don’t want it to block the execution of the rest of the application. In particular, you can use threads to avoid blocking the main thread of the application.
To understand more....
find nice simple and short source code from
http://www.xprogress.com/post-36-threading-tutorial-using-nsthread-in-iphone-sdk-objective-c/

I'd suggest a combination of NSTimer, that fires each 5-10 seconds + a Reachability interface, which checks for you the network status. No need for a thread. For using the Reachability check Apple's example.
Put this call in viewDidLoad
[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(onTimer:) userInfo:nil repeats:YES];
-(void) onTimer:(NSTimer *)theTimer
{
//Here perform reachability checks
}

Related

NSThread causes UIWebView Crash

i would like to explain my issue from the beginning. I am creating a app with UIWebView. Also I am capturing the screen at the moment user using the app and create a video using that image array.
I am using NSTimer to get screen shots of the screen. I worked well but i got one issue. That was when user start scrolling the web page or when user hold his touch on the screen NSTimer got pause and after he releases the touch NSTimer continue.
Here is my NSTimer used to get Screen shots of the screen.
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
target:self
selector:#selector (writeSample)
userInfo:nil
repeats:YES];
I googled this issue and most of the people got same issue as i got. So they found a answer for that and that is using NSRunLoop. They said it stops pausing the NSTimer.
So I used NSRunLoop and add NSTimer into the NSRunLoop and here is the code after I did that.
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
target:self
selector:#selector (writeSample)
userInfo:nil
repeats:YES];
[runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
[runLoop run];
This code worked well and it didnt stops pausing NSTimer. But after i used NSRunLoop My app got really really slow. Also it took lots of time to load the webpage into the WebView and scrolling also very slow.
So I started to search in google again and i found the issue. That was all those things are doing in main thread and iphone cant process every thing in same time. So people suggest to use NSThread to over come the problem. So what i did was create a NSThread and attach the process to the custom thread.
Here is my code after i apply NSThread to it.
[NSThread detachNewThreadSelector:#selector(launchTimer) toTarget:self withObject:nil];
-(void)launchTimer{
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
target:self
selector:#selector (writeSample)
userInfo:nil
repeats:YES];
[runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
[runLoop run];
}
-(void) writeSample{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//did some coding here to take screen shot
[pool release];
}
This solves the slowing the app issue forever and my app is running again very smoothly but it brings up serious problem now. That is happening because of using threads i guess. My custom thread and main thread getting conflict now and causes the app to crash. I searched the google for the reason. I found some questions related to this kind of problem and some people answered those and said Any UI changes need to be done in Main thread. Also UIWebView WebThread must run in main thread.
Those are some error reports i am getting,
Those errors are like some thread conflicting. But I have no idea how to solve this problem. I used my code to some native app that is not having any Web Views or Maps. So it works well with out crashing. But when i use this to app that is having WebView or Map its crashing some times and give me this errors.
I am in soo much trouble in here and If any one can give any idea or sample code to handle threads , handle thread priorities , or using NSTimer and NSRunLoop with out using NSThreads , or Overcome the app slowness without using NSThread , Any answer would be very very very helpful and I am looking forward to hear from you soon.
Thanks.
My guess is the code that you wrote to capture screen shots is causing the problem. A simple test would be to comment out all the code in the writeSample method and see if the app still crashes. I say this because you are right that all UI related tasks should work in the Main Thread at all times.
I would suggest to use a separate thread for timer so that your timer isn't paused and then from the writeSample method force the screen capture code to run on the main thread.
Hope this helps
First off:
As soon as you are using timers, you are working with run loops — as you can easily see from the reference:
Timers work in conjunction with run loops.
(That’s the first sentence of the second paragraph)
With that out of the way, to your syptoms:
Blocking a thread by capturing images, causes it to stutter.
This shouldn’t surprise you!
Moving the work off of that thread, releases the strain on the first one.
Shocking, I know!
Well, given that you didn’t show us any of the code that causes your synchronization issues, (read: crashes) this sarcastic answer is all the help I can offer you.
That and the tip to read and internalize the document I linked to above…
Edit
I just forgot to mention, this:
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:blablabla];
[runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
[runLoop run];
doesn’t make much sense because…
-scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
Creates and returns a new NSTimer object and schedules it on the current run loop in the default mode.
(Which is explained in the magnificent documentation, as well.)
In essence: when you’re on your own private thread, the default mode is sufficient. You have to make sure that the run loop is actually running, though.
This is actually accomplished by the last line of that code snippet, but it effectively causes your method to not return until the timer is cancelled…

Execute a method that takes a second to complete without temporarily halting code

Basically, i have a method that takes a few seconds to complete as it copies some files using NSFileManager. This is invoked on the touchesMoved event when the user picks up a draggable UIView icon. However, there's a slight delay before the icon's position is updated. I'm guessing it's waiting for that method to copy it's files before continuing. The method HAS to be triggered on touchesMoved, so please don't suggest moving it.
How can i execute a method that takes about a second to complete, without holding up the code?
(..and don't worry the copy method doesn't get repeatedly called from the touchesMoved event)
You could perform the task in the background using performSelectorInBackground:...:
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html
This prevent that selector from blocking the main thread.
Example:
[self performSelectorInBackground:#selector(myMethod) withObject:nil];
Do it in a background thread. Leave the main thread to deal with UI stuff only.
Technically you could divide the copying of files into very small chunks, and tell the current NSRunLoop to dispatch between each file copy.
But practically just say no to any IO access on the main thread, all IO access should be done in the background. Even the slightest block on the main thread will make the UI stutter and be unresponsive, Android user might accept that, iOS user do not.
Your options are numerous, and easy to implement. You could do a simple performSelector–:
-(void)backgroundWorker {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Do your stuff
[pool release];
}
-(void)startDoingIOStuff {
[self performSelectorInBackground:#selector(backgroundWorker)
withObject:nil];
}
You could do it practically inline using a block and GCD:
-(void)startDoingIOStuff {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL),
^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Do your stuff
[pool release];
});
}
Or you could use an NSOperation on a NSOperationQueue. I have written a longer blog post on this topic, including source code that is available here: http://blog.jayway.com/2010/08/19/future-cocoa-operation/
Before immediately resorting to a secondary thread, it would certainly be worth a try to use a plain old performSelector on self. For example:
[self peformSelector:#selector(copyFiles) withObject:nil afterDelay:0.0];
Note that this is different from doing:
[self copyFiles];
The peformSelector version basically says "do copyFiles ASAP, OK?", but doesn't block everything while waiting for it to be done. In other words, it's possible that the perform selector version would allow the main event loop to update the UI (thereby preventing the apparent visual lag) before the file copying is actually done.

Activity indicator as one table view loads another

I've been trying for about a day to get a table cell to display an activity indicator while it loads a new view. Upon didSelectRowAtIndexPath I'd like to display the indicator while the following runs
[self.navigationController pushViewController:subKeywordController animated:YES];
This controller then runs a fairly intensive SQL query
I've searched the web and read dozens of posts but none seem to help with my specific problem. I understand that I need to run the indicator in another thread because the push and subsequent load takes precedence but I'm unsure how to do it. I thought about running the SQL query in the controller before but that's getting very messy.
The odd thing is that I've been using MBProgressHUD to display busy cursors in this same table view with no issues. It's only when I apply a search and then select one of the results that causes this error:
bool _WebTryThreadLock(bool), 0x1d79b0: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
The app continues on the iPhone but crashes the simulator.
Any help would be greatly appreciated.
The problem is that your task in the controller is holding up the UI code (but you probably already know that!). A cheap and easy way of solving this is to put a tiny delay on starting your slow task (in this case your SQL query) using a timer :
- (void)viewDidLoad {
[super viewDidLoad];
// instead of running the SQL here, run it in a little bit
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(doSQL:) userInfo:nil repeats:NO];
// Show the please wait stuff
[activityIndicator setHidden:NO];
}
- (void)doSQL:(NSTimer *)timer {
// Do your sql here
}
The other way of solving this is to move your SQL into a seperate thread :
- (void)viewDidLoad {
[super viewDidLoad];
// instead of running the SQL here, run it in a little bit
[self performSelectorInBackground:#selector(doSQL) withObject:nil];
// Show the please wait stuff
[activityIndicator setHidden:NO];
}
- (void)doSQL {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Do your sql here
// Tell the main thread
[self performSelectorOnMainThread:#selector(doneSQL) userInfo:nil waitUntilDone:YES];
// Cleanup
[pool release];
}
- (void)doneSQL {
// Update your UI here
}
Hope that helps!

NSTimer doesn't work without UIApplication?

I have a custom iPhone application which doesn't rely on UIKit in any way (it is not linked to UIKit). This means that I'm not using UIApplication and therefore not calling UIApplicationMain.
The problem is that when I create a timer it never fires. The timer is created like that:
[NSTimer timerWithTimeInterval:10 target:self selector:#selector(updateTime) userInfo:nil repeats:TRUE];
I am suspecting that the problem might be run-loop related as after I finish basic initialization in "main()" , I do this:
NSLog(#"Starting application ...");
applicationInstance = [MyApp alloc];
[applicationInstance setMainLayer:mainLayer];
[NSThread detachNewThreadSelector:#selector(runApplication) toTarget:applicationInstance withObject:nil];
CFRunLoopRun();
I reverse-engineered UIKit and noticed that UIApplication does much more things like registering for system events etc. NSTimer might be relying on one of those things. The other thing I've noticed is that in UIApplication's delegate the thread is the same as in main().
How do I get NSTimer to work properly? If it is run-loop related, can someone point out the error? "CFRunLoopRun()" is used to hang up the main thread so the rest of the application can run. I don't think it is right though.
Edit: I think the run loop needs to be configred. Somehow ...
Your problem is definitely run loop-related; see the NSTimer reference, specifically, the introduction:
Timers work in conjunction with run loops. To use a timer effectively, you should be aware of how run loops operate—see NSRunLoop and Threading Programming Guide. Note in particular that run loops retain their timers, so you can release a timer after you have added it to a run loop.
The solution was pretty simple
NSTimer * timeUpdateTimer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(updateTime) userInfo:nil repeats:TRUE];
[[NSRunLoop mainRunLoop] addTimer:timeUpdateTimer forMode:NSDefaultRunLoopMode];
Thanks for the tip Shaggy Frog

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.