Die einfache Lösung besteht darin, dies asynchron zu tun, um die Fortschrittsansicht zu aktualisieren, während Sie gehen:
Erstellen Sie die Fortschrittsansicht und fügen Sie sie Ihrer Ansicht hinzu
Versenden Sie Ihren Code in eine Hintergrundwarteschlange
Versenden Sie nach Abschluss jedes Downloads die Aktualisierung der Fortschrittsansicht zurück in die Hauptwarteschlange
Im Pseudocode würde das so aussehen
UIProgressView *progressView = [[UIProgressView alloc] init];
// configure the progress view and add it to your UI
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i=0; i<[array count]; i++)
{
NSError *error;
NSArray *ipaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *idocumentsDir = [ipaths objectAtIndex:0];
NSString *idataPath = [idocumentsDir stringByAppendingPathComponent:@"File"];
NSLog(@"idataPath:%@",idataPath);
//Create folder here
if (![[NSFileManager defaultManager] fileExistsAtPath:idataPath])
{
[[NSFileManager defaultManager] createDirectoryAtPath:idataPath withIntermediateDirectories:NO attributes:nil error:&error];
}
// Image Download here
NSString *fileName = [idataPath stringByAppendingFormat:@".jpg"];
NSLog(@"imagePathDOWNLOAD:%@",fileName);
_imgData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[array objectAtIndex:i]]];
[_imgData writeToFile:fileName atomically:YES];
// now dispatch any UI updates back to the main queue
dispatch_async(dispatch_get_main_queue(), ^{
[progressView setProgress: (CGFloat) (i + 1.0) / [array count] animated:YES];
tempImg.image = [UIImage imageWithData:_imgData];
});
}
});
Es gibt auch eine ganze Reihe immer eleganterer Ansätze:
Verwenden Sie die gleichzeitige Warteschlange (anstatt die oben genannten, die die Bilder seriell herunterladen), um die Bilder herunterzuladen, was erheblich schneller ist. Ich könnte die Operation Queue mit vorschlagen
maxConcurrentCount
von5
, um Parallelität zu genießen, aber stellen Sie sicher, dass Sie die iOS -Grenze in der Anzahl der gleichzeitigen Anfragen nicht überschreiten.Verwenden
NSURLConnectionDataDelegate
basierter Download statt derNSData
MethodeinitWithContentsOfURL
, die während der individuellen Downloads Zwischenfortschritte bieten können. Sehen Download-Manager oder Operation herunterladen zum Beispiel.Verwenden AFNetworking Dies liefert auch Download-Block-basierte Schnittstelle.
Oben, in Punkt 1, schlug ich vor, dass Sie in Betracht ziehen, eine gleichzeitige Warteschlange zu verwenden, also habe ich mich entschlossen, sie zu bewerten. Für mich war diese GCD-Implementierung unten 3-4-mal langsamer als die NSOperationQueue
Implementierung folgt.
Hier ist die GCD -Implementierung:
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
UIProgressView *progressView = [self addProgressView];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSInteger downloadSuccessCount = 0;
NSInteger downloadFailureCount = 0;
NSString *idataPath = [self createDownloadPath];
for (int i = 0; i < [array count]; i++)
{
// Image Download here
NSString *filename = [self pathForItem:i array:array folder:idataPath];
NSURL *url = [self urlForItem:i array:array];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = nil;
if (data)
image = [UIImage imageWithData:data];
if (image) {
downloadSuccessCount++;
[data writeToFile:filename atomically:YES];
} else {
downloadFailureCount++;
}
// now dispatch any UI updates back to the main queue
dispatch_async(dispatch_get_main_queue(), ^{
[progressView setProgress: (CGFloat) (downloadSuccessCount + downloadFailureCount) / [array count] animated:YES];
// update the image in the UI if you want
[UIView transitionWithView:self.imageView duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
tempImg.image = image;
} completion:nil];
});
}
NSLog(@"Completed in %.1f seconds", CFAbsoluteTimeGetCurrent() - start);
});
dazu NSOperationQueue
Implementierung:
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
UIProgressView *progressView = [self addProgressView];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 5;
NSString *idataPath = [self createDownloadPath];
self.downloadSuccessCount = 0;
self.downloadFailureCount = 0;
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"Completed in %.1f seconds", CFAbsoluteTimeGetCurrent() - start);
}];
for (int i = 0; i < [array count]; i++)
{
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// Image Download here
NSString *filename = [self pathForItem:i array:array folder:idataPath];
NSURL *url = [self urlForItem:i array:array];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = nil;
if (data)
image = [UIImage imageWithData:data];
if (image)
[data writeToFile:filename atomically:YES];
// now dispatch any UI updates back to the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if (image) {
self.downloadSuccessCount++;
// update the image in the UI if you want, though this slows it down
[UIView transitionWithView:self.imageView duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
tempImg.image = image;
} completion:nil];
}
else
self.downloadFailureCount++;
[progressView setProgress: (CGFloat) (self.downloadSuccessCount + self.downloadFailureCount) / [array count] animated:YES];
}];
}];
[queue addOperation:operation];
[completionOperation addDependency:operation];
}
[queue addOperation:completionOperation];
Fazit, wenn Sie verwenden NSOperationQueue
(Was nicht nur Parallelität liefert, die Sie auch in einer gleichzeitigen Warteschlange tun können, sondern auch die Anzahl der gleichzeitigen Vorgänge (die Sie auf fünf oder weniger für Netzwerkoperationen beschränken sollten) problemlos kontrollieren können), genießen Sie eine bedeutender Leistungsnutzen.
Noch besser wäre, wie ich vorgeschlagen habe, die Einstellung von Afnetworking, bei dem Sie nicht nur diesen Nutzen für die Ereigniswarteschlange genießen, auch bei beiden anderen Vorteilen.