1

I need to create a routine that save automatically a file content in a constant time period, ie, a backgroung loop that perform the save instructions. I thinked in use a recursive call of performSelector like below:

- (void)viewWillAppear:(BOOL)animated{

    [super viewWillAppear:animated];

    [self performSelector:@selector(saveMethod) withObject:nil afterDelay:kTimeConstant];

}

- (void)saveMethod{

     //The save logic should to be here

     [self performSelector:@selector(saveMethod) withObject:nil afterDelay:kTimeConstant];

}

It works, but when I get out of viewController, it still running, and it must to stop. are there any better way to execute it? Thank you!

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Lucio Fonseca
  • 3,477
  • 2
  • 17
  • 20
  • 1
    The code you've posted doesn't do anything in the background (ie. in a separate thread). Do you actually want to the save to happen on a non-main thread? – Andrew Madsen Jun 27 '13 at 16:59
  • 1
    If you don't want it to be execute, then you can cancel @selector method in `viewWillDissapear:` method. And this is not background method. It will call in main thread after delay. – TheTiger Jun 27 '13 at 17:03
  • I have a RichtextEditor, and I want to implement a autosaving that in a time period save the html content, but it doesn`t can lock the execution, to be invisible to the user, so I think that it should`t run in the Main Thread. – Lucio Fonseca Jun 27 '13 at 17:05
  • Thank you The Tiger for the explanation. I really don't know much about it. – Lucio Fonseca Jun 27 '13 at 17:10
  • And why it shouldn't run in main thread ?? Have you done anything for this ? If you want it in background then you should use [– performSelectorInBackground:withObject:](http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/performSelectorInBackground:withObject:) – TheTiger Jun 27 '13 at 17:10
  • Your requirement is not possible with single line method. You will have to run delay method in background. See below answer for how to run method in background. – TheTiger Jun 27 '13 at 17:22
  • The Tiger, the used cancelPreviousPerformRequestsWithTarget and it works fine! I still use the recursive call. Do you Agree that it is the best way? – Lucio Fonseca Jun 27 '13 at 17:46

2 Answers2

2

There is a function NSRunLoop cancelPreviousPerformRequestsWithTarget:selector:object: which allows you to cancel the performSelector call. Call this when you unload the view controller

ie.

 [NSRunLoop cancelPreviousPerformRequestsWithTarget:self selector:@selector(saveMethod) object:nil];
bengoesboom
  • 2,119
  • 2
  • 23
  • 27
2

This is probably a better implementation:

- (void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];

    // Start timer and sets it to a property called saveTimer
    self.saveTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
                              target:self
                            selector:@selector(saveMethod:)
                            userInfo:nil
                             repeats:YES];
}

- (void)saveMethod:(NSTimer*)theTimer {
     // The save logic should to be here
     // No recursion
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    // Stop timer
    [self.saveTimer invalidate];
}

This is running on the main thread so it is probably not the best implementation but it should work better than what you currently have.

Firo
  • 15,448
  • 3
  • 54
  • 74
  • it looks interesting for me. Thank you Firo! – Lucio Fonseca Jun 27 '13 at 17:26
  • I would not say it better implementation. – TheTiger Jun 27 '13 at 17:28
  • It really works fine, but the invalidade does't is stopping the timer =( – Lucio Fonseca Jun 27 '13 at 17:36
  • Thats what I'm trying to tell. Happy you got it :) – TheTiger Jun 27 '13 at 17:41
  • I know that it works like above, yet the documentation on `NSTimer` clearly states "The selector must correspond to a method that returns void and takes a single argument". – Nikolai Ruhe Jun 27 '13 at 18:03
  • @LucioFonseca I made a correction, thanks @NikolaiRuhe. It looks like `invalidate` works only if the method parameter list is correct. Look at my fix on the method (also make sure you add the `:` to `@selector(saveMethod:)`. If the `invalidate` still does not work for some reason try setting the timer to nil. – Firo Jun 27 '13 at 18:46