如何将我的iOS网络请求限制为一秒

Ste*_*ton 12 objective-c ios

许多(如果不是大多数)Web服务对客户都有速率限制.Delicious说客户每秒可以提出一个请求; Twitter每个终点都有限制; 我确信Facebook和Flickr以及Foursquare都有自己的想法.

您可以使用a一次轻松地将iOS应用程序限制为单个请求NSOperationQueue.

但是,如何将应用程序限制为每秒只生成一个请求?

我查看过Apple,AFNetworking,ASINetwork和其他一些代码的示例代码,似乎都没有解决这个问题.这对我来说似乎很奇怪.我会承认我可能会遗漏一些非常明显的东西......

一些参数:

  • 假设我有一个NSOperationQueue用于网络操作并且请求是一个NSOperation(我想也可能是一个GCD队列,但这是我一直在使用的)
  • 队列中的每个请求都使用相同的速率限制
  • 我正在寻找iOS中的解决方案,但一般的想法可能会有用

可能的解决方案:

  • sleepNSOperation(这是一个队列/线程中的语句,所以这不会阻止其他任何东西)
  • NSTimer 在里面 NSOperation
  • performSelector:NSOperation(我修补ASINetworking使用这种方法,虽然我没有使用它,并没有推动上游的变化)
  • 启动/停止队列(使用KVO?)以确保不超过速率限制
  • 特别"睡觉" NSOperation.这将是下一个网络操作将依赖的任务
  • 完全忽略速率限制,只是在收到"超出速率限制"错误响应时暂停一下

这些看起来都很混乱.睡眠的操作可能会阻止形式的"优先级"队列.启动/停止队列似乎很脆弱.忽略限制是粗鲁的.

要清楚,我已经解决了这个问题.但解决方案似乎"凌乱"而且有些脆弱.我想知道是否有更好,更清洁的选择.

想法?

del*_*ser 6

@implementation SomeNSOperationSubClass {
    BOOL complete;
    BOOL stopRunLoop;
    NSThread *myThread;
}

-(void) rateLimitMonitor:(NSTimer *)theTimer {
    [theTimer invalidate];
}

-(void) main {
    myThread = [NSThread currentThread];

    NSTimer *myTimer = [NSTimer timerWithTimeInterval:1 target:self  selector:@selector(rateLimitMonitor:) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode];

    [self doAsyncThing];

    while ((!stopRunLoop || [myTimer isValid]) && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
    complete = YES;
}

-(void) internalComplete {
    stopRunLoop = YES;
}

-(void) setComplete {
    [self performSelector:@selector(internalComplete) onThread:myThread withObject:nil waitUntilDone:NO];
}

-(BOOL) isFinished {
    return complete;
}

@end
Run Code Online (Sandbox Code Playgroud)

并在您的异步回调中

    [myNSOperationSubClass setComplete];
Run Code Online (Sandbox Code Playgroud)