【问题标题】:Showing Accurate Progress In UIProgressView While Downloading Images in iphone在 iphone 中下载图像时在 UIProgressView 中显示准确的进度
【发布时间】:2013-03-04 06:13:03
【问题描述】:

我有四个包含图片的网址... 我正在下载这些图像并将它们放入文档文件夹..

这是我的代码..

-(void)viewDidLoad
{
NSMutableArray *myUrlsArray=[[NSMutableArray alloc]init];
[myUrlsArray addObject:@"http://blogs.sfweekly.com/thesnitch/steve_jobs3.jpg"];
[myUrlsArray addObject:@"http://www.droid-life.com/wp-content/uploads/2012/12/Steve-Jobs-Apple.jpg"];
[myUrlsArray addObject:@"http://2.bp.blogspot.com/-T6nbl0rQoME/To0X5FccuCI/AAAAAAAAEZQ/ipUU7JfEzTs/s1600/steve-jobs-in-time-magazine-front-cover.png"];
[myUrlsArray addObject:@"http://images.businessweek.com/ss/08/09/0929_most_influential/image/steve_jobs.jpg"];
[myUrlsArray addObject:@"http://cdn.ndtv.com/tech/gadget/image/steve-jobs-face.jpg"];

for (int i=0; i<myUrlsArray.count; i++)
{
    [self downloadImageFromURL:[myUrlsArray objectAtIndex:i] withName:[NSString stringWithFormat:@"MyImage%i.jpeg",i]];
}

}




#pragma mark- downloading File

-(void)downloadImageFromURL:(NSString *)myURLString withName:(NSString *)fileName
{
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:myURLString]]];

NSLog(@"%f,%f",image.size.width,image.size.height);

   // Let's save the file into Document folder.**

    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];

NSString *jpegPath = [NSString stringWithFormat:@"%@/%@",documentsPath,fileName];// this path if you want save reference path in sqlite
NSData *data2 = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];//1.0f = 100% quality
[data2 writeToFile:jpegPath atomically:YES];

}

现在...我需要准确显示上述下载进度的 UIProgressView。

我怎样才能实现这个功能...

谁能提供一些指导方针来实现这一目标..

提前致谢...

【问题讨论】:

  • 对于这个东西,首先你必须在完全下载之前知道图像的总大小,然后你必须计算每次下载的数据以及该数据占总大小的百分比,然后只有我认为这是可能的。
  • 顺便说一句,你真的不想下载NSData,创建一个UIImage,然后使用UIImageJPEGRepresentation重新提取NSData。 JPG 是有损的,因此您要么会失去质量,要么如果您使用 1.0 来提高质量,那么文件无疑会比原始文件大。如果您自己执行此操作,请确保将原始 NSData 检索到它自己的变量中,并且当您要保存它时保存它,而不是 UIImageJPEGRepresentation 的结果。
  • 这是一个 hack,所以我不会列出作为答案。但我在这种情况下所做的是构建自己的进度条并在每个图像完成时将其更新 25%。实际上,为了让它看起来不只是停留在 75% 然后消失,我让它喜欢 90% 然后在删除它之前做一些其他的快速任务。
  • 谢谢@sanjitshaw...@Rob....@badweasel..

标签: iphone ios objective-c xcode ipad


【解决方案1】:

我建议您使用一些异步下载技术(AFNetworking、SDWebImage 或使用基于委托的NSURLSession 自行滚动)而不是dataWithContentsOfURL,这样(a)您不会阻塞主队列; (b) 随着下载的进行,您可以获得进度更新。

我还建议为每次下载创建一个NSProgress。当您的委托方法获取有关已下载字节数的更新时,请更新 NSProgress 对象。

然后您可以将每个NSProgressobservedProgress 关联为UIProgressView,当您更新您的NSProgress 时,UI 可以自动更新。

或者,如果您和单个UIProgressView 来显示每次下载的所有NSProgress 的聚合进度,您可以创建一个父NSProgress,将每个下载的NSProgress 建立为父的子NSProgress,然后,随着每次下载更新其各自的NSProgress,这将自动触发父NSProgress的计算。同样,您可以将父 NSProgress 绑定到主 UIProgressView,然后您将自动更新 UI 的总进度,只需让每次下载更新其各自的 NSProgress


不过,有一个技巧,因为某些 Web 服务不会通知您预期的字节数。他们将报告NSURLResponseUnknownLength 的“预期字节数”,即-1! (它这样做的合理原因可能超出了这个问题的范围。)这显然使计算下载的百分比变得困难。

在这种情况下,有几种方法:

  1. 您可以举起双手,只使用不确定的进度指示器;

  2. 您可以尝试更改请求,以便 Web 服务将报告有意义的“预期字节数”值(例如 https://stackoverflow.com/a/22352294/1271826);或

  3. 您可以使用“估计下载大小”来估计完成百分比。例如,如果您知道您的图像平均为 100kb,则可以执行以下操作来更新与特定下载关联的 NSProgress

    if (totalBytesExpectedToWrite >= totalBytesWritten) {
        self.progress.totalUnitCount = totalBytesExpectedToWrite;
    } else {
        if (totalBytesWritten <= 0) {
            self.progress.totalUnitCount = kDefaultImageSize;
        } else {
            double written = (double)totalBytesWritten;
            double percent = tanh(written / (double)kDefaultImageSize);
            self.progress.totalUnitCount = written / percent;
        }
    }
    
    self.progress.completedUnitCount = totalBytesWritten;
    

    这是一种花招,它使用tanh 函数返回一个“完成百分比”值,该值平滑且渐近地接近 100%,使用 kDefaultImageSize 作为估计的基础。

    它并不完美,但它产生了一个相当不错的完成百分比代理。

【讨论】:

  • 再次感谢您花费宝贵的时间为我的问题提供详细而详细的答案...您的回答对我帮助很大...
  • 嘿@Rob.i 在 [__NSCFString totalBytesExpected] 处崩溃:无法识别的选择器已发送到实例。
  • 该错误告诉您 totalBytesExpected 正在被 NSString 调用(__NSCFStringNSString 类集群的成员)。以上,所有totalBytesExpected 引用都在ImageDownload 实例上调用。在某个地方,您不小心传递了 NSString 对象。 (你在某个地方做过演员吗?)在不知道你在NSString 上调用totalBytesExpected 的确切位置的情况下,很难诊断出哪里出了问题。你知道你在哪一行得到这个错误吗?
  • 在那里设置断点并查看imageDownload 参考。如果您在此处遇到特定错误,则它一定不是 ImageDownload 引用,而是出于某种原因 NSString
  • @KrutarthPatel - 如果您的服务器返回 NSURLResponseUnknownLength,即会发生这种情况。 -1,对于totalBytesExpected。我在原始答案中包含的计算完成百分比的再现在该场景中的完成百分比中引入了一些不连续性。自从我在 2013 年写下这个答案以来,我已经采用了一种新方法来估计下载的确切大小未知但您对大小有合理猜测的情况下的完成百分比,即tanh如我上面修改后的答案所示。
【解决方案2】:

您对 dataWithContentsOfURL 的调用是同步的,这意味着您不会在下载过程中获得更新。

您可以使用像 AFNetworking (https://github.com/AFNetworking/AFNetworking) 这样的库,它具有下载进度的回调。

【讨论】:

【解决方案3】:

实际上更好的解决方案是使用 SDWebImage 管理器,它会在后台为您加载图像并缓存它们。然后下次使用该图像时,它将检查缓存。谷歌一下。

这样用户在下载内容时也不必坐在那里等待..

然后看看这个对如何做一个状态有一些想法的另一个问题:

How to show an activity indicator in SDWebImage

【讨论】:

【解决方案4】:

不要使用dataWithContentsOfURL,你会阻塞主线程直到数据到达。

改为创建您自己的与 NSURLConnection 的连接并开始聆听您的委托。

  • connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response:用[response expectedContentLength]获取总数据大小。
  • connection:(NSURLConnection *)connection didReceiveData:(NSData *)data:这是您进行计算并更新您的UIProgressView 的地方。类似于loadedBytes/总数据大小。

祝你好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-29
    • 1970-01-01
    • 1970-01-01
    • 2013-02-21
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多