数据传递的几种方式:代理,通知,block,单例


数据回调之代理:


在需要传送数据出去的类中设置代理:设置代理协议,代理属性(为id类型,weak修饰),定义一个代理方法,这这个类中判断是否执行了这个代理方法,用(
if ([self.delegate respondsToSelector:@selector(代理方法)]))来判断,

代理为self,在接受数据的类中:遵守代理协议,设置( 需要传送数据出去的类 )的代理为self, 实现代理方法;

具体案例(线程间的通信)如下:

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

@protocol SHDownloadOperationDelegate <NSObject>

@optional

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

@end


@interface SHDownloadOperation : NSOperation

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

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

// 设置代理属性 (assign 也可以)
@property(nonatomic ,weak) id<SHDownloadOperationDelegate> delegate;

@end

操作类的.m文件
#import "SHDownloadOperation.h"

@implementation SHDownloadOperation

//
-(void)main
{
    // 为了防止子线程中的对象不能及时释放,手动添加 autoreleasepool.
    @autoreleasepool {

        // 下载图片.
        self.image = [self downloadWebImageWithUrlString:self.urlString];
        
        // 回到主线程,执行代理
        dispatch_async(dispatch_get_main_queue(), ^{
            
            // 实现代理
            if ([self.delegate respondsToSelector:@selector(downloadWebImageWithImage:)]) {
                
                [self.delegate downloadWebImageWithImage:self.image];
            }
            
            NSLog(@"执行代理的线程%@",[NSThread currentThread]);
        });
    }
}


// 下载图片
- (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;
}


@end

viewController.m文件中:
#import "ViewController.h"
#import "SHDownloadOperation.h"

@interface ViewController ()<SHDownloadOperationDelegate>

@property(nonatomic ,strong) NSOperationQueue *queue;

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController

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

- (void)viewDidLoad {
    [super viewDidLoad];
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");

    // 1. 创建自定义操作.
    SHDownloadOperation *op = [[SHDownloadOperation alloc] init];
    
    // 设置代理
    op.delegate = self;
    
    // 告诉操作下载哪一张图片.
    op.urlString = @"http://e.hiphotos.baidu.com/image/pic/item/8644ebf81a4c510fe5b8daf46459252dd52aa5db.jpg";
    
    // 2. 执行操作
    [self.queue addOperation:op];
    
}

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


@end




通知方法:1,注册通知观察者  2,发送通知  3,接收通知后执行注册的方法 4,移除通知 
 NSOperation类

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

@interface SHDownloadOperation : NSOperation

// 给操作一个显示图片的地址(imageView)
@property(nonatomic ,strong)UIImageView *imageView;

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

@end

.m文件
#import "SHDownloadOperation.h"

@implementation SHDownloadOperation

//
-(void)main
{
    // 为了防止子线程中的对象不能及时释放,手动添加 autoreleasepool.
    @autoreleasepool {

        // 下载图片.
        UIImage *image = [self downloadWebImageWithUrlString:self.urlString];
        
        // 图片下载完毕之后,将图片传递给控制器.
        // 通知:
        
        // 发送通知: postNotificationName: 发送通知
        // NotificationName: 通知名称.通知的标记,通知观察者通过通知名称来接收通知.
        // object: 通知内容.需要传递的内容.
        
        // 回到主线程发送通知
        dispatch_async(dispatch_get_main_queue(), ^{
            
            [[NSNotificationCenter defaultCenter] postNotificationName:@"downloadWebImage" object:image];
            
            NSLog(@"发出通知的线程:%@",[NSThread currentThread]);
        });
        

        


        

    }
}


// 下载图片
- (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;
}


@end

viewController.m
#import "ViewController.h"
#import "SHDownloadOperation.h"

@interface ViewController ()

@property(nonatomic ,strong) NSOperationQueue *queue;

@property (weak, nonatomic) IBOutlet UIImageView *imageView;//在storyboard中有连线

@end

@implementation ViewController

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

- (void)viewDidLoad {
    [super viewDidLoad];

    // 1. 注册通知观察者.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setUpImageWithNotify:) name:@"downloadWebImage" object:nil];
    
}

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

// 接收到通知之后,执行的方法.
// notify: 通知. 通知是同步的.(在哪条线程发送通知,也在哪条线程接收通知.)
-(void)setUpImageWithNotify:(NSNotification *)notify
{
    NSLog(@"接收通知的线程:%@",[NSThread currentThread]);
    // 1.取出通知内容
    UIImage *image = notify.object;
    
    // 2.显示图片
    self.imageView.image = image;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");

    // 1. 创建自定义操作.
    SHDownloadOperation *op = [[SHDownloadOperation alloc] init];
    
    // 告诉操作下载哪一张图片.
    op.urlString = @"http://e.hiphotos.baidu.com/image/pic/item/8644ebf81a4c510fe5b8daf46459252dd52aa5db.jpg";
    
    // 2. 执行操作
    [self.queue addOperation:op];
    
}


@end


block回传数据的方法:

     1. 定义block类型.返回值/参数类型.

     2. 定义block中执行的内容.确定block中执行的代码.

     3. 执行block.


 上面三步只要保证顺序就OK,具体哪一个步骤在哪一个对象中定义,不必关心.


自定义operation类中:
#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

.m文件中
#import "SHDownloadOperation.h"

@implementation SHDownloadOperation

//
-(void)main
{
    // 为了防止子线程中的对象不能及时释放,手动添加 autoreleasepool.
    @autoreleasepool {

        // 下载图片.
        self.image = [self downloadWebImageWithUrlString:self.urlString];
        
        // block 也是同步的.
        
        // 回到主线程执行 block.
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            // 3. 执行block
            if (self.block) {
                NSLog(@"2.执行block中的内容.");
                self.block(self.image);
            
            }
        });

    }
}


// 下载图片
- (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;
}


@end

viewController类中
#import "ViewController.h"
#import "SHDownloadOperation.h"

@interface ViewController ()

@property(nonatomic ,strong) NSOperationQueue *queue;

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController

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

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // block :块代码.指向结构体的指针.javascript/js:闭包.
    // 闭包: 可以从函数外部访问函数内部的变量.
    
    // block 很灵活. 可以将 block 当做一个参数传递. ===> 将一个方法当做参数传递了.
    
    // block 使用:
    
    // 1. 定义block类型. 返回值/参数类型.
    // 2. 定义block中执行的内容. 确定block中执行的代码.
    // 3. 执行block.
    
    // 上面三步只要保证顺序就OK,具体哪一个步骤在哪一个对象中定义,不必关心.
    
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");

    // 1. 创建自定义操作.
    SHDownloadOperation *op = [[SHDownloadOperation alloc] init];
    
    // 告诉操作下载哪一张图片.
    op.urlString = @"http://e.hiphotos.baidu.com/image/pic/item/8644ebf81a4c510fe5b8daf46459252dd52aa5db.jpg";
    
    // 操作下载完图片之后,显示图片.
    // 利用 block 将下面的代码传递给自定义的下载操作.
    
    // 2. 定义 block 中执行的内容.
    // block 参数 image :就是下载好的图片.
    op.block = ^(UIImage *image){
        
        self.imageView.image = image;
        NSLog(@"3.最后执行这块代码.");
    };

    // 2. 执行操作
    [self.queue addOperation:op];
    
}



@end

还有直接block 和间接block的回传值
这是间接的block定义的属性

在.m中 ,

在viewController中



间接block的用法:

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

// 1. 定义block类型

@class SHDownloadOperation;

typedef void(^downloadBlock)(SHDownloadOperation *op);

@interface SHDownloadOperation : NSOperation

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

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

// 定义block属性,来接收blk中传递过来的函数.
@property(nonatomic ,copy)downloadBlock block;



// 定义一个方法.用来传递 block 的方法.(接口,方便外接书写block.)
// 参数: block 类型的参数. blk:形参
-(void)downloadImageWithDownloadBlock:(downloadBlock)blk;

@end


#import "SHDownloadOperation.h"


@implementation SHDownloadOperation


//

-(void)main

{

    // 为了防止子线程中的对象不能及时释放,手动添加 autoreleasepool.

    @autoreleasepool {


        // 下载图片.

        self.image = [selfdownloadWebImageWithUrlString:self.urlString];

        

        // 回到主线程显示图片

        dispatch_async(dispatch_get_main_queue(), ^{

            

            // 3.执行 block.

            if (self.block) {

                NSLog(@"准备执行最后的block.");

                self.block(self);

            }

            

        });

    }

}


// block当做一个参数传递.

// 2. 确定 self.block中执行的内容.

-(void)downloadImageWithDownloadBlock:(downloadBlock)blk

{

    if (blk) {

        NSLog(@"2.确定 self.block中执行的内容.");

        self.block = blk;

    }

}



// 下载图片

- (UIImage *)downloadWebImageWithUrlString:(NSString *)urlString

{

    NSLog(@"downloadWebImageWithUrlString%@",[NSThreadcurrentThread]);

    

    NSURL *url = [NSURLURLWithString:urlString];

    

    NSData *data = [NSDatadataWithContentsOfURL:url];

    

    UIImage *image = [UIImageimageWithData:data];

    

    return image;

}



@end


控制器中



#import "ViewController.h"
#import "SHDownloadOperation.h"

@interface ViewController ()

@property(nonatomic ,strong) NSOperationQueue *queue;

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController

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

- (void)viewDidLoad {
    [super viewDidLoad];
    
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");

    // 1. 创建自定义操作.
    SHDownloadOperation *op = [[SHDownloadOperation alloc] init];
    
    // 告诉操作下载哪一张图片.
    op.urlString = @"http://e.hiphotos.baidu.com/image/pic/item/8644ebf81a4c510fe5b8daf46459252dd52aa5db.jpg";
    
    // 告诉操作图片下载完毕之后做什么!
    // 图片下载完毕之后,执行下面block中的内容.
    [op downloadImageWithDownloadBlock:^(SHDownloadOperation *op) {
        
        NSLog(@"3.图片下载完毕之后,最后执行这块代码!");
        // 显示图片.
        self.imageView.image = op.image;
    }];
    
    // 2. 执行操作
    [self.queue addOperation:op];
    
}



@end

单例:这段代码请定义一个Header.file文件放进去  作用:定义一个类方法来创建单例对象;
// .h
#define single_interface(class)  + (class *)shared##class;

// .m
// \ 代表下一行也属于宏
// ## 是分隔符
#define single_implementation(class) \
static class *_instance; \
 \
+ (class *)shared##class \
{ \
    if (_instance == nil) { \
        _instance = [[self alloc] init]; \
    } \
    return _instance; \
} \
 \
+ (id)allocWithZone:(NSZone *)zone \
{ \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
        _instance = [super allocWithZone:zone]; \
    }); \
    return _instance; \
}
单例类的.h文件
#import <Foundation/Foundation.h>
#import "Singleton.h"

@interface UserInfo : NSObject

single_interface(UserInfo)

@property (nonatomic,copy)NSString* title;

@end

单例类的.m文件
#import "UserInfo.h"

@implementation UserInfo
single_implementation(UserInfo)

@end

需要传值出去的控制器的.m文件
#import "TwoViewController.h"
#import "UserInfo.h"

@interface TwoViewController ()

@end

@implementation TwoViewController
//点击按钮发送信息
- (IBAction)btnClick:(UIButton *)sender {
    
//TODO:单例实现
    UserInfo *info = [UserInfo sharedUserInfo];
    info.title = self.textField.text;

    

    [self dismissViewControllerAnimated:YES completion:^{
        
         }];

接收值传递过来的控制器的.m文件中

#import "ViewController.h"
#import "TwoViewController.h"
#import "UserInfo.h"

@interface ViewController ()//<TwoViewControllerDelegate>
@property (weak, nonatomic) IBOutlet UILabel *myLabel;

@end

@implementation ViewController
//视图即将出现时 利用单例传值
-(void)viewWillAppear:(BOOL)animated{
    
    [super viewWillAppear:animated];
    
    //TODO:单例实现
    UserInfo *info = [UserInfo sharedUserInfo];
    self.myLabel.text = info.title;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    
}
- (IBAction)btnClick:(UIButton *)sender {
    
    TwoViewController *twoVC = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"TwoViewController"];

  
    [self presentViewController:twoVC animated:YES completion:nil];

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值