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最推荐使用的。

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

NSThread:

优点: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
1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];

 

1
2
3
4
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: 创建一个线程:

1
[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 
-(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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#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]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#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,加锁并解锁相关代码。

1
2
3
4
5
6
7
- (void)doSomeThing:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized directive.
    }
}

还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习
转载:http://blog.csdn.net/totogo2010/article/details/8010231

posted on   梁飞宇  阅读(189)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示