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查询的模式,这些模式已经过审查并且运行良好.
使用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.