ios 多线程 NSThread Cocoa NSOperation GCD

本文介绍了Objective-C中实现多线程的多种方法,包括NSThread的使用、NSOperationQueue的特点及应用,以及Grand Central Dispatch (GCD) 的优势与实践案例。通过具体的代码示例展示了如何有效利用多线程提高程序性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NSThread:

一个NSThread对象控制一个线程
当需要把Objective-C中的方法,放到独立的线程中运行时,可以使用此类
多线程特别适用于,当需要执行一个长时间任务,却不想阻塞执行其余操作时

两种创建方式

detachNewThreadSelector:toTarget:withObject:

initWithTarget:selector:object:

隐式创建线程的方式

-performSelectorInBackground:withObject:

//方式1
    NSThread * t1 = [[NSThread alloc]initWithTarget:self selector:@selector(doWork) object:nil];
    [t1 start];
    //方式2
    [NSThread detachNewThreadSelector:@selector(doWork) toTarget:self withObject:nil];
    //方式3
    [self performSelectorInBackground:@selector(doWork) withObject:nil];

NSThread对象的局限性:
需要考虑线程同步的问题
当多个线程在同一时刻访问同一资源(比如打印机)的时候,便会造成混乱。
同步这里应理解为协同、合作
-(void) fetchMoneyAndDecreBalance:(id) who
{
    @synchronized(self){
        NSLog(@"%@取钱:8000,取钱之前余额为:%d",who,self->balance);
        [NSThread sleepForTimeInterval:0.1];
        self->balance -= 8000;
        [NSThread sleepForTimeInterval:0.1];
        NSLog(@"%@取钱后余额为:%d",who,self->balance);
    }
}

//
//  ViewController.m
//  NSThreadByStoryboard
//
//  Created by 何瑾 on 15/1/13.
//  Copyright (c) 2015年 e世雕龙. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIProgressView *progressView;// 进度条

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

#pragma mark 使用线程的三种方式
- (IBAction)useThread:(id)sender {
    // 方式一
    NSThread *t1 = [[NSThread alloc]initWithTarget:self selector:@selector(doWork) object:nil];
    // 必须手动启动线程
    [t1 start];
    
    // 方式二(不用手动启动线程,自动启动线程)
    [NSThread detachNewThreadSelector:@selector(doWork) toTarget:self withObject:nil];
    
    //方式三(不用手动启动线程,自动启动线程)
    [self performSelectorInBackground:@selector(doWork) withObject:nil];
}
#pragma mark 线程完成的工作
- (void)doWork {
    for (int i=1; i<=1000; i++) {
        NSLog(@"%@%d",[NSThread currentThread],i);
    }
}
#pragma mark 使用线程更新进度条
- (IBAction)updateProgressView:(id)sender {
    // 创建线程
    NSThread *t = [[NSThread alloc]initWithTarget:self selector:@selector(updateProgressViewUI) object:nil];
    // 启动线程
    [t start];
}
#pragma mark 更新进度条
- (void)updateProgressViewUI {
    self.progressView.progress = 0;
    for (int i=0; i<100; i++) {
        // 让当前线程的runloop停止0.02秒
        [NSThread sleepForTimeInterval:0.02f];
        // 在主线程中更新UI
        [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:YES];
    }
}
#pragma mark 更新UI
- (void)updateUI {
    self.progressView.progress += 1.0/100;
}
#pragma mark 多线程取钱问题(线程同步问题)
- (IBAction)useThreadFetchMoney:(id)sender {
    // 创建线程1
    NSThread *husband = [[NSThread alloc]initWithTarget:self selector:@selector(fetchMoney:) object:@"大丈夫"];
    // 启动线程1
    [husband start];
    
    // 创建线程2
    NSThread *wife = [[NSThread alloc]initWithTarget:self selector:@selector(fetchMoney:) object:@"大老婆"];
    // 启动线程2
    [wife start];
}
#pragma mark 取钱方法
- (void)fetchMoney:(NSString *)who {
    static int money = 10000;// 余额
    // 线程同步前,结果很混乱
    /*NSLog(@"%@开始取钱,取前余额:%d",who,money);
    money -= 2000;
    NSLog(@"%@取后余额:%d",who,money);*/
    // 线程同步后,结果正常
    @synchronized(self) {
        NSLog(@"%@开始取钱,取前余额:%d",who,money);
        money -= 2000;
        NSLog(@"%@取后余额:%d",who,money);
    }
}
@end








NSOperationQueue

    // 创建操作对象
    MyFetchMoneyOperation *husband = [MyFetchMoneyOperation new];
    husband.who = @"大丈夫";
    MyFetchMoneyOperation *wife = [MyFetchMoneyOperation new];
    wife.who = @"大老婆";
    // 多线程顺序执行操作队列,此句代码必须在往队列中加入操作之前
    NSOperationQueue *queue = [NSOperationQueue new];
    queue.maxConcurrentOperationCount = 1;
    // 把所有操作放入操作队列中
    [queue addOperation:husband];
    [queue addOperation:wife];
    
    //NSOperation对象是一个single-shot(一次性)对象,当它执行完一遍后,便不能再次使用,下面代码出错!
    /*NSOperationQueue *queue2 = [[NSOperationQueue alloc]init];
    [queue2 addOperation:husband];
    [queue2 addOperation:wife];*/


BankAccount * account = [BankAccount new];
    account.balance = 10000;

	Fetcher * husband = [[Fetcher alloc]init];
	Fetcher * wife = [[Fetcher alloc]init];
    _husband.name = @"丈夫";
    wife.name = @"妻子";
    _husband.account = account;
    wife.account = account;
    NSOperationQueue * bankQueue = [NSOperationQueue new];
    [bankQueue addOperation:_husband];
    [bankQueue addOperation:wife];
    //多线程顺序执行操作队列
  bankQueue.maxConcurrentOperationCount = 1;

NSOperation对象是一个single-shot(一次性)对象,当它执行完一遍后,便不能再次使用
操作队列优先级

 MyOperation *o1= [[[MyOperationalloc]init]autorelease];

   o1.name = @"o1";

   

   MyOperation *o2= [[[MyOperationalloc]init]autorelease];

   o2.name = @"o2";

   

   MyOperation *o3= [[[MyOperationalloc]init]autorelease];

   o3.name = @"o3";

   [o3 setQueuePriority:NSOperationQueuePriorityVeryHigh];

   

   NSOperationQueue*queue = [[NSOperationQueuealloc]init];

   [queue setMaxConcurrentOperationCount:1];

   [queue addOperation:o1];

   [queue addOperation:o2];

   [queue addOperation:o3];

GrandCentralDispatch GCD


Grand Central Dispatch (GCD)Apple开发的一个多核编程的较新的解决方法。
它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。
它是一个在线程池模式的基础上执行的并行任务。在MacOS X 10.6雪豹中首次推出,也可在IOS4及以上版本使用。
将耗时的计算放到主线程之外,达到平滑UI的效果
处理并发多线程
处理线程间依赖关系
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        for(int i = 0;i < 100;i++){
            [NSThread sleepForTimeInterval:0.02];
            //在主线程中更新内容
            dispatch_async(dispatch_get_main_queue(), ^{
                self.progressView.progress += 0.01;
            });
        }
    });


 

 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSString * str1 = [self doWork1];
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text = [self.textView.text stringByAppendingFormat:@"%@\r\n",str1];
        });
    });
    dispatch_async(queue, ^{
        NSString * str2 = [self doWork2];
        dispatch_async(dispatch_get_main_queue(), ^{
            self.textView.text = [self.textView.text stringByAppendingFormat:@"%@\r\n",str2];
        });
    });
……
    });

NSMutableString * totalString = [[NSMutableString alloc]initWithCapacity:10];
    dispatch_group_t group =dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_async(group, queue, ^{
        NSString * str1 = [self doWork1];
        [totalString appendString:str1];   });
    dispatch_group_async(group, queue, ^{
        NSString * str2 = [self doWork2];
        [totalString appendString:str2];    });
    dispatch_group_async(group, queue, ^{
        NSString * str3 = [self doWork3];
        [totalString appendString:str3];    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        self.textView.text = totalString;
    });

GCD与多核计算的关系

GCDapple为多核的并行运算提出的解决方案
GCD的使用能充分发挥硬件的性能
NSOperationQueueGCD
OperationQueueGCD有相同的功效
但它是用GCD构建,是GCD的高级抽象
GCD只支持FIFO队列,而加入NSOperationQueue队列的操作可以被从新排序(设置优先级)
NSOperationQueue支持操作间设置依赖关系而GCD不可以
异步加载图片
加载网络资源的时候经常用到多线程
把耗时的任务放到主线程之外,平滑UI,增强用户体验
NSThread异步加载图片

-(void)downloadImage:(NSIndexPath *)indexPath
{
    @autoreleasepool {
	……
        UIImage * image = [UIImage imageWithData:data];
        if(image != nil){
            [self.imagesCache replaceObjectAtIndex:indexPath.row withObject:image];
        }
        //更新UI的代码须到主线程中执行
        [self performSelectorOnMainThread:@selector(updateTableViewCellImage:) withObject:indexPath waitUntilDone:NO];
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值