摘自《iOS程序员面试笔试宝典》
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];
}];
});
}
网友评论