2012-11-05 12 views
11

Viele, wenn nicht die meisten Webservices haben ein Ratenlimit für Clients. Delicious sagt, ein Client kann eine Anfrage pro Sekunde machen; Twitter hat Grenzen pro Endpunkt; Ich bin sicher Facebook und Flickr und Foursquare haben ihre eigene Idee.Wie beziehe ich meine iOS-Netzwerkanforderungen auf eine Sekunde ein

Sie können eine iOS-Anwendung problemlos auf eine einzelne Anfrage beschränken, indem Sie eine NSOperationQueue verwenden.

Aber wie schränkt man eine Anwendung darauf ein, sagen wir, nur eine Anfrage pro Sekunde?

Ich habe mir den Beispielcode von Apple, AFNetworking, ASINetwork und einigen anderen angeschaut, und keines scheint dieses Problem zu lösen. Das erscheint mir seltsam. Ich werde zugeben, dass ich etwas fehlen könnte sehr offensichtlich ...

Einige Parameter:

  • Angenommen ich ein NSOperationQueue für den Netzbetrieb und die Anforderung ist ein NSOperation (könnte auch ein GCD sein ich nehme an, aber das ist, woran ich meistens gearbeitet habe)
  • Das gleiche Rate-Limit wird für jede Anfrage in der Warteschlange verwendet
  • Ich bin auf der Suche nach einer Lösung in iOS, aber allgemeine Ideen könnten nützlich sein

Mögliche Lösungen:

  • sleep Anweisung in der NSOperation (es ist eine Warteschlange/Thread so würde dies nichts anderes blockieren)
  • NSTimer im NSOperation
  • performSelector: in der NSOperation (I patched ASINetworking to use this approach , obwohl ich es nicht verwende und die Änderung nicht stromaufwärts geschoben habe)
  • Starten/stoppen Sie die Warteschlange (mit KVO?), um sicherzustellen, dass die Rate limi t wird nicht überschritten
  • Special "Schlaf" NSOperation. Dies wäre eine Aufgabe, die die nächste Netzwerkbetrieb abhängig wäre, auf
  • vollständig die Rate Limit ignorieren und nur ein bisschen Pause, wenn Sie die „überschritten Rate Limit“ Fehlerreaktion

Diese alle scheinen, ziemlich chaotisch. Vorgänge, die in den Ruhezustand versetzt werden, würden wahrscheinlich Formen von Warteschlangen "Priorität" verhindern. Das Starten/Stoppen der Warteschlange scheint fragil zu sein. Das Limit zu ignorieren ist unhöflich.

Um klar zu sein, habe ich dieses Problem gelöst. Aber die Lösung scheint "unordentlich" und etwas zerbrechlich. Ich würde gerne wissen, ob es eine bessere, sauberere Option gibt.

Ideen?

Antwort

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 

und in Ihrem async Rückruf

[myNSOperationSubClass setComplete]; 
+0

Vielen Dank für Ihre Hilfe. Das sieht ziemlich genau so aus, wie ich es mir für meine Option 2 vorgestellt habe, aber da Sie genau zeigen, wie es geht, und es keine abweichenden Ansichten gibt, werde ich Ihre Antwort akzeptieren. –

-1

KEINEN PREIS SOLUTION EINZUSCHRäNKEN, aber in der Nähe

ich zu bewerten, um meine Anfrage benötigt begrenzen eine 429 Reaktion ausgelöst zu vermeiden durch zu viele Anfragen.

Mögliche Lösung, vorausgesetzt, Sie haben Ihr Netzwerkmodul bereits mit anderen Technologien als NSOperation implementiert.

Verwenden Sie GCD, um dieses Problem zu lösen. Der folgende Code führt eine Verzögerung von 1 Sekunde zu jedem Netzwerkanruf ein. Achten Sie auf den Parameter für popTime

- (void)main { 

     for (NSInteger index = 0; index < 10; index++) { 
      [self networkCallWithDelay:1.0f]; 
     } 
    } 

// Ihr Netzwerk-Code geht hier

- (void)networkCallWithDelay:(double)delay { 

    double delayInSeconds = delay/10.0f; 

    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 

     // Your asynchronous network call goes here 
    }); 
} 
+0

Das ist völlig inkorrekt, es gibt überhaupt kein Ratenlimit ... Alles was es tut ist, die Netzwerkanrufe eine Sekunde später auszuführen, aber genauso viele von ihnen pro Sekunde. –

+0

@einsteinx2 kannst du bitte OP's Frage nochmal lesen, fragt er. "Aber wie schränkt man eine Anwendung ein, um beispielsweise nur eine Anfrage pro Sekunde zu machen? " – Edwin

+0

Ja, ich verstehe das. Wie auch immer, ich lese gerade Ihre Antwort erneut und sehe, dass Sie tatsächlich eine einfache Form der Ratenbegrenzung durchführen, indem Sie die Verzögerung in 10 Sekunden teilen. Ich hatte die Division verpasst und dachte, dass Sie nach einer 1-sekündigen Verspätung nur den Anruf tätigen würden. Ich glaube, ich war nur müde, tut mir leid. Ich habe meine Down-Abstimmung entfernt. –

Verwandte Themen