【问题标题】:How to make UIProgressView to show progress of NSArray loading from file (iPhone)?如何使 UIProgressView 显示从文件(iPhone)加载 NSArray 的进度?
【发布时间】:2013-07-29 20:16:36
【问题描述】:

我希望这是可能的。

我有代码在应用启动后加载非常大的文件(字典):

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    NSString *filePath = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]
        pathForResource:@"en_US" ofType:@"txt"]
        encoding:NSUTF8StringEncoding error:nil];
    dictionary = [NSSet setWithArray:[NSArray arrayWithArray:
        [filePath componentsSeparatedByCharactersInSet:
        [NSCharacterSet whitespaceAndNewlineCharacterSet]]]];
}

我在viewDidLoad 中也有正确的代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.progressView.progress = 0.0;
    [self performSelectorOnMainThread:
        @selector(applicationDidFinishLaunching:)
        withObject:nil
        waitUntilDone:NO];
}

但我不知道如何强制UIProgressView 显示从NSArray 创建NSSet dictionary 的进度。在 iOS 模拟器中需要几秒钟,所以在设备上可能需要十几秒钟。我真的需要显示进度,我更喜欢这种方式而不是活动指示器视图。

我现在对如何获取进口商品的数量感兴趣(所有商品的数量都是已知的)。

有什么想法吗? :)

【问题讨论】:

  • 您知道哪个部分花费的时间比您想要的要长吗?阅读文件还是构建字典?
  • 我不确定您的上述代码是从文件中读取的。相反,它似乎是从文件路径组件形成的数组中形成一个集合。它绝不会读取实际的文件字节。我在这里有什么遗漏吗?
  • @MikeD 第一个。从数组构建字典几乎不引人注意。
  • @NiravBhatt 好吧,你是对的。我以为我可以在创建它的同时重复读取 NSArray 项目的数量,并用它来计算进度,但看起来不可能。你有什么想法以另一种方式实现吗?
  • 根据您的数据结构要求,您最终会调用 arraywithcontentsoffile 或 dictionarywithcontentsofffile 或它的任何变体。您的 filePath 变量将成为这些函数之一的参数。并不是说它们提供了基于时间的进度。它们只是在完整读取完成后返回的一次性函数。为了取得进步,您可能需要编写自己的 C 例程。

标签: iphone ios objective-c nsarray uiprogressview


【解决方案1】:

你需要使用 NSURLRequest/NSURLConnection 发起一个异步请求来获取字典数据。 NSURLConnection 的委托将为您提供读取的字节数和剩余字节数,您可以在其中执行异步调度到主线程以更新您的进度视图值。

【讨论】:

  • 我的字典是本地存储的,不需要下载。只想显示将其加载到内存的进度。
  • 好吧,我误解了你的问题。
【解决方案2】:

如果您有一个长文本文件要解析,框架类将需要很长时间。你无法改变这一点。而且你无法改变他们永远不会在工作期间回电告诉你他们的进度。

您唯一的机会是自己执行文本文件拆分,并在挖掘文本文件时设置进度。您可以使用正则表达式拆分文本文件。 "\w+" 收集至少有一个字符的单词。

如果您以繁重的工作方式设置进度条,则必须给它一些时间来不时刷新屏幕。请参阅下面的“未来魔法”。

也许下面可以作为一个起点——在代码下面的文本文件的内容存储在NSString“content”中。

NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
                              regularExpressionWithPattern:@"\\w+"
                              options:NSRegularExpressionCaseInsensitive
                              error:&error];

[regex enumerateMatchesInString:content
                        options:0
                          range:NSMakeRange(0, [content length])
                     usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
                         // push one match to the dictionary
                         [dictionary addObject:[content substringWithRange:match.range]];

                         // update the progress bar
                         NSDate* futureDate = [NSDate dateWithTimeInterval:0.001 sinceDate:[NSDate date]];
                         [[NSRunLoop currentRunLoop] runUntilDate:futureDate];
                         self.progressbar.progress = (float) match.range.location/content.length;
}];

请注意,代码并未针对速度进行优化。例如,您不应使用 every 标记更新进度条。根据您拥有的令牌数量 - 计算检测到的令牌并每 100 次匹配更新 pgogress 栏,或者如此...

【讨论】:

  • 我不确定您的解决方案是否有意义。您假设存在 NSString *content 已经加载了文本文件,但事实并非如此。创建它需要时间,我想用进度条显示。
  • 好的。你的文本文件有多大?我在设备上瞬间加载了 4MB。但实际解析需要 90% 的时间。
  • 您的起始情况相同:NSString *filePath = [NSString stringWithContentsOfFile。所以我认为显示进度很重要,而不是加载。尝试解决方案。如果加载也需要很长时间,请查看使用流进行阅读,如已澄清 here。祝你好运!
【解决方案3】:

使用SVProgressHUD。它有 showProgress 等代表来显示进度。

编辑:

请注意,这只是对方法的建议,并非实际实施。根据您的观察,您可能会或可能不会选择实施它。

如果是本地文件,您可以对读取整个文件所需的总时间进行一些计算猜测。然后将这个时间除以 100。

使用arrayWithContentsOfFiledictionaryWithContentsOfFile 或其他任何一个创建一个异步队列以从文件中读取。在主线程上实现一个计时器,并通过它将进度增加 1,并继续在主线程上发布进度(不要从异步线程读取进度,因为它永远不会告诉你,我们在伪造它)。

一旦arrayWithContentsOfFile 返回,在主线程上发布 100%。您可能需要稍微调整一下才能准确(例如在 Windows 中,您一直看到文件下载时间在波动),但我想变化不会太大。每种类型的目标设备都会提供硬件和内存,因此它只是文件大小的函数。

【讨论】:

  • 这没有多大帮助,因为问题的症结更多的是根据读取的字节数而不是使用哪个视图来显示进度。
猜你喜欢
  • 2013-02-21
  • 2013-03-04
  • 2020-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多