2

我在方法或循环中为 NSWindow (Mac OS X) 和 UIView (iOS) 设置背景颜色时遇到了很大的麻烦。以下设置背景颜色的代码仅适用于循环中的最后一行代码,即当 i、j、k 的所有值均为 255 时,屏幕变为白色作为适当的 RGB 混合。

`- (void) ChangeColorLoop
{
for (int i=0; i<=255; i++)
    for (int j=0; j<=255; j++)
        for (int k=0; k<=255; k++)
        {
            [NSThread sleepForTimeInterval: 0.1];
            //NSLog(@"%d, %d, %d", i, j, k);
            float red = (float) i/255;
            float green = (float) j/255;
            float blue = (float) k/255;    
            float alpha = 1.0f;
            UIColor *mixedColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
            //BackgroundView.backgroundColor = mixedColor;
            [BackgroundView setBackgroundColor:mixedColor];
        }
}`

提前致谢,

杰瑞

4

2 回答 2

0

从您的评论中听起来,这是在主线程上运行的。我看到它有几个问题。您没有看到颜色变化的根本原因是您的循环阻塞了主线程,并且视图(通常)仅在运行循环周期结束时重绘。直到整个循环完成后才会发生这种情况。有多种方法可以解决这个问题。最简单的可能是每次通过 for 循环手动运行运行循环。您还可以将此工作移至后台线程并将setBackgroundColor:调用分派到主队列。另一种方法是使用计时器(NSTimer 或计时器调度源)定期更新颜色。

在任何情况下,您都不应该在 for 循环中间休眠主线程。几乎没有充分的理由让主线程休眠,这样做会阻止您的 UI 更新或处理用户输入事件。

编辑:这是一些示例代码,显示了我提到的计时器方法:

@interface AppDelegate ()

@property (nonatomic, strong) NSTimer *colorChangeTimer;
@property (nonatomic) float red;
@property (nonatomic) float green;
@property (nonatomic) float blue;

@end

@implementation AppDelegate

- (id)init
{
    self = [super init];
    if (self) {
        self.red = 0.5;
        self.blue = 0.5;
        self.green = 0.5;
    }
    return self;
}

- (void)updateColors:(NSTimer *)timer
{
    NSColor *newColor = [NSColor colorWithDeviceRed:self.red green:self.green blue:self.blue alpha:1.0];
    [self.window setBackgroundColor:newColor];
    if (self.red >= 1.0) {
        [self.colorChangeTimer invalidate];
        self.colorChangeTimer = nil;
    }
    if (self.green > 1.0) {
        self.green = 0.0;
        self.red += 0.01;
    }
    if (self.blue >= 1.0) {
        self.blue = 0.0;
        self.green += 0.01;
    } else {
        self.blue += 0.01;
    }
}

- (IBAction)changeColors:(id)sender 
{
    if (self.colorChangeTimer != nil) return;
    self.colorChangeTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(updateColors:) userInfo:nil repeats:YES];
}

@synthesize window = _window;
@synthesize colorChangeTimer = _colorChangeTimer;
@synthesize red = _red;
@synthesize green = _green;
@synthesize blue = _blue;

@end
于 2012-05-09T15:55:23.383 回答
0

只有当您的代码返回到事件循环时,该setBackgroundColor:消息才会被执行,直到最后才会执行。这就是为什么只有最后一种颜色“需要”。

因此,您需要在后台线程上运行循环。但是setBackgroundColor:调用需要在主线程上(因为这是所有 UI 代码所在的位置)。

如果您使用 GCD,您的逻辑需要类似于:

-(void)changeColorLoop {
  dispatch_async(backgroundqueue, ^{
    for (;;) {
      // Do stuff
      dispatch_sync(main_queue, ^{
        [BackgroundView setBackgroundColor:mixedColor];
      });
    }
  });
}
于 2012-05-09T15:57:16.497 回答