我想知道为什么我的代码行似乎没有按顺序执行。以下是我的代码片段如下。
- (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];
答案 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");
});
}