Multiprocessing Services is a legacy C-based interface used by applications transitioning from older versions of Mac OS. This technology is available in OS X only and should be avoided for any new development. Instead, you should use the NSThread class
>一般使用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
第一个是实例方法,第二个是类方法
-
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"
-
#define kURL @"http://avatar.youkuaiyun.com/2/C/D/1_totogo2010.jpg"
-
@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.youkuaiyun.com/detail/totogo2010/4591149
著作权声明:本文由http://blog.youkuaiyun.com/totogo2010/原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!
|