2013-03-23 4 views
10

Ich habe Probleme mit dem Herunterladen von 5 MB Datei, dauert es mehr als 2 Minuten auf iPhone 5 mit iOS 6.1.NSURLConnection sehr lange herunterladen

Mit iPhone 4S mit der gleichen iOS-Version dauert es nur 10 Sekunden, beide verwenden WiFi.

Ich habe versucht, verschiedene Cache-Richtlinien und Timeout-Intervall von NSURLRequest, es hat nichts geändert, es dauert immer noch lange Zeit. Der Download erfolgt über HTTP.

Ich benutze NSURLConnection Klasse, vor dem Download dieser "großen" Datei Ich lade zwei andere herunter.

Weiß nicht, was sonst noch wichtig sein kann, um die Zeit zu reduzieren.

Vielen Dank im Voraus.

Code:

@interface MyClass : NSObject <NSURLConnectionDelegate> 
{ 
    @private id delegate; 
    NSURLConnection *connection; 
    NSMutableData* responseData; 
    //... 
} 


#import "MyClass.h" 

@implementation MyClass 

-(void)getObj1:(id)delegateObj 
{ 
    delegate = delegateObj; 

    NSString *url = @"..."; 

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0]; 

    connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

    if(connection) 
    { 
     responseData = [NSMutableData data]; 
    } 
} 

-(void)getObj2:(*String)somesString 
{ 

    NSString *url = @"..."; 

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0]; 

    connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

    if(connection) 
    { 
    responseData = [NSMutableData data]; 
    } 
} 

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    //.... 
} 


-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    [responseData appendData:data]; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    if(firstRequest) 
    { 
     //save data from first request and set responseData clear 
     [self getObj2:@"..."]; 
    } 
} 

und andere, ohne etwas Besonderes, ich hoffe, diese

genug sein, werde ich diesen Beitrag https://devforums.apple.com/message/754875#754875 gefunden haben, aber immer noch nicht gut für mich funktioniert. Aber jetzt verstehe ich diese seltsame Situation besser.

+0

Ihr Code ist wichtig. Wenn Sie angeben könnten, wie Sie die Anforderung erstellt und gestartet haben, und die Delegatmethoden. –

+0

Irgendeine Idee? Vielleicht hilft dieser Link von meiner Bearbeitung, ich habe keine Ideen mehr – Meryl

+0

Sie sollten lieber _two_ Objekte Ihrer 'MyClass' erstellen, um zwei verschiedene Downloads durchzuführen. Sie können die Ivars schnell verwirren. Stellen Sie außerdem sicher, dass Sie [[NSURLConnection alloc] init ...] für den Thread aufrufen, in dem der Delegat ausgeführt werden soll. Möglicherweise der Hauptthread - ansonsten müssen Sie wissen, wie Sie einen sekundären Thread für diesen Zweck einrichten, der ein bisschen knifflig ist. – CouchDeveloper

Antwort

0

Haben Sie versucht AFNetworking? Es ist ein Wrapper auf NSURLConnection. Ich bin mir nicht sicher, ob es Ihnen helfen würde, einen schnelleren Download zu bekommen, aber es gibt Ihnen einen Vorteil gegenüber NSURLConnection.

+0

Basierend auf diesem Thema http://stackoverflow.com/questions/12570483/ios6-large-downloads-time-out?rq=1 Ich nehme an, dass es nicht hilft, aber ich werde das im nächsten Schritt überprüfen. Danke für die Antwort. – Meryl

+0

Ich habe versucht, aber es dauert immer noch die gleiche Zeit – Meryl

1

Verwenden Sie AFDownloadRequestOperation (AFNetworking "Unterklasse") - Sie können auch den Vorgang anhalten/fortsetzen.

Hier haben Sie ein Beispiel https://stackoverflow.com/a/12209618

+0

Ich habe kein ARC-Projekt und ich habe einige Probleme mit dieser Klasse – Meryl

0

Sie GCD verwendeten dispatch_async Warteschlange Anforderung auszuführen Satz von NSURLRequest Daten vom Server zum Download oder Server-Antwort zu bekommen.

NSString *webURL = @"http://therealurl.appspot.com/?format=json&url=bit.ly/a"; 
NSURL *url = [NSURL URLWithString:webURL]; 
NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:url]; 
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:awesomeRequest delegate:self]; 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul); 
dispatch_async(queue, ^{ 
    NSRunLoop *loop=[NSRunLoop currentRunLoop]; 
    [connection scheduleInRunLoop:loop forMode:NSRunLoopCommonModes]; 
    //[self processTheAwesomeness]; 
}); 
+1

Eine Verbindung sollte nicht über 'ScheduleInRunLoop: forMode:' in einer Dispatch-Warteschlange, die versucht, seine Laufschleife zu bekommen . Das wird nicht funktionieren, da die Laufschleife jederzeit (wenn überhaupt) verschwinden kann und der darunterliegende Thread jederzeit von Delegat zu Delegat wechseln kann. – CouchDeveloper

+0

Was er gesagt hat. Wenn Sie Ihre eigene Planung so handhaben und vom Hauptthread fernhalten möchten, müssen Sie den Hintergrundthread selbst erstellen und verwalten. Das heißt, im Fall einer einzelnen Übertragung, bei der es keine andere signifikante Aktivität im Hauptthread gibt, gibt es keinen Grund, sie nicht einfach auf den Hauptthread zu planen. – ipmcc

0

Ich bin mir nicht sicher, was Ihr Problem ist, aber der folgende Code funktioniert zuverlässig für mich.

- (id)init 
{ 
    self.downloadQueue = [[NSOperationQueue alloc] init]; 
    [self.downloadQueue setMaxConcurrentOperationCount:1]; 
} 

- (void)doDownload:(NSURL *)url 
{ 
    [self.downloadQueue addOperation:[NSBlockOperation blockOperationWithBlock:^{ 

    NSData *data =[NSData dataWithContentsOfURL:url]; 

    dispatch_sync(dispatch_get_main_queue(), ^{ 
     NSAutoreleasePool *mainQueuePool = [[NSAutoreleasePool alloc] init]; 

     ... update user interface ... 

     [mainQueuePool release]; 
    }); 

    }]]; 
} 
-1

Ich denke, es ist ein Problem in Ihrem Gerät. Versuchen Sie ein anderes Gerät von einem Freund.

0

Ich würde eine Lösung vorschlagen, wo Sie eine Art von Kommunikations-Manager haben, der eine NSOperationQueue behandelt, mit einem einzigen Einstiegspunkt-Methode, wo Sie geben Sie eine URL, wo die Inhalte lebt Sie herunterladen möchten und ein Erfolg und ein Fehlerblock. Der Kommunikationsmanager erstellt dann eine NSOperation, wo Sie die NSURLRequest erstellen und die Rückrufe behandeln.

Sobald der Commninication Manager die Operation in die Warteschlange stellt, wird die Methode start aufgerufen. In meiner Communication Manager-Implementierung verfolge ich (neben dem Setzen der Operationen in die Queue) jeden gestarteten Vorgang über eine NSMutableDictionary, so dass Sie einzelne oder alle Operationen abbrechen können (im Beispielcode wird dafür der operationKey verwendet. Hier Die JSONOperation gibt (im Erfolgsfall) einen NSString an den Communicator zurück, aber es könnte auch irgendeine Art von Daten sein, zB benutze ich dieselbe Klasse zum Herunterladen von Bildern, also würde ich das Datenobjekt selbst zurückgeben. Unten finden Sie meine JSONOperation-Klasse als Beispiel.Mir gefällt die Idee, dass ich die anderen Dateien auf Gist legen könnte.

Mein NSOperation sieht aus wie dieses

@interface JSONOperation : NSOperation <NSURLConnectionDataDelegate, OperationDelegate> 
    + (instancetype)jsonOperationForProvider:(id)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure; 
@end 

#import "JSONOperation.h" 
#import "ProviderDelegate.h" 

@interface JSONOperation() 
@property (nonatomic, assign) BOOL executing; 
@property (nonatomic, assign) BOOL finished; 
@property (nonatomic, assign) BOOL cancelled; 

@property (nonatomic, strong) NSURL *url; 

@property (nonatomic, weak) id <ProviderDelegate> delegate; 
@property (nonatomic, strong) NSURLConnection *connection; 
@property (nonatomic, strong) NSMutableData *receivedData; 

@property (nonatomic, copy) OperationFailure failure; 
@property (nonatomic, copy) OperationSuccessWithString success; 
@end 

@implementation JSONOperation 

- (void)start 
{ 
    if ([self isCancelled]) 
{ 
    [self willChangeValueForKey:@"isFinished"]; 
    _finished = YES; 
    [self didChangeValueForKey:@"isFinished"]; 

    return; 
} 

    NSURLRequest *request = [NSURLRequest requestWithURL:self.url]; 
    self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; 
    [self.connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 
    [self.connection start]; 

    [self willChangeValueForKey:@"isExecuting"]; 
    _executing = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 
} 

- (NSMutableData *)receivedData 
{ 
    if (nil == _receivedData) { 
     _receivedData = [NSMutableData data]; 
    } 
    return _receivedData; 
} 

+ (instancetype)jsonOperationForProvider:(id <ProviderDelegate>)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure 
{ 
    NSAssert(nil != provider, @"provider parameter can't be nil"); 

    JSONOperation *operation = [[[self class] alloc] init]; 
    operation.delegate = provider; 
    operation.url = provider.contentURL; 
    operation.failure = failure; 
    operation.success = success; 

    return operation; 
} 

- (BOOL)isConcurrent { 
    return YES; 
} 

- (BOOL)isExecuting { 
    return _executing; 
} 

- (BOOL)isFinished { 
    return _finished; 
} 

- (BOOL)isCancelled { 
    return _cancelled; 
} 

#pragma mark - NSURLConnectionDataDelegate 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 

    if (_success) { 
     NSString *receivedText = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; 
     _receivedData = nil; 

     self.success(self, receivedText); 
    } 

    [self willChangeValueForKey:@"isFinished"]; 
    [self willChangeValueForKey:@"isExecuting"]; 

    _executing = NO; 
    _finished = YES; 

    [self didChangeValueForKey:@"isExecuting"]; 
    [self didChangeValueForKey:@"isFinished"]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
    [self.receivedData appendData:data]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    [connection cancel]; 
    _connection = nil; 
    _receivedData = nil; 
    _url = nil; 

    if (_failure) { 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      self.failure(self, error); 
    }]; 
    } 

    [self willChangeValueForKey:@"isFinished"]; 
    [self willChangeValueForKey:@"isExecuting"]; 

    _executing = NO; 
    _finished = YES; 

    [self didChangeValueForKey:@"isExecuting"]; 
    [self didChangeValueForKey:@"isFinished"]; 
} 

#pragma mark - OperationDelegate 

- (NSString *)operationKey 
{ 
    return [self.url absoluteString]; 
} 

- (id)provider 
{ 
    return _delegate; 
} 

- (void)cancelOperation 
{ 
    _failure = nil; 
    _success = nil; 

    [self.connection cancel]; 
    _connection = nil; 

    _receivedData = nil; 
    _url = nil; 

    [self willChangeValueForKey:@"isCancelled"]; 
    [self willChangeValueForKey:@"isFinished"]; 
    [self willChangeValueForKey:@"isExecuting"]; 

    _executing = NO; 
    _finished = YES; 
    _cancelled = YES; 

    [self didChangeValueForKey:@"isCancelled"]; 
    [self didChangeValueForKey:@"isExecuting"]; 
    [self didChangeValueForKey:@"isFinished"]; 
} 

@end 

EDIT - Gist Sample files

0

Nun, in meiner Erfahrung AFNetworking macht ein ehrfürchtiges Job die downloads.I im Umgang mit einem Download-Vorgang für Dateien mit 10+ ist mit MB size.So empfehle ich dringend, es zu verwenden.

My answer on stack to show progressbar .Siehe die Antwort, wo ich sowohl die Art und Weise implementieren, mit AFNetworking und NSUrlconnection .Sie in beide Richtungen versuchen können, und den Fortschritt sehen und Sie können berechnen, wie die Bytes in jedem packet.By es Tracking heruntergeladen haben, so können Sie Analysieren Sie, wie es in der Download-Zeit variiert. Versuchen Sie es

+0

@Meryl: Probieren Sie es aus und wissen Sie, wie es gelaufen ist –

0

Versuchen Sie einfach gzip zu verwenden, um die Remote-Datei für NSURLRequest zu komprimieren. Es wird Ihre Verbindung dramatisch beschleunigen.

Um dies zu verwenden, müssen Sie es auf dem Server installiert haben, und die gute Nachricht ist, wenn Sie apache2 auf Ihrem Server verwenden, kommt es standardmäßig. Um zu testen, um sicherzustellen, dass der Server/URL hatte gzip Komprimierung aktiviert, testen Sie es mit diesem Online-Tool: http://www.feedthebot.com/tools/gzip/

Wenn die Antwort ja ist, gehen Sie den Code in Ihrem Objective-C-Code in Xcode hinzuzufügen. Nach dieser Zeile im Code:

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0]; 

nur hinzufügen:

// Create a mutable copy of the immutable request and add more headers 
NSMutableURLRequest *mutableRequest = [request mutableCopy]; 

//add gzip compression 
[mutableRequest addValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; 

// Now set our request variable with an (immutable) copy of the altered request 
request = [mutableRequest copy]; 

Dies wird deutlich Ihre Reaktionszeit beschleunigen, und Sie brauchen nicht AFNetworking für eine kleine NSURLRequest oder NSURLConnection Aufgabe zu verwenden.