2012-11-05 5 views
11

Molti, se non la maggior parte, i servizi Web hanno un limite di velocità per i client. Delicious dice che un cliente può fare una richiesta al secondo; Twitter ha limiti per end-point; Sono sicuro che Facebook, Flickr e Foursquare hanno una loro idea.Come si limita il limite delle richieste della rete iOS a un secondo

È possibile limitare facilmente un'applicazione iOS a una singola richiesta alla volta utilizzando uno NSOperationQueue.

Ma come si limita un'applicazione a fare, diciamo, solo una richiesta al secondo?

Ho esaminato il codice di esempio di Apple, AFNetworking, ASINetwork e alcuni altri, e nessuno sembra risolvere questo problema. Questo mi sembra strano. Ti concedo che potrei mancare qualcosa molto ovvio ...

Alcuni parametri:

  • Si supponga Ho un NSOperationQueue per le operazioni di rete e la richiesta è un NSOperation (potrebbe anche essere un GCD suppongo, ma è quello con cui lavoro principalmente)
  • Lo stesso limite di velocità viene utilizzato per ogni richiesta in coda
  • Sto cercando una soluzione in iOS, ma le idee generali potrebbero essere utili

Possibili soluzioni:

  • sleep economico nel NSOperation (si tratta di una coda di/thread quindi questo non bloccherebbe qualsiasi altra cosa)
  • NSTimer nel NSOperation
  • performSelector: nel NSOperation (I patched ASINetworking to use this approach , anche se non lo sto usando e non ho spinto il cambiamento a monte)
  • Avvia/arresta la coda (usando KVO?) per assicurarti che il tasso sia limitato t non viene superato
  • Speciale "sleep" NSOperation. Questo sarebbe un compito che il funzionamento della rete successivo sarebbe dipende
  • completamente ignorare il limite di velocità e solo mettere in pausa un po 'quando si ottiene il "limite di velocità superato" risposta di errore

Questi tutti sembrano piuttosto confusa. Le operazioni che dormono probabilmente impedirebbero forme di coda di "priorità". L'avvio/arresto della coda sembra fragile. Ignorare il limite è scortese.

Per essere chiari, ho risolto questo problema. Ma la soluzione sembra "disordinata" e alquanto fragile. Mi piacerebbe sapere se c'è un'opzione migliore e più pulita.

Idee?

risposta

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 

e nella vostra callback asincroni

[myNSOperationSubClass setComplete]; 
+0

Molte grazie per il vostro aiuto. Questo sembra più o meno quello che avevo in mente per la mia opzione 2 ma dal momento che mostri esattamente come farlo e non ci sono punti di vista dissenzienti, accetterò la tua risposta. –

-1

NON A rate limiting SOLUZIONE, MA VICINO

avevo bisogno di votare limitare la mia richiesta al fine di evitare una risposta 429 innescato da troppe richieste.

Soluzione possibile, presupponendo che il modulo di rete sia già stato implementato utilizzando altre tecnologie oltre a NSOperation.

Utilizzare GCD per risolvere questo problema. Il seguente codice introduce un ritardo di 1 secondo per ciascuna chiamata di rete. Prestare particolare attenzione al parametro per popTime

- (void)main { 

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

// Il codice di rete va qui

- (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

Questo è completamente errato, non limita affatto il limite ... Tutto ciò che fa è fare le chiamate di rete 1 secondo dopo, ma altrettante al secondo. –

+0

@ einsteinx2 puoi leggere di nuovo la domanda dell'OP, chiede. "Ma come limiti un'applicazione a fare, diciamo, solo una richiesta al secondo? " – Edwin

+0

Sì, lo capisco. Ad ogni modo rileggo la tua risposta e vedo che stai effettivamente facendo una semplice forma di limitazione della velocità dividendo il ritardo in 10 secondi. Avevo perso la divisione e pensavo che stavi facendo tutte le chiamate dopo un ritardo di 1 secondo. Suppongo che ero solo stanco, mi dispiace per quello. Ho rimosso il mio voto negativo. –

Problemi correlati