Hi basé sur this answer J'ai écrit sous-classe de NSInputStream
et cela fonctionne plutôt bien.NSURLSession demande corps passé lentement NSInputStream (gestion de la bande passante)
Maintenant Il s'est avéré que j'ai un scénario où je alimente au serveur une grande quantité de données et pour éviter la famine des autres services, j'ai besoin de contrôler la vitesse d'alimentation des données. Donc, je me suis amélioré functinality de ma sous-classe avec les conditions suivantes:
- lorsque les données doivent être reportées,
hasBytesAvailable
renvoieNO
et tentatives de lecture se termine par zéro octets lus - lorsque les données peuvent être envoyées,
- read:maxLength:
permet de lire une certaine quantité maximale données à la fois (par défaut 2048). - lorsque
- read:maxLength:
renvoie 0 octets lus, le délai requis est calculé et après ce délai, l'événementNSStreamEventHasBytesAvailable
est envoyé.
est ici parties intéressantes de code (il est mélangé avec C++):
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len {
if (![self isOpen]) {
return kOperationFailedReturnCode;
}
int delay = 0;
NSInteger readCount = (NSInteger)self.cppInputStream->Read(buffer, len, delay);
if (readCount<0) {
return kOperationFailedReturnCode;
}
LOGD("Stream") << __PRETTY_FUNCTION__
<< " len: " << len
<< " readCount: "<< readCount
<< " time: " << (int)(-[openDate timeIntervalSinceNow]*1000)
<< " delay: " << delay;
if (!self.cppInputStream->IsEOF()) {
if (delay==0)
{
[self enqueueEvent: NSStreamEventHasBytesAvailable];
} else {
NSTimer *timer = [NSTimer timerWithTimeInterval: delay*0.001
target: self
selector: @selector(notifyBytesAvailable:)
userInfo: nil
repeats: NO];
[self enumerateRunLoopsUsingBlock:^(CFRunLoopRef runLoop) {
CFRunLoopAddTimer(runLoop, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes);
}];
}
} else {
[self setStatus: NSStreamStatusAtEnd];
[self enqueueEvent: NSStreamEventEndEncountered];
}
return readCount;
}
- (void)notifyBytesAvailable: (NSTimer *)timer {
LOGD("Stream") << __PRETTY_FUNCTION__ << "notifyBytesAvailable time: " << (int)(-[openDate timeIntervalSinceNow]*1000);
[self enqueueEvent: NSStreamEventHasBytesAvailable];
}
- (BOOL)hasBytesAvailable {
bool result = self.cppInputStream->HasBytesAvaible();
LOGD("Stream") << __PRETTY_FUNCTION__ << ": " << result << " time: " << (int)(-[openDate timeIntervalSinceNow]*1000);
return result;
}
j'ai écrit quelques essais pour cela et ça a marché.
Un problème est apparu lorsque j'ai utilisé ce flux avec NSURLSession
comme source du corps de la requête HTTP. De journaux, je peux voir que NSURLSession
essaie de tout lire à la fois. En première lecture, je renvoie une partie limitée des données. Immédiatement après cela NSURLSession
demande s'il y a des octets disponibles (je renvoie NO
). Après un certain temps (par exemple 170 ms), j'envoie une notification que les octets sont maintenant disponibles mais NSURLSession
ne répond pas à cela et n'appelle aucune méthode de ma classe de flux.
Voici ce que je vois dans les journaux (lors de l'exécution un certain test):
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper open]
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 1 time: 0
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper read:maxLength:] len: 32768 readCount: 2048 time: 0 delay: 170
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 0 time: 0
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 0 time: 0
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 0 time: 0
09:32:15161[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper notifyBytesAvailable:]notifyBytesAvailable time: 171
Lorsque le temps est le montant de millisecondes depuis a été ouvert flux.
Looks NSURLSession
est incapable de gérer les flux d'entrée avec un débit de données limité. Est-ce que quelqu'un d'autre a eu un problème similaire? Ou a un concept alternatif comment réaliser la gestion de la bande passante sur NSURLSession
?
'ASIHTTPRequest' est une solution (il supporte la limitation), mais mon projet est loin de se terminer, c'est-à-dire qu'il est déjà trop tard pour changer de framework utilisé. Aussi ce 'ASIHTTPRequest' ressemble à un projet abandonné et la directrice ne l'aime pas. –