iOS 多线程NSThread-NSOperation-GCD

本文详细介绍了iOS中的三种多线程技术:NSThread、Cocoa NSOperation 和 GCD。重点讲解了 NSThread 的使用方法,包括创建线程、线程间的通讯及线程同步等内容。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

iOS有三种多线程编程的技术,分别是:
1、NSThread 
2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用)
3、GCD  全称:Grand Central Dispatch( iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用)

这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。
这篇我们主要介绍和使用NSThread,后面会继续2、3 的讲解和使用。

三种方式的有缺点介绍:
NSThread:
优点:NSThread 比其他两个轻量级
缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

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
第一个是实例方法,第二个是类方法。
1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];  
2、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键拖到viewControll er.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"  
@interface ViewController ()  
@end  
@implementation ViewController  
-(void)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];  
}  
}  


-(void)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线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?

[self performSelectorOnMainThread:@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我已经注释了。

线程的顺序执行
他们都可以通过
[ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。
比如:
#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 @synchronized directive.
    
}

}

还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习

NSThread下载图片的例子代码:http://download.csdn.net/detail/totogo2010/4591149

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值