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

Tra*_*ggs 3 networking objective-c ios afnetworking afnetworking-2

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

根据ViewController我所处的水平,我想用不同的查询轮询不同的数据(应用程序的焦点调整查询的焦点).为了"让它成功",我设置了以下内容:

#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?
    ...
}
Run Code Online (Sandbox Code Playgroud)

基本上,当控制器的视图出现时,它会发送一个REST查询(当它异步返回时,它将更新fromDoc:方法中的模型;控制器KVO设置了关系,这将导致UI更改.更新完成后,它可以近似关于什么时候它应该进行下一次拉动,并安排使用performSelector:withObject:afterDelay:.当另一个控制器占据中心阶段时,该viewWillDisappear:方法试图阻止任何forkPull已经排队的s.

虽然这种方式有效.我很确定它没有通过"正确的"测试.关于所有任务和后台工作如何工作,我很天真,但在我看来,它AFNetworking增加了自己的水平,所以我stopPull可能没有效果.我已经看到了一些关于我的NSLog输出的证据,似乎那些不再位于顶部的控制器仍然有循环运行.

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

kdt*_*kdt 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
}
Run Code Online (Sandbox Code Playgroud)

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

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

dispatch_suspend(self.timer);
dispatch_resume(self.timer);
Run Code Online (Sandbox Code Playgroud)

您可以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);
Run Code Online (Sandbox Code Playgroud)

有关此内容的完整文档,请参阅Apple Concurrency Programming Guide.