[转]iOS多线程编程之NSThread的使用
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实现的技术有下面三种:
|
Technology |
Description |
|---|---|
|
Cocoa threads |
Cocoa implements threads using the |
|
POSIX threads |
POSIX threads provide a C-based interface for creating threads. If you are not writing a Cocoa application, this is the best choice for creating threads. The POSIX interface is relatively simple to use and offers ample flexibility for configuring your threads. For more information, see “Using POSIX Threads” |
|
Multiprocessing Services |
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 |
一般使用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];
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.csdn.net/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
//
// 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 -(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线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?
[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
#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];
- }
- }
- (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];
- }
- }
#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
著作权声明:本文由http://blog.csdn.net/totogo2010/原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!
[转]iOS多线程编程之NSThread的使用的更多相关文章
- iOS多线程编程之NSThread的使用
目录(?)[-] 简介 iOS有三种多线程编程的技术分别是 三种方式的有缺点介绍 NSThread的使用 NSThread 有两种直接创建方式 参数的意义 PS不显式创建线程的方法 下载图片的例子 ...
- iOS多线程编程之NSThread的使用(转)
本文由http://blog.csdn.net/totogo2010/原创 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThread 2.Cocoa NSOperation ...
- iOS多线程编程之NSThread的使用(转载)
1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1.NSThread 2.Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的 ...
- [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- [转] iOS多线程编程之NSOperation和NSOperationQueue的使用
<iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...
- iOS 多线程编程之Grand Central Dispatch(GCD)
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...
- iOS多线程编程之NSOperation和NSOperationQueue的使用
前一篇 <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是 ...
- IOS 多线程编程之Grand Central Dispatch(GCD)介绍和使用 多线程基础和练习
介绍:前面内容源自网络 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式 ...
- iOS多线程编程之GCD的使用
什么是线程呢? 1个CPU执行的CPU命令列为一条无分叉的路径即为线程. 这种无分叉路径不止1条,存在多条时即为多线程. 什么是GCD? Grand Central Dispatch (GCD)是异步 ...
随机推荐
- php curl模拟post请求提交数据样例总结
在php中要模拟post请求数据提交我们会使用到curl函数,以下我来给大家举几个curl模拟post请求提交数据样例有须要的朋友可參考參考.注意:curl函数在php中默认是不被支持的,假设须要使用 ...
- 关于matlab鼠标响应
今天看了一下Matlab中响应鼠标的事件,整理如下, (1)函数WindowButtonMotionFcn,当鼠标在窗口上运动的时候就会相应此函数,于是在此函数中可以设置运动时想要的代码,如:改变鼠标 ...
- 浅谈Spring(一)
一.Spring引言 Spring是一款轻量级框架,代码入侵量很小,并且还是众多优秀的设计模式的组合(工厂.代理.模板.策略). 特点: 1.方便解耦,简化开发 通过Spring提供的IoC容器,我们 ...
- C++类的常成员函数
让一个成员函数带上常量性是什么意思呢?通常的答案是,一个常成员函数不会更改其class对象.这是一种平凡的表述,而编译器实现的手法也相当平凡. 任何非静态成员函数其实都被编译器隐式插入了一个指针类型的 ...
- Apache 编译扩展的方法
下载源码包 进入源码包的modules目录 选择你要编译的.c文件 eg: /home/work/local/apache/bin/apxs -c -i -a mod_proxy_http.c 选项说 ...
- 修改IIS虚拟目录名称
@echo off echo ------------------------------------------------------------------------------ echo - ...
- MySQL 分区表各个分区的行数
分区的信息是记录在information_schema.partitions 这个表里的.它不能直接定位行所在的分区,但它可查到每个分区中有多少行. 例子: select partition_name ...
- Windows phone 8.1 MessageBox 变了哦!
using Windows.UI.Popups; public async void MessageBoxShow(string content, string caption) { MessageD ...
- 深入剖析PE文件
不赖猴的笔记,转载请注明出处. 深入剖析PE文件 PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解. 一. ...
- HDU 3374 String Problem (KMP+最小最大表示)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3374 [题目大意] 给出一个字符串,求出最小和最大表示是从哪一位开始的,并且输出数量. [题解] ...