12

I need to poll data from server periodically in my iOS application. I need to do it every 10 seconds in a thread, in order to keep the UI usable. This function will be fired when the user logs in. I'm thinking about using NSRunLoop with NSTimer to achieve this functionality, and maybe use AFNetworking to get JSON data.

Is this the correct approach? Should this be done using GCD?

amb
  • 4,798
  • 6
  • 41
  • 68

1 Answers1

19

Probably the only part that must be done off the main thread is the request itself. Deciding that you need a request and forming that request can be done without any fancy stuff...

Agree with H2CO3 that polling might become a problem for your server with too many clients in the wild, but also agree with you that it's not necessarily a mistake in all cases.

Setup a timer ...

[NSTimer scheduledTimerWithTimeInterval:10.0
                                 target:self
                               selector:@selector(timerFired:)
                               userInfo:nil
                                repeats:YES];

Run a request ...

- (void)timerFired:(NSTimer *)timer {

    NSURLRequest *request = // setup your request
    [NSURLConnection sendAsynchronousRequest:request 
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
    if (!error) {
       // change my model in an observable way, or
       // if we're in a vc, change my model and update the UI

       // if we want to stop polling, [timer invalidate];
    }
}];

NSTimer fires periodically. Upon fire, a method (on the main thread) decides if it needs to poll (in the case you described, always 'yes' if it's called on a 10sec period). Form the request, NSURLConnection sendAsynchronousRequest: will move the slow part of the request off the main. The block on sendAsynch runs back on the main when the request is done.

The trick is that other parts of your app need to be setup to observe changes in the model and update the views. This may be as simple as doing a table reload in the sendAsynch block, or more complex, like setting up KVO that will trigger as the model changes.

danh
  • 62,181
  • 10
  • 95
  • 136
  • Great approach, I'll try it as soon as I can. I've also thought about using `NSNotificationCenter`, do you think that it's a good approach to notify other VC? – amb Oct 30 '12 at 15:35
  • Yes, I think NSNotification is a good way to notify more broadly. The VCs listening probably don't need to do anything unless their view is visible. The logic on notification would be, if my view is visible, call some update view logic. Call that same logic on viewWillAppear. Here's an SO post about checking if view is visible... http://stackoverflow.com/questions/2777438/how-to-tell-if-uiviewcontrollers-view-is-visible – danh Oct 30 '12 at 17:53
  • 1
    Finally, I've implemented this poll using both `NSTimer` and a singleton. I use this singleton in all my app, so it's always updating from server. – amb Nov 28 '12 at 11:19
  • @danh what about using Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false, block: {timer in ...}) ?? https://gist.github.com/omarojo/512cf0b18eb6952cc4cb19434a6510a1 Could that cause any memory error in long run or something? is it necesary to invalidate the global timer ? – omarojo May 03 '17 at 11:32
  • @omarojo - that code looks okay. there's no memory related reason to invalidate that timer. – danh May 03 '17 at 13:18