UIKit类要在哪一个应用线程上使用
UIKit的界面类只能在主线程上使用,对界面进行更新,多线程环境中要对界面进行更新必须要切换到主线程上。
例如下面的问题代码:
@interface TTWaitController () @property (strong, nonatomic) UILabel *alert; @end @implementation TTWaitController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. CGRect frame = CGRectMake(20,200,200,20); self.alert = [[UILabel alloc]initWithFrame:frame]; self.alert.text = @"Please wait 10 seconds..."; self.alert.textColor = [UIColor whiteColor]; [self.view addSubview:self.alert]; NSOperationQueue *waitQueue = [[NSOperationQueue alloc]init]; [waitQueue addOperationWithBlock:^{ [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]]; self.alert.text = @"Thanks!"; }]; } @end @implementation TTAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.rootViewController = [[TTWaitController alloc]init]; [self.window makeKeyAndVisible]; return YES; } @end
这段代码是想提醒用户等待10s,10s后在标签上显示“Thanks”,但多线程代码部分NSOperationQueue的addOperationWithBlock函数不能保证block里面的语句是在主线程中运行的,UILabel显示文字属于UI更新,必须要在主线程进行,否则会有未知的操作,无法在界面上及时正常显示。
解决方法是将UI更新的代码写在主线程上。代码同步到主线程上主要有3种方法:NSThread、NSOperationQueue和GCD,3个层次的多线程都可以获取主线程并同步。
iOS中有哪几种从其他线程回到主线程的方法
iOS中只有主线程才能立即刷新UI。如果是通过侦听异步消息,触发回调函数,或者调用异步方法,请求刷新UI,那么都会产生线程阻塞和延迟的问题。如果要在其他线程中执行刷新UI的操作,那么就必须切换回主线程。主要由以下3种方式。
1.NSThreadPerformAdditions协议
这个协议提供了两个切换到主线程的API。
-(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array; -(void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
2.GCD
使用GCD的dispatch_get_main_queue()方法可以获取主队列,主队列中的任务必定是在主线程中执行的。
dispatch_async(dispatch_get_main_queue(), ^{ });
3.NSOperationQueue
和GCD一样,使用NSOperationQueue提供+mainQueue方法可以获取主队列,再将刷新UI的任务添加到主队列中。
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ }];
示例代码如下:
- (void)goToMainThread{ /*开启子线程下载图片*/ dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSData *imageData = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:@"http://jxh1992.com/pe0060886.jpg"]]; _image = [UIImage imageWithData:imageData]; /*切换到主线程显示*/ //1.NSThread // [self performSelectorOnMainThread:@selector(changeBe) withObject:nil waitUntilDone:NO]; //2.GCD // dispatch_async(dispatch_get_main_queue(), ^{ // [self changeBe]; // }); //3.NSOperationQueue [[NSOperationQueue mainQueue]addOperationWithBlock:^{ [self changeBe]; }]; }); }