حدد عرض التقدم في الحلقة ، أو تحديث عرض التقدم

StackOverflow https://stackoverflow.com/questions/19834016

  •  25-07-2022
  •  | 
  •  

سؤال

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];

    tempImg.image = [UIImage imageWithData:_imgData];   
}

كيفية تعيين عرض التقدم لهذه الحلقة ، أريد تعيين عرض تقدم لتنزيل البيانات. وكذلك تسمية التقدم (أي ٪) أريد نسبة العشرية.

هل كانت مفيدة؟

المحلول

الحل البسيط هو القيام بذلك بشكل غير متزامن ، وتحديث عرض التقدم كما تذهب:

  1. قم بإنشاء عرض التقدم وأضفه إلى عرضك

  2. أرسل رمزك إلى قائمة انتظار الخلفية

  3. مع انتهاء كل تنزيل ، أرسل تحديث عرض التقدم إلى قائمة الانتظار الرئيسية

في رمز الزائفة ، سيبدو ذلك

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];
        });
    }
});

هناك سلسلة كاملة من الأساليب الأنيقة بشكل متزايد ، أيضًا:

  1. استخدم قائمة الانتظار المتزامنة (بدلاً من ما سبق ، والذي يقوم بتنزيل الصور بشكل متسلسل) لتنزيل الصور ، والتي ستكون أسرع بكثير. قد أقترح قائمة انتظار التشغيل مع maxConcurrentCount من 5, ، للاستمتاع بالتزامن ، ولكن تأكد من عدم تجاوز حد iOS في عدد الطلبات المتزامنة.

  2. يستخدم NSURLConnectionDataDelegate تنزيل على أساس بدلا من NSData طريقة initWithContentsOfURL, والتي يمكن أن تقدم تقدمًا مؤقتًا أثناء التنزيلات الفردية. نرى مدير التحميل أو تنزيل العملية للحصول على أمثلة.

  3. يستخدم Afnetworking والتي توفر أيضا الواجهة القائمة على التحقيق في كتلة التقدم.


أعلاه ، في النقطة 1 ، اقترحت أن تفكر في استخدام قائمة انتظار متزامنة ، لذلك قررت أن أقوم بتقييمها. بالنسبة لي ، كان تطبيق GCD أدناه أبطأ 3-4 مرات من NSOperationQueue التنفيذ الذي يتبع ذلك.

هنا تنفيذ GCD:

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);
});

الى هذا NSOperationQueue تطبيق:

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];

خلاصة القول ، إذا كنت تستخدم NSOperationQueue (وهو ما لا يوفر التزامن فحسب ، والذي يمكنك أيضًا القيام به في قائمة انتظار متزامنة GCD ، ولكنه يتيح لك أيضًا التحكم بسهولة في عدد العمليات المتزامنة (والتي يجب أن تحدها إلى خمسة أو أقل لعمليات الشبكة)) ، ستستمتع فائدة أداء كبيرة.

والأفضل من ذلك ، كما اقترحت ، هو توظيف AFNetworking ، والتي تستمتع بها ليس فقط هذه المنفعة التزامن في قائمة الانتظار ، وكلا الفوائد الأخرى أيضًا.

نصائح أخرى

[progressView setProgress: (CGFloat) (i + 1.0) / [array count] animated:YES];
self.progressLabel.text = [NSString stringWithFormat:@"%.0f",self.progressView.progress*100];
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top