如何使用iOS中的AFNetworking定期从REST界面轮询/拉出

时间:2014-05-07 17:59:40

标签: ios objective-c networking afnetworking afnetworking-2

我正在建立一个"监控"我的iPhone上的应用程序。我正在使用AFNetworking-2.0。我有一个后端服务器公开一个用Python3 / tornado编写的RESTful接口。

根据我ViewController的级别,我想用不同的查询轮询不同的数据(应用程序的焦点调整查询的焦点)。为了#34;让它工作",我已经设置了以下内容:

#pragma mark - Pull Loop

- (void) forkPull {
    NSString* uri = [NSString stringWithFormat: @"%@/valves",  Site.current.serialID];
    [[HttpConnection current]
        GET: uri
        parameters: @{}
        success:^(NSURLSessionDataTask* task, id responseObject){
            [Site.current performSelectorOnMainThread: @selector(fromDoc:) withObject:responseObject waitUntilDone:YES];
            NSTimeInterval delay = 60; // default poll period
            // attempt to hone in if we have valid lastTouch info
            if (Site.current.touched != nil) {
                NSDate *futureTick = [Site.current.touched dateByAddingTimeInterval: 65];
                if ([futureTick compare: [NSDate date]] == NSOrderedDescending) {
                    delay = futureTick.timeIntervalSinceNow;
                }
            }
            [self performSelector: @selector(forkPull) withObject:nil afterDelay:delay];
            NSLog(@"%@ forkPull again in %f", self, delay);
        }
        failure:^(NSURLSessionDataTask* task, NSError* error){
            NSLog(@"%@ forkPull error: %@ (uri=%@)", self, error, uri);
            [self performSelector: @selector(forkPull) withObject:nil afterDelay:60];
        }
    ];
}

- (void) stopPull {
    [NSObject cancelPreviousPerformRequestsWithTarget: self];
}

#pragma mark - View Management

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear: animated];
    ....
    [self forkPull]; // start up polling while I'm visible
}

-(void) viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self stopPull]; // I'm going away, so shut down the pull loop?
    ...
}

基本上,当控制器的视图出现时,它会发送一个REST查询(当它异步返回时,它会在fromDoc:方法中更新模型;控制器有KVO个关系设置将导致UI更改。更新完成后,它能够估计何时应该进行下一次拉动,并使用performSelector:withObject:afterDelay:进行计划。当另一个控制器占据中心位置时,{{ 1}}方法尝试停止已排队的任何viewWillDisappear:

虽然这种方法有效。我很确定它没有通过"做对了"测试。我对所有任务和后台工作的工作方式都很天真,但在我看来,forkPull会增加自己的级别,因此我的AFNetworking可能无效。我已经在我的stopPull输出中看到了一些证据,看起来控制器不再位于顶部,仍然有循环运行。

但我确定其他人之前已经做过这种模式。我很想知道如何更好地构建/实现它。我正在寻找某人分享他们用于执行半周期REST查询的模式,这些模式已经过审查并且运行良好。

1 个答案:

答案 0 :(得分:6)

使用Grand Central Dispatch:

@property (strong, nonatomic) dispatch_source_t timer;

- (void)startTimer
{
    if (!self.timer) {
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    }
    if (self.timer) {
        dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), 60ull*NSEC_PER_SEC, 10ull*NSEC_PER_SEC);
        dispatch_source_set_event_handler(_timer, ^(void) {
            [self tick];
        });
        dispatch_resume(_timer);
    }
}

- (void)tick
{
    // Do your REST query here
}

这将每60秒调用一次tick方法。

要暂停和恢复计时器,请使用dispatch_suspend和dispatch_resume:

dispatch_suspend(self.timer);
dispatch_resume(self.timer);

您可以在以后随时调用dispatch_source_set_timer以更快地安排滴答或将其推迟到以后:

// Fire sooner than 60 seconds, but resume 60s fires after that
unsigned long long delaySeconds = arc4random() % 60;
dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, delaySeconds * NSEC_PER_SEC), 60ull*NSEC_PER_SEC, 10ull*NSEC_PER_SEC);

有关此问题的完整文档,请参阅Apple Concurrency Programming Guide