Cocoa touch Cocoa Touch ProgressView在循环中未显示更新

Cocoa touch Cocoa Touch ProgressView在循环中未显示更新,cocoa-touch,uikit,uiprogressview,Cocoa Touch,Uikit,Uiprogressview,如果我有一个无害的循环,当我按下如下按钮时,它会被触发: - (IBAction)start:(id)sender{ calculatingProgressBar.progress = 0.0; int j = 1000; for (int i=0; i<j; i++) { calculatingProgressBar.progress = (i/j); } } -(iAction)开始:(id)发送方{ 计算进度条。进度=0.0; i

如果我有一个无害的循环,当我按下如下按钮时,它会被触发:

- (IBAction)start:(id)sender{
    calculatingProgressBar.progress = 0.0;  
    int j = 1000;
    for (int i=0; i<j; i++) {
        calculatingProgressBar.progress = (i/j);
    }
}
-(iAction)开始:(id)发送方{
计算进度条。进度=0.0;
int j=1000;

对于(int i=0;i假设calculatingProgressBar是一个IBOutlet,那么您可能只需要以符合KVO的方式设置新值,即使用setter:self.calculatingProgressBar.progress=(i/j)假设calculatingProgressBar是一个IBOutlet,那么您可能只需要以兼容KVO的方式设置新值,即使用setter:self.calculatingProgressBar.progress=(i/j);

问题是UI仅在运行(事件)循环时定期更新。a
for()
loop(我假设在主线程上运行)将阻止运行循环,直到完成。这不仅意味着进度条不会被更新(或者,更确切地说,将在最后跳到100%),而且可能会在一段时间内冻结UI。(我假设,由于您正在显示进度条,这可能需要一段时间。)

对于任何冗长的操作,您要做的是在单独的队列/线程上完成工作,并在主线程上定期调用更新UI。例如,您可以尝试以下操作(警告:在浏览器中键入)):

dispatch\u queue\u t queue=dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u BACKGROUND,0);
调度异步(队列^{
int j=1000;

for(int i=0;i问题在于,UI只在运行(事件)循环开始时定期更新。我假设在主线程上运行的
for()
循环将阻止运行循环,直到完成。这不仅意味着进度条不会被更新(或者,更确切地说,将在结束时跳到100%),但您可能会在一段时间内冻结UI。(我假设,由于您正在显示进度条,这可能需要一段时间。)

对于任何冗长的操作,您要做的是在单独的队列/线程上完成工作,并在主线程上定期调用更新UI。例如,您可以尝试以下操作(警告:在浏览器中键入)):

dispatch\u queue\u t queue=dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u BACKGROUND,0);
调度异步(队列^{
int j=1000;

对于(int i=0;i,当您在主线程上运行代码时,UI无法自我更新。这是有意的,可以极大地提高性能。这意味着在
start
返回之前,UI不会发生任何更新。您多次更新
progress
,然后返回,因此只绘制一次

你需要使用计时器或GCD队列来实现你所说的。这在很大程度上取决于你的其余代码是什么样子的,但这里有一种方法,如果你想让它运行超过60秒,例如:

- (IBAction)start:(id)sender{
  calculatingProgressBar.progress = 0.0;  
  int j = 60;

  dispatch_time_t now = dispatch_time(DISPATCH_TIME_NOW, 0);
  for (int i=0; i<j; i++) {
    dispatch_after(dispatch_time(now, i * NSEC_PER_SEC),
                   dispatch_get_current_queue(),
                   ^{
                     calculatingProgressBar.progress = (i/j);
                    });
    }
}
-(iAction)开始:(id)发送方{
计算进度条。进度=0.0;
int j=60;
dispatch\u time\u t now=dispatch\u time(dispatch\u time\u now,0);

对于(int i=0;i,当您在主线程上运行代码时,UI无法自我更新。这是有意的,可以极大地提高性能。这意味着在
start
返回之前,UI不会发生任何更新。您多次更新
progress
,然后返回,因此只绘制一次

你需要使用计时器或GCD队列来实现你所说的。这在很大程度上取决于你的其余代码是什么样子的,但这里有一种方法,如果你想让它运行超过60秒,例如:

- (IBAction)start:(id)sender{
  calculatingProgressBar.progress = 0.0;  
  int j = 60;

  dispatch_time_t now = dispatch_time(DISPATCH_TIME_NOW, 0);
  for (int i=0; i<j; i++) {
    dispatch_after(dispatch_time(now, i * NSEC_PER_SEC),
                   dispatch_get_current_queue(),
                   ^{
                     calculatingProgressBar.progress = (i/j);
                    });
    }
}
-(iAction)开始:(id)发送方{
计算进度条。进度=0.0;
int j=60;
dispatch\u time\u t now=dispatch\u time(dispatch\u time\u now,0);
对于(int i=0;i我认为更优雅(且通用)的解决方案是:
在您的委托中,有以下内容:

maxNumber = 1000; // define this somewhere, just for convenience
...
[self performSelectorInBackground:@selector(doLoop:) withObject:[NSNumber numberWithInt:maxNumber]];
有这样一种方法:

- (void)doLoop:(NSNumber *)myMaxNumber { // this runs on the background
  calculatingProgressBar.progress = 0.0;  
  NSNumber *j = myMaxNumber;
  for (int i=0; i<j; i++) {
    [self performSelectorOnMainThread:@selector(updateProgress:) withObject:[NSNumber numberWithInt:i] waitUntilDone:NO];
  }
  // here you could call a method in the main thread, just to signify that your loop is done.
  // [self performSelectorOnMainThread:@selector(loopDone:) withObject:nil waitUntilDone:NO];
}
我认为一个更优雅(更通用)的解决方案是: 在您的委托中,有以下内容:

maxNumber = 1000; // define this somewhere, just for convenience
...
[self performSelectorInBackground:@selector(doLoop:) withObject:[NSNumber numberWithInt:maxNumber]];
有这样一种方法:

- (void)doLoop:(NSNumber *)myMaxNumber { // this runs on the background
  calculatingProgressBar.progress = 0.0;  
  NSNumber *j = myMaxNumber;
  for (int i=0; i<j; i++) {
    [self performSelectorOnMainThread:@selector(updateProgress:) withObject:[NSNumber numberWithInt:i] waitUntilDone:NO];
  }
  // here you could call a method in the main thread, just to signify that your loop is done.
  // [self performSelectorOnMainThread:@selector(loopDone:) withObject:nil waitUntilDone:NO];
}

我已经阅读了这个主题,并假设您必须绊倒并欺骗UI进行更新。当我尝试这段代码时,我得到一条消息:使用不兼容类型int的表达式初始化“const struct timespec”。消息已删除-双重Postededid。不需要欺骗。您只需要按照系统预期的异步行为。我已经阅读了ar在本主题中,假设您必须绊倒并欺骗UI进行更新。当我尝试此代码时,我收到一条消息:使用不兼容类型int的表达式初始化“const struct timespec”。消息已删除-双重Postededid。不需要任何欺骗。您只需按照系统预期的异步行为。正如您可能已经看到的红色我在Xcode的后维珍模式下。我渴望做更多的事情,但仍有很多摸索。我怀疑我已经得到了三个很好的建议,但还没有足够的理智来让它们工作。在self前面加前缀。在行中给出一个消息属性“Calculating ProgressBar”,在类型为“VC name…Xcode I”的对象上找不到这不是你的问题。Cocoa是。:@EdwardHasted——你收到错误消息是因为你没有声明calculatingProgressBar是一个属性。我对“self”的理解是错误的不过,你不需要这样。这里的其他答案指出了你的代码的一个主要问题。但到目前为止,每个人都忽略了一个问题,那就是你不能将i和j声明为int,因为这样做会导致i/j始终等于0(因为你在做整数数学,所以任何分数都等于0)。如果你将它们声明为float(或double)由于康拉德·舒尔茨坎(Conrad ShultzCan)提到的跑步循环问题,你们应该会立即看到横杆跳到100%。我感谢你们三位的时间、耐心和建议。我现在已经开始了解这个问题,并开始理解解决方案。这需要时间才能真正理解。没有计算器