5

I am trying to determine the best strategy to poll a webservice once a minute, parse the xml returned and then update an object stored in a shared instance. This process needs to run in a separate thread, and will continue as long as the app is running.

It seems that I could put all the code to call the webservice and parse the xml into an NSOperation and add that NSOperation to an NSOperationQueue stored in the app delegate as soon as the app launches.

Is it a correct approach to use an NSTimer inside the main method of the NSOperation so that the operation will loop once a minute, indefinitely? In that scenario the NSOperation would never actually return - this seems what I want but I am not sure if this is the right way to think about it.

The problem I am trying to solve is of course extremely common, so I am trying to figure out the correct way to implement it. Any advice greatly appreciated.

Black Frog
  • 11,595
  • 1
  • 35
  • 66
JohnRock
  • 6,795
  • 15
  • 52
  • 61
  • I'm still learning the intricacies of NSTimer, but I've had problems using them in non-main threads, so I'm thinking you might end up with the timer in your main thread, adding operations to your operationqueue, rather than having the timer IN the new thread...if you end up using the solution you proposed – Robot Woods Apr 04 '11 at 03:15

4 Answers4

0

The real correct way to do it is to use push notifications. If any of your users have cell plans with limited data or data charged based on usage, they will thank you for it.

But if you insist on polling, you may as well use the NSTimer directly rather than messing with a timer inside an NSOperation. This will run on the main thread, but you could have the timer callback use performSelectorInBackground:withObject: to do processing in the background. Or you could just skip the timer altogether and run the whole polling sequence on a separate NSThread, and use sleepForTimeInterval: to delay between polls.

Anomie
  • 92,546
  • 13
  • 126
  • 145
  • Thanks for your input. I don't think that push notifications are always the correct way however. The data that I am updating is actually essential to the app itself and needs to be updated when the app is in the foreground. I'm not sure if I understand why you think it is better to run the timer on the main thread..? And as for using NSThread, I was under the impression that the preferred way is to use an NSOperationQueue - no? – JohnRock Apr 04 '11 at 03:26
0

I would highly recommend you take a look at ASIHTTPRequest. What an amazing little class, and really well documented.

Edit:

Take a look at this answer for what seems to be the optimal solution.

Community
  • 1
  • 1
Mike A
  • 2,501
  • 2
  • 23
  • 30
  • Can you mention how that class relates to the question I asked? How would it help? – JohnRock Apr 08 '11 at 13:44
  • It has a really nice implementation of an NSOperation queue that runs asynchronously. It would be pretty easy to have an NSTimer simply add a request to the queue if you are, as I would assume, performing other actions that require http requests. Or am I misunderstanding your problem? – Mike A Apr 08 '11 at 19:38
  • Well I think the main point of confusion that I have is if I use an NSTimer, where should that timer be? Should it run on the main UI thread and launch a new operation once a minute? Or can/should the entire polling mechanism live in its own thread and leave the main thread free? Does ASIHTTPRequest address that at all? – JohnRock Apr 09 '11 at 03:30
  • Not really, it just helps manage the http calls and queue. I'm sorry I misunderstood your question, and I'm not quite sure what the "optimal" solution is. I edited my answer with a post that should help. – Mike A Apr 09 '11 at 06:25
0

one approach: create a thread and use a run loop, updating or idling as appropriate. then you can perform the request from the secondary thread and post it to the rest of the app after it's been parsed/prepped.

this way offers more control over pause/resume/delays/timing, and you can easily control the number of active requests (which should be exactly zero or one).

justin
  • 104,054
  • 14
  • 179
  • 226
-1

I wouldn't use NSTimer for this problem/design. I would create NSThread from the AppDelegate when the application starts. I would lower the priority of this thread. Inside the NSThread main method is basically a loop.

-(void)main {

    while(true) {
        // get raw data from url
        // hash the result
        // compare the hash to the last time
        if (currentHash != lastHash) {
          // post a notification to default center with the new data
          lastHash = currentHash;
        }
        // sleep the thread sleepForTimeInterval
    }
}

Your Model object would subscribe to the notification from the thread and parse the new data and updates ivars. Your View object would listen to the Model using KVO and display any updates/changes.

Black Frog
  • 11,595
  • 1
  • 35
  • 66
  • in this pattern what method should I be using to make an authenticated request to get the xml data from a webservice? Does it have to be a synchronous request? Should I be using ASIHTTPRequest like Mike A recommends? – JohnRock Apr 09 '11 at 23:26
  • Since it's not on the main thread, it easier to make the call synchronously. And yes, you would be using something along the lines of [NSURLConnection](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html). And yes, using [ASIHTTPRequest](http://allseeing-i.com/ASIHTTPRequest/) library would make life a lot easier. – Black Frog Apr 10 '11 at 00:41