kidd风的IOS日志之多线程(NSThread)的使用
2016-02-24 13:58
477 查看
1、简介:
1.1 iOS有三种多线程编程的技术,分别是:
1.、NSThread2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用)
3、GCD 全称:Grand Central Dispatch( iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用)
这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。
这篇我们主要介绍和使用NSThread,后面会继续2、3 的讲解和使用。
1.2 三种方式的优缺点介绍:
NSThread:优点:NSThread 比其他两个轻量级
缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
NSThread实现的技术有下面三种:
Cocoa threads
POSIX threads
Multiprocessing Services
一般使用cocoa thread 技术。
Cocoa operation
优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。
Cocoa operation 相 关的类是 NSOperation ,NSOperationQueue。NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用 它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。创建NSOperation子类的对象,把对 象添加到NSOperationQueue队列里执行。
GCD
Grand Central Dispatch (GCD) 是Apple开发的一个多核编程的解决方法。在iOS4.0开始之后才能使用。GCD是一个替代诸如 NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。现在的iOS系统都 升级到6了,所以不用担心该技术不能使用。
介绍完这三种多线程编程方式,我们这篇先介绍NSThread的使用。
2、NSThread的使用
2.1 NSThread 有两种直接创建方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
第一个是实例方法,第二个是类方法
[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil]; NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil]; [myThread start];
2.2参数的意义:
selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil
第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
2.3 PS:不显式创建线程的方法:
用NSObject的类方法 performSelectorInBackground:withObject: 创建一个线程:[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
2.4 下载图片的例子:
2.4.1 新建singeView app
新建项目,并在xib文件上放置一个imageView控件。按住control键拖到viewController.h文件中创建imageView IBOutlet ViewController.m中实现:// ViewController.m // NSThreadDemo // // Created by rongfzh on 12-9-23. // Copyright (c) 2012年 rongfzh. All rights reserved. // #import "ViewController.h" #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg" @interface ViewController () @end @implementation ViewController d)downloadImage:(NSString *) url{ NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]]; UIImage *image = [[UIImage alloc]initWithData:data]; if(image == nil){ }else{ [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; } } d)updateUI:(UIImage*) image{ self.imageView.image = image; } - (void)viewDidLoad { [super viewDidLoad]; // [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL]; NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL]; [thread start]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
2.4.2线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?[selfperformSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
用:performSelector:onThread:withObject:waitUntilDone:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
2.4 下载图片的例子:
2.4.1 新建singeView app
新建项目,并在xib文件上放置一个imageView控件。按住control键拖到viewController.h文件中创建imageView IBOutlet ViewController.m中实现:// ViewController.m // NSThreadDemo // // Created by rongfzh on 12-9-23. // Copyright (c) 2012年 rongfzh. All rights reserved. // #import "ViewController.h" #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg" @interface ViewController () @end @implementation ViewController d)downloadImage:(NSString *) url{ NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]]; UIImage *image = [[UIImage alloc]initWithData:data]; if(image == nil){ }else{ [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; } } d)updateUI:(UIImage*) image{ self.imageView.image = image; } - (void)viewDidLoad { [super viewDidLoad]; // [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL]; NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL]; [thread start]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
2.4.2线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?[selfperformSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
用:performSelector:onThread:withObject:waitUntilDone:
2.3 线程同步
我们演示一个经典的卖票的例子来讲NSThread的线程同步:.h
#import <UIKit/UIKit.h> @class ViewController; @interface AppDelegate : UIResponder <UIApplicationDelegate> { int tickets; int count; NSThread* ticketsThreadone; NSThread* ticketsThreadtwo; NSCondition* ticketsCondition; NSLock *theLock; } @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) ViewController *viewController; @end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { tickets = 100; count = 0; theLock = [[NSLock alloc] init]; // 锁对象 ticketsCondition = [[NSCondition alloc] init]; ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [ticketsThreadone setName:@"Thread-1"]; [ticketsThreadone start]; ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [ticketsThreadtwo setName:@"Thread-2"]; [ticketsThreadtwo start]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } - (void)run{ while (TRUE) { // 上锁 // [ticketsCondition lock]; [theLock lock]; if(tickets >= 0){ [NSThread sleepForTimeInterval:0.09]; count = 100 - tickets; NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]); tickets--; }else{ break; } [theLock unlock]; // [ticketsCondition unlock]; } }
如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了。
线程的顺序执行
他们都可以通过[ticketsConditionsignal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。
比如:
#import "AppDelegate.h" #import "ViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { tickets = 100; count = 0; theLock = [[NSLock alloc] init]; // 锁对象 ticketsCondition = [[NSCondition alloc] init]; ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [ticketsThreadone setName:@"Thread-1"]; [ticketsThreadone start]; ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [ticketsThreadtwo setName:@"Thread-2"]; [ticketsThreadtwo start]; NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil]; [ticketsThreadthree setName:@"Thread-3"]; [ticketsThreadthree start]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; return YES; } -(void)run3{ while (YES) { [ticketsCondition lock]; [NSThread sleepForTimeInterval:3]; [ticketsCondition signal]; [ticketsCondition unlock]; } } - (void)run{ while (TRUE) { // 上锁 [ticketsCondition lock]; [ticketsCondition wait]; [theLock lock]; if(tickets >= 0){ [NSThread sleepForTimeInterval:0.09]; count = 100 - tickets; NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]); tickets--; }else{ break; } [theLock unlock]; [ticketsCondition unlock]; } }
wait是等待,我加了一个 线程3 去唤醒其他两个线程锁中的wait
其他同步
我们可以使用指令@synchronized来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。- (void)doSomeThing:(id)anObj { @synchronized(anObj) { // Everything between the braces is protected by the@synchronizeddirective. } }
还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
2.4 下载图片的例子:
2.4.1 新建singeView app
新建项目,并在xib文件上放置一个imageView控件。按住control键拖到viewController.h文件中创建imageView IBOutlet ViewController.m中实现:// ViewController.m // NSThreadDemo // // Created by rongfzh on 12-9-23. // Copyright (c) 2012年 rongfzh. All rights reserved. // #import "ViewController.h" #define kURL @"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg" @interface ViewController () @end @implementation ViewController d)downloadImage:(NSString *) url{ NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]]; UIImage *image = [[UIImage alloc]initWithData:data]; if(image == nil){ }else{ [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; } } d)updateUI:(UIImage*) image{ self.imageView.image = image; } - (void)viewDidLoad { [super viewDidLoad]; // [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL]; NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL]; [thread start]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
2.4.2线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?[selfperformSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
用:performSelector:onThread:withObject:waitUntilDone:
相关文章推荐
- iOS打电话、发短信、发邮件开发
- iOS开发 之 屏幕适配
- 极光推送的使用
- 使用Autolayout xib实现动态高度的TableViewCell
- iOS Size Classes 的简单使用
- iOS AES 加密
- iOS 拦截系统自带的Pop事件
- IOS 字体表
- iOS学习----------SDWebImage框架解析(1)
- iOS-常用框架
- iOS: 属性声明strong和retain竟然不一样
- iOS新技术
- iOS开发-graphics
- ios 调用支付宝
- iOS之属性定义和内存管理
- IOS中延时执行的几种方式的比较和汇总
- ios-苹果开发者账号类型说明
- iOS问题笔记-[[NSBundle mainBundle] pathForResource: ofType:]方法获取不到资源路径
- iOS开发必看的博客汇总
- 制作iOS Ad-Hoc测试应用