I have to loop in particluar method which do some task. I have used the method performselectoronmainthread wait until done method. Its working fine if i call it for once. But It fails when I call it in for loop. ie
this is the code:
for (int i=1;i<=3;i++) {
ip=i;
[self performSelectorOnMainThread:#selector(createThread:) withObject:ip waitUntilDone:YES];
}
-(void)createThread:(NSString*)ipIs
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Ip address is :%#",ipIs);
[SimplePingHelper ping:ipIs target:self sel:#selector(Result:)];
[pool release];
}
- (void)Result:(NSNumber*)success {
//do some stuff
}
The problem is that this code works fine when I run this loop once and It calls Result method. But it execution path changes when I try to use loop in performSelectorOnMainThread to pass different variables into it.Then It doesnt call result method.
I am looping because I want to run these same methods on different variables but task to be performed would be same.I am also using waituntil done:YES value..but still it is not working
Any idea ?
try creating other thread
myThread = [[NSThread alloc] initWithTarget:self selector:#selector(setupTimerThread) object:nil];
[myThread start];
-(void)setupTimerThread
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
timer2 = [NSTimer timerWithTimeInterval:0.04
target:self
selector:#selector(triggerTimer:)
userInfo:nil
repeats:YES];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer2 forMode:NSDefaultRunLoopMode];
[runLoop run];
[pool release];
}
-(void)triggerTimer:
{
//this method will be called in loop set loop interval by setting the timers time duration in above method
}
EDIT :
int ip=0;
-(void)triggerTimer:
{
ip++; // till ip<=3
[self createThread:ip];
}
Related
I have an NSOperation running on a background thread, and I want to change a property of it, a float named runSpeed, upon getting a memory warning on the main thread. The next time the background thread hits runSpeed though, it appears to be the same value it was previously.
How can I make sure it changes in the NSOperation thread when i change it on the main thread?
EDIT:
Didn't post code originally because I assumed I was thinking about it wrong. Here's my code:
AppDelegate
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
NSLog(#"memory warning");
if (dataUpdateIsActive) {
NSLog(#"data update is active");
dataUpdate.runSpeed = 10;
[NSTimer scheduledTimerWithTimeInterval:10
target:self
selector:#selector(resetRunSpeed)
userInfo:nil
repeats:NO];
}
}
Then in a method:
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
dataUpdate = [[JDataUpdate alloc] init];
[dataUpdate setOldPSC:[oldContext persistentStoreCoordinator]];
[dataUpdate setCurrentPSC:[newContext persistentStoreCoordinator]];
[dataUpdate setRunSpeed:0.5];
[dataUpdate setEntriesToCreate:250];
[dataUpdate setSaveFrequency:10];
dataUpdateIsActive = YES;
[operationQueue addOperation:dataUpdate];
Both of those NSLogs get triggered.
NSOperation
- (void)main
{
for (NSInteger index = 0; index < [self entriesToCreate]; ++index) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:[self runSpeed]]];
}
}
I am using NSThread along with NSTimer.
My code is like this
-(void) checkForRecentAlarm
{
if ([self.alarmThread isFinished])
{
[self.alarmThread cancel];
}
self.alarmThread = [[NSThread alloc] initWithTarget:self selector:#selector(startTimerForRecentAlarm) object:nil];
[self.alarmThread start];
//[NSThread detachNewThreadSelector:#selector(startTimerForRecentAlarm) toTarget:self withObject:nil];
}
-(void)startTimerForRecentAlarm
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
self.recentAlarmTime = [NSDate date];
self.dbObject = [[RADataBaseModelManager alloc] init];
self.recentAlarmTime = [self.dbObject getMostRecentAlarmTimeFromDB];
if (self.recentAlarmTime) {
NSTimeInterval timeIntervalToAlarm = [self.recentAlarmTime timeIntervalSinceNow];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
//Fire timer every second to updated countdown and date/time
self.RATimer = [NSTimer scheduledTimerWithTimeInterval:timeIntervalToAlarm target:self selector:#selector(timerFireMethod:) userInfo:nil repeats:NO];
[runLoop run];
}
[pool release];
}
- (void)timerFireMethod:(NSTimer*)theTimer
{
[self.RATimer invalidate];
[theTimer invalidate];
self.RATimer = NULL;
theTimer = NULL;
[self playAlarm];
UIAlertView *alarmAlert = [[UIAlertView alloc] initWithTitle:#"Alarm" message:#"" delegate:self cancelButtonTitle:#"Close" otherButtonTitles:#"Snooze", nil];
[alarmAlert show];
[alarmAlert release];
alarmAlert = nil;
}
Now the problem is, my alertbox comes twice for one call in the
startTimerForRecentAlarm
method. So that the alert comes consequently twice and my view get stuck.
What will be problem here?
I am trying to implement an alarm with multiple alarm option using a single NSTimer.
Please help.
When I debug this, I can find many simultaneous threads are running on same code(UIAlertView).
I can't see any obvious reason why that would be called twice, but it does seem like an overly complex way of doing what you need to do.
Have you thought about using local notifications?
If you don't want to do that, you could refactor your code so it works like this:
1. Add a new event
2. If there's no timer or the time to the event is shorter than the time on the timer, then set the timer for this event.
3. When a timer fires, check for the next event and set a timer for that event (if there is one).
This does seem really complex. My general observation is that if you get two timer firings it's because you have two timers for some reason.
If you have multiple threads doing UIAlertView, you have another problem, because you can only (reliably) do UI from the main thread.
I am using Background Thread to update one of my label
I am using the following code. But in iOS 4.0 i have learn that application saves its states and goes to background. and my application also did that work but the thread i am using stops working when i hide the application and again resumes from where i left when i reopen it. Can anybody please tell me what do I need to change in code in order to make the thread keep on running in background and change my GUI while my application is hidden. I am using this code..
-(void)startThread
{
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:#selector(setUpTimerThread) object:nil];
[thread start];
}
-(void)setUpTimerThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSTimer *timer = [NSTimer timerWithTimeInterval:3 target:self selector:#selector(triggerTimer) userInfo:nil repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];
[runLoop run];
[pool release];
}
-(void)triggerTimer
{
NSLog(#"***Timer Called after 3 seconds*** %d",count);
self.label.text = [NSString stringWithFormat:#"count value = %d",count];
//self.titleLabel.text= [NSString stringWithFormat:#"count value = %d",count];
count = count +1;
}
Thanks
Timers won't work on relaunch of the application. What you need to do is reinitialize the timer from your appDelegate's applicationDidBecomeActive: method and make sure you shut down the timer from applicationWillEnterBackground: method
I am working on performing some tasks in the background every 60 seconds. The background task is the server requests documents to be downloaded form the website. The main thread/UI seems to be locking when the request is done and I am saving the data to sqlite.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread detachNewThreadSelector:#selector(startTheBackgroundSync) toTarget:self withObject:nil];
[pool release];
- (void)startTheBackgroundSync {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// [self performSelectorInBackground:#selector(moveSynctoBack) withObject:nil];
// [self performSelectorOnMainThread:#selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];
serverSync = [[[ServerSync alloc]init]autorelease];
while (1==1) {
serverSync.delegate = self;
[serverSync syncNow:nil];
[NSThread sleepForTimeInterval:120];
}
[pool release];
[serverSync release];
}
While the looping does not lock up the main thread, but when ASIHTtpRequest finished with the data it locks up the ui for a second.
The finished selector of an ASIHTTPRequest will always be performed on the main thread. Therefore you shouldn't do long running tasks there.
Instead of launching a new thread you can schedule a repeated NSTimer:
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:120 target:self selector:#selector(backgroundSync) userInfo:nil repeats:YES];
... with the following action method:
-(void) backgroundSync
{
ServerSync* serverSync = [[[ServerSync alloc]init]autorelease];
serverSync.delegate = self;
[serverSync syncNow:nil];
}
Be sure that you use the startAsynchronous-method in ServerSync to start the request!
Furthermore I'd recommend to implement a singleton and then use it like that:
-(void)init {
[[ServerSync sharedSync] setDelegate:self];
}
-(void) backgroundSync
{
[[ServerSync sharedSync] syncNow];
}
I'm having trouble with a simple threading example. I know my methods aren't complete, but as of now, I want to press the start button and have that fire off a thread that increments a counter every second. I know it's connected in IB correctly since the NSLog tells me it gets to my timerThread method. But then it immediately jumps back to the initial myThread, without ever reaching the updateDisplay method and releases the pool, which is why I am guessing my program doesn't actually increment a counter. I thought I would then put it in a sleep interval or something, but in the end I think I am missing the correct way to achieve this. Any thoughts would be great. Thanks!
#implementation MainController
-(id)initWithLabel:(UILabel *)label {
if (self = [super init]) {
countLabel = label;
[countLabel retain];
}
return self;
}
-(int)count {
return count;
}
-(void)setCount:(int) value {
count = value;
}
-(void)updateDisplay:(NSTimer *)timer {
NSLog(#"%s", __FUNCTION__);
countLabel.text = [NSString stringWithFormat:#"%i", count];
count++;
}
-(void)timerThread {
NSLog(#"%s", __FUNCTION__);
[NSTimer timerWithTimeInterval:1.0
target:self
selector:#selector(updateDisplay:)
userInfo:nil
repeats:YES];
//NSNumber *threadID = [NSNumber numberWithInt:(int)threadID];
// threadLabel = [NSString stringWithFormat:#"%#", threadID];
}
-(void)myThread {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//NSNumber *threadID = [NSNumber numberWithInt:(int)threadID];
[self performSelectorOnMainThread:#selector(timerThread)
withObject:nil
waitUntilDone:NO];
// NSLog(#"threadID in myThread: %#", threadID);
[pool release];
}
-(void)startThread {
// threadIndex = 0;
// numThreads = 0;
// NSNumber *threadID = [NSNumber numberWithInt:threadIndex++];
[self performSelectorInBackground:#selector(myThread) withObject:nil];
// NSLog(#"%i", threadIndex);
numThreads++;
}
-(void)myThreadStop {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread exit];
[self performSelectorOnMainThread:#selector(updateDisplay)
withObject:nil
waitUntilDone:NO];
[pool release];
}
-(void)stopThread {
[self performSelectorInBackground:#selector(myThreadStop) withObject:nil];
}
-(void) dealloc {
[countLabel release];
[super dealloc];
}
#end
The short answer is that you did not schedule the timer.
iOS (and others) use run loops. Each thread may have a run loop, and the main UI thread has a run loop set up for you. Simplistically, a run loop keeps a queue of things to do and either does them in an ordered fashion or blocks until there is something to do.
Anything that you do with the active UI, like setting the text of a UILabel, must be done on the main thread. In your case, you have set up (but not scheduled) a timer on the main thread to update the timer. Scheduling a timer just means adding it to the run loop.
If you had a lengthy task to perform that would update the UI at the end, you could use performSelectorInBackground to start the lengthy task and performSelectorOnMainThread when the task finishes to update UI.
If you have a short periodic task, such as updating a clock or counter UI, you can just create an NSTimer on the same thread you want the timer to fire on. When creating the timer, use a scheduledTimerWithTimeInterval variant so it will start firing automatically.
When you create a repeating timer, you must keep a reference to it so you can invalidate the timer before the target is released. At the latest, in dealloc you should invalidate the timer.
Instead of calling startThread, turn timerThread into startTimer.
-(void) startTimer {
timerMember = [[NSTimer
scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateDisplay:)
userInfo:nil
repeats:YES] retain];
}
-(void) dealloc {
[timerMember invalidate];
[timerMember release];
...
}