2

メソッド内またはループ内でNSWindow(Mac OS X)およびUIView(iOS)の背景色を設定するのに非常に問題があります。背景色を設定する次のコードは、ループ内のコードの最後の行でのみ機能します。これは、画面がRGBの適切な混合として白に変わるため、i、j、kのすべての値が255の場合です。

`- (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 に答える