NSThread不按顺序执行

时间:2015-01-17 15:57:34

标签: objective-c

我想知道为什么我的代码行似乎没有按顺序执行。以下是我的代码片段如下。

- (void)myThreadMethod:(id)options
{
    NSInteger random = [self GetRandomNumber:12];

    NSLog(@"Random Number: %ld",(long)random);
    [self ChangeSquareColor:random:[UIColor redColor]];

    [NSThread sleepForTimeInterval:5.0f];

    [self ChangeSquareColor:random:[UIColor lightGrayColor]];
    NSLog(@"Color changed");
}



-(void) buttonClicked:(UIButton*)button
{
    NSLog(@"you clicked on button %ld", (long)button.tag);
    //New thread
    [NSThread detachNewThreadSelector:@selector(myThreadMethod:) toTarget:self withObject:nil];
}

-(void)ChangeSquareColor:(NSInteger)Number
                        :(UIColor*)color
{
    UIButton *button = (UIButton *)[self.view viewWithTag:Number];
    button.backgroundColor = color;
}

-(NSInteger)GetRandomNumber:(NSInteger)Number
{
    return arc4random() % Number;
}

出于某种奇怪的原因,[self ChangeSquareColor:random:[UIColor lightGrayColor]];似乎首先调用[NSThread sleepForTimeInterval:5.0f];

2 个答案:

答案 0 :(得分:1)

UIKit不是线程安全的,不应该从后台线程调用。我想如果你改变-ChangeSquareColor::将它的工作重新发送回主线程,事情可能会好一点。

-(void)ChangeSquareColor:(NSInteger)Number
                        :(UIColor*)color
{
    dispatch_async(dispatch_get_main_queue(), ^{
        UIButton *button = (UIButton *)[self.view viewWithTag:Number];
        button.backgroundColor = color;
    });
}

此外,互联网上的迹象表明arc4random也不是线程安全的,因此您可能也应该对此保持谨慎。

答案 1 :(得分:0)

除了ipmcc关于将所有UI更新分派到主队列(这很关键)的观察之外,您可能根本不应该使用detachNewThreadSelector

要在后台执行某些操作,您可以使用Grand Central Dispatch

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // what to do in the background
});

要在后台执行某些操作,请更新用户界面:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // what to do in the background

    dispatch_async(dispatch_get_main_queue(), ^{
        // update UI here
    });
});

因此,回到你的例子:

- (void)buttonClicked:(UIButton*)button
{
    NSLog(@"you clicked on button %ld", (long)button.tag);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSInteger randomNumber = [self generateRandomNumber:12];

        NSLog(@"Random Number: %ld", (long)randomNumber);
        dispatch_async(dispatch_get_main_queue(), ^{
            [self changeSquareNumber:randomNumber color:[UIColor redColor]];
        });

        [NSThread sleepForTimeInterval:5.0f];

        dispatch_async(dispatch_get_main_queue(), ^{
            [self changeSquareNumber:randomNumber color:[UIColor lightGrayColor]];
        });
        NSLog(@"Color changed");
    });
}

- (void)changeSquareNumber:(NSInteger)squareNumber
                     color:(UIColor*)color
{
    UIButton *button = (UIButton *)[self.view viewWithTag:squareNumber];
    button.backgroundColor = color;
}

- (NSInteger)generateRandomNumber:(NSInteger)upperLimit
{
    return arc4random_uniform(upperLimit);
}

[注意,我更改了你的方法名称以符合Cocoa naming conventions(例如,方法名称以小写字母开头,以动词开头,避免"得到"以及"设置&#34 ;确保所有参数都已命名,等等。我还使用arc4random_uniform而不是arc4random%运算符来避免模偏差。]


或者,更好的是,避免阻塞线程(即使它是一个全局队列的工作线程),只是在特定延迟后触发下一步的启动:

- (void)buttonClicked:(UIButton*)button
{
    NSLog(@"you clicked on button %ld", (long)button.tag);

    NSInteger randomNumber = [self generateRandomNumber:12];

    NSLog(@"Random Number: %ld",(long)randomNumber);
    [self changeSquareNumber:randomNumber color:[UIColor redColor]];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self changeSquareNumber:randomNumber color:[UIColor lightGrayColor]];
        NSLog(@"Color changed");
    });
}