自定义NSOperation进行多线程之间的通信(通知、代理、block)

本文详细介绍了在iOS应用开发中如何通过通知、代理和block实现线程间的高效通信,包括创建自定义操作类、设置回调方法以及在主控制器中管理线程任务,以确保资源有效利用和代码逻辑清晰。

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

每一个应用程序至少有一个主线程。线程的工作就是去执行一系列的指令。在Cocoa Touch中,主线程包含应用程序的主运行回路。几乎所有你写的代码都会在主线程中执行,除非你特别创建了一个单独的线程,并在这个新线程中执行代码。

线程有两个显著的特征:

1.每个线程都有访问你的应用程序资源的同等权限;它包括访问除了局部变量之外的所有的对象。所以,任何对象都可能被任意线程修改,使用并且改变。

2.没有办法可以去预测一个线程会运行多久或者哪个线程会首先完成!


关于自定义NSOperation 类,可以遵循以下步骤:

1.继承NSOperation

2.重写“main”方法

3.“main”方法中创建一个“autoreleasepool”

4.将你的代码放在“autoreleasepool”

创建你自己的自动释放池的原因是,你不能访问主线程的自动释放池,所以你应该自己创建一个。


一、使用通知进行线程之间的通信


1)自定义 NSOperation 文件中;



@interface ZTDownloadOperation : NSOperation

@property(nonatomic ,strong)UIImage *image;

@property(nonatomic ,copy)NSString *urlString;

@end

@implementation ZTDownloadOperation

-(void)main
{
    // 为了防止子线程中的对象不能及时释放,手动添加 autoreleasepool.
    @autoreleasepool {
        
        // 下载图片.
        self.image = [self downloadWebImageWithUrlString:self.urlString];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            // 需求: 利用通知将 下载操作 传递出去.
            [[NSNotificationCenter defaultCenter] postNotificationName:@"downloadOperation" object:self];
        });
        
    }
}


// 下载图片
- (UIImage *)downloadWebImageWithUrlString:(NSString *)urlString
{
    NSLog(@"downloadWebImageWithUrlString%@",[NSThread currentThread]);
    
    NSURL *url = [NSURL URLWithString:urlString];
    
    NSData *data = [NSData dataWithContentsOfURL:url];
    
    UIImage *image = [UIImage imageWithData:data];
    
    return image;
}

2)主控制器中;


@interface ViewController ()

@property(nonatomic ,strong) NSOperationQueue *queue;

//storyboard中拖拽一个imageView
@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController

-(NSOperationQueue *)queue
{
    if (!_queue) {
        _queue = [[NSOperationQueue alloc] init];
    }
    return _queue;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //添加通知的观察者
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setUpImageWithNotify:) name:@"downloadOperation" object:nil];
    
}


-(void)setUpImageWithNotify:(NSNotification *)notify
{
    SHDownloadOperation *op = notify.object;
    
    self.imageView.image = op.image;
}

-(void)dealloc
{
    // 移除通知观察者.
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");
    
    // 1. 创建自定义操作.
    SHDownloadOperation *op = [[SHDownloadOperation alloc] init];
    
    // 告诉操作下载哪一张图片.
    op.urlString = @"http://...";
    
    // 2. 执行操作
    [self.queue addOperation:op];
    
}

3 通知使用注意:

    通知效率是最低的.通知是最灵活最简单.两个对象没有联系,利用通知来传值.

    使用通知的时候,一定要注意移除通知观察者.

    通知是同步的,注意线程.



二、使用代理进行线程之间的通信

主体框架与上述代码基本相似,需要修改的是:

 1 在自定义NSOperation .h文件中,添加代理协议及代理属性
@protocol SHDownloadOperationDelegate <NSObject>

@optional

-(void)downloadWebImageWithImage:(UIImage *)downloadImage;

@end

 2 在自定义NSOperation .m文件中,修改回到主线程函数中的代码

// 实现代理
if ([self.delegate respondsToSelector:@selector(downloadWebImageWithImage:)]) {
    
    [self.delegate downloadWebImageWithImage:self.image];
}

 3 在主控制器中设置代理,并实现代理方法

// 实现代理方法
-(void)downloadWebImageWithImage:(UIImage *)downloadImage
{
    NSLog(@"代理方法:%@",[NSThread currentThread]);
    
    self.imageView.image = downloadImage;
}


三、使用block进行线程之间的通信

 1 在自定义NSOperation .h文件中

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

// 1.定义block 类型
typedef void(^downloadBlock)(UIImage *image);

@interface SHDownloadOperation : NSOperation

// 下载好的图片.
@property(nonatomic ,strong)UIImage *image;

// 图片的下载地址
@property(nonatomic ,copy)NSString *urlString;

// 定义block属性
@property(nonatomic ,copy) downloadBlock block;

@end

 2 在自定义NSOperation .m文件中, 修改回到主线程函数中的代码

// 3. 执行block
if (self.block) {
    NSLog(@"2.执行block中的内容.");
    self.block(self.image);
}

 3 在主控制器中

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{   
    // 1. 创建自定义操作.
    SHDownloadOperation *op = [[SHDownloadOperation alloc] init];
    
    // 设置图片url地址
    op.urlString = @"http://...";
 
    // 2. 定义 block 中执行的内容.
    // block 参数 image :就是下载好的图片.
    op.block = ^(UIImage *image){
        
        self.imageView.image = image;
        NSLog(@"3.最后执行这块代码.");
    };
    
    // 2. 执行操作
    [self.queue addOperation:op];
    
}


总的来说,通知的效率最低,一般当两个对象没有联系时,利用通知进行传值;block使用起来最为方便,所以block在工作中使用最为广泛.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值