iOS开发:多线程编程之NSThread的使用详解
iOS开发:多线程编程之NSThread的使用详解
发布时间:2016-02-29 来源:查字典编辑
摘要:1、简介:1.1iOS有三种多线程编程的技术,分别是:1.、NSThread2、CocoaNSOperation(iOS多线程编程之NSOp...

1、简介:

1.1 iOS有三种多线程编程的技术,分别是:

1.、NSThread

2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用)

3、GCD 全称:Grand Central Dispatch( iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用)

这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。

这篇我们主要介绍和使用NSThread,后面会继续2、3 的讲解和使用。

1.2 三种方式的优缺点介绍:

NSThread:

优点:NSThread 比其他两个轻量级

缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

NSThread实现的技术有下面三种:

iOS开发:多线程编程之NSThread的使用详解1一般使用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 @"/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开发:多线程编程之NSThread的使用详解2图片下载下来了。

2.3 线程同步

我们演示一个经典的卖票的例子来讲NSThread的线程同步:

.h

#import

@class ViewController;

@interface AppDelegate : UIResponder

{

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等等,可以自己看官方文档学习

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新IOS开发学习
热门IOS开发学习
编程开发子分类