第一部分:連結
- iOS 多線程:『pthread、NSThread』詳盡總結
- .iOS 多線程:『GCD』詳盡總結
- OS 多線程:『NSOperation、NSOperationQueue』詳盡總結
- iOS 多線程:『RunLoop』詳盡總結
- 關于performSelector:afterDelay:的一個坑及思考
第二部分:例子
1.NSThread
-(void)downloadImageOnSub{
[NSThread detachNewThreadSelector:@selector(downLoadImage) toTarget:self withObject:nil];
}
-(void)downLoadImage{
NSLog(@"Current Thread:%@", [NSThread currentThread]);
NSURL *imgUrl = [NSURL URLWithString:@"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=414435988,70382748&fm=15&gp=0.jpg"];
NSData *imgData = [NSData dataWithContentsOfURL:imgUrl];
UIImage *img = [UIImage imageWithData:imgData];
[self performSelectorOnMainThread:@selector(updateImageView:) withObject:img waitUntilDone:YES];
}
-(void)updateImageView:(UIImage*)img{
NSLog(@"Current Thread:%@", [NSThread currentThread]);
mImageView.image = img;
}
更新UI時切換到主線程:performSelectorOnMainThread,這部分跟Android很類似。這裡稍微提醒下,IOS預設隻支援HTTPS,不支援HTTP,原因時安全問題。
2. NSNotification
-(void)registerNotify {
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(doNotify) name:@"mynotify" object:nil];
[[NSNotificationCenter defaultCenter]addObserverForName:@"myMainNotify" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
NSLog(@"Recieve main Notify:%@",[NSThread currentThread]);
}];
}
- (IBAction)sendNotify:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[NSNotificationCenter defaultCenter]postNotificationName:@"mynotify" object:nil];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[NSNotificationCenter defaultCenter]postNotificationName:@"myMainNotify" object:nil];
});
}
-(void)doNotify{
NSLog(@"Recieve notify:%@", [NSThread currentThread]);
}
這裡有兩種register的方法,addObserverForName提供了切換到主線程分方法。
-
NSRunLoop
1)運作示意圖
2)NSTimerIOS并發線程學習(XCode9.1 Object-C)
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
}
-(void)run{
NSLog(@"run test1");
}
運作效果:使用者不操作時會不斷列印"run test1",如使用者點選滑鼠則拖動滾動條之類,則不會運作run,NSDefaultRunLoopMode相當于Android的idle狀态。
3). 圖檔延遲顯示
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"Touch Begin");
[self performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"loop.jpg"] afterDelay:4.0 inModes:@[NSDefaultRunLoopMode]];
}
-(void)setImage:(UIImage *)image{
NSLog(@"setImage:%@", image);
self.mImageView.image = image;
}
運作效果:滑鼠松開後4秒後顯示指定圖檔,注意這裡的代碼與參考連接配接中不一樣,參考連接配接中用self.imageView performSelector,是運作不了,具體原因沒分析過,估計是self.imageView導緻線程切換到非主線程了。
4)常駐記憶體線程
@property (strong, nonatomic) NSThread *mThread;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.mThread = [[NSThread alloc]initWithTarget:self selector:@selector(run2) object:nil];
[self.mThread start];
}
-(void)run2{
//add task here
NSLog(@"run test2");
//start the loop
[[NSRunLoop currentRunLoop]addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop]run];
NSLog(@"test2 end");
}
運作發現,隻會列印run test2,不會列印end,這就好比Android中的Loop循環。如果不好了解,再加入如下代碼運作多次。
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"Touch Begin");
[self performSelector:@selector(run) onThread:self.mThread withObject:nil waitUntilDone:NO];
}
多次點選滑鼠,就會發現隻會列印run test1,不會列印run test2,因為Loop第一次就已經起來,後面隻管執行task即可。