Block

参数传值的一般方式:

顺传:给需要传值的对象直接定义属性就能传值

逆传:用代理(delegate),Block

Block声明

返回值(^block变量名)(参数)

Block定义

  1. void(^block)() = ^(){...}; 如果有参数,必须要写参数 void(^block)(int) = ^(int a){...};
  2. void(^block)() = ^{...}; 如果没有参数,参数可以隐藏
  3. int(^block)() = ^int{...}; block返回值可以省略,不管有没有返回值,都可以省略

Block类型

int(^block)(NSString*) = ^(NSString *name){return @"Hello"};

Block调用

int(^block)(NSString*) = ^(NSString *name){return @"Hello"};

block();//调用

Block快捷方式

//敲inlineBlock后,就会自动生成代码:
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
    <#statements#>
};

Block使用场景

1.在一个方法中定义,在另一个方法中调用

2.在一个类中定义,在另一个类中调用

Block的几种用法

用法一:

//不带参数
void(^block1)() = ^(){
    NSLog(@"正在执行block1");
 };

block1();


//带参数
void(^block2)(int a,int b) = ^(int a,int b){
    NSLog(@"正在执行block2");
    int c = a + b;
    NSLog(@"a + b = %d",c);
};

block2(3,9);

用法二:

#import "ViewController.h"

typedef void(^MyBlock)();

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    MyBlock block1 = ^{
        NSLog(@"正在执行block1");
    };

    block1();
}

@end

用法三(跨越方法调用):

#import "ViewController.h"

typedef void(^MyBlock)();

@interface ViewController ()

@property(copy,nonatomic)MyBlock block2;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.block2 = ^{
        NSLog(@"正在执行block2");
    };

}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.block2();
}

@end

用法四(跨越方法调用):

#import "ViewController.h"

@interface ViewController ()

@property (strong, nonatomic) void(^block)();

@end

@implementation ViewController

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

    self.block = ^{
        NSLog(@"调用了Block");
    };
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.block();
}

@end

用法五(跨越类的调用):

BlockClass.h

#import <Foundation/Foundation.h>

@interface BlockClass : NSObject

@property (strong, nonatomic) void(^block)();

@end

ViewController.m

#import "ViewController.h"
#import "BlockClass.h"

@interface ViewController ()

@property (strong,nonatomic)BlockClass *blockClass1;
@property (strong,nonatomic)BlockClass *blockClass2;
@property (strong,nonatomic)BlockClass *blockClass3;

@end

@implementation ViewController

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

    self.blockClass1 = [[BlockClass alloc]init];
    self.blockClass2 = [[BlockClass alloc]init];
    self.blockClass3 = [[BlockClass alloc]init];

    self.blockClass1.block = ^{
        NSLog(@"圣诞快乐");
    };

    self.blockClass2.block = ^{
        NSLog(@"元旦快乐");
    };

    self.blockClass3.block = ^{
        NSLog(@"春节快乐");
    };
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    self.blockClass1.block();
    self.blockClass2.block();
    self.blockClass3.block();
}

@end

用法六(值的逆传):

BlockClass.h

#import <Foundation/Foundation.h>

@interface BlockClass : NSObject

@property (strong, nonatomic) void(^paramBlock)(int value);

@end

BlockClass.m

#import "BlockClass.h"

@implementation BlockClass

- (instancetype)init
{
    if(self = [super init])
    {
        //每隔1秒执行一次block
        [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {

            if(self.paramBlock)
            {
                int value = 123;
                self.paramBlock(value);
            }
        }];
    }
    return self;
}

@end

ViewController.m

#import "ViewController.h"
#import "BlockClass.h"

@interface ViewController ()

@property (strong,nonatomic)BlockClass *blockClass;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.blockClass = [[BlockClass alloc]init];

    self.blockClass4.paramBlock = ^(int value){
        //设置代码块功能
        NSLog(@"%d",value);
    };
}

@end

输出:(每隔1秒输出一次)

2016-12-25 23:43:32.151 BlockTest2[11235:346225] 123
2016-12-25 23:43:33.151 BlockTest2[11235:346225] 123
2016-12-25 23:43:34.213 BlockTest2[11235:346225] 123
2016-12-25 23:43:35.176 BlockTest2[11235:346225] 123

Block内存管理

block对象一般存在于堆、栈或全局区

MRC:

  • 只要block没有一用外部局部变量,block放在全局区
 void(^block)() = ^{
    NSLog(@"调用Block");
};

/*<__NSGlobalBlock__: 0x10de380d0> block放在全局区*/
NSLog(@"%@",block);
  • 当block引用了外部局部变量,则会放在栈里面
__block int a = 3;

void(^block)() = ^{
    NSLog(@"调用Block%d",a);
};

/*<__NSStackBlock__: 0x7fff52052950>放在栈*/
NSLog(@"%@",block);

定义一个全局属性方法

@property(copy,nonatomic) void(^block)();//MRC下没有strong,weak

只能使用copy,如果使用retain修饰,block还在栈中,会被销毁

ARC:

只要block引用了外部局部变量,则会放在堆里

__block int a = 3;

void(^block)() = ^{
    NSLog(@"调用Block%d",a);
};

/*<__NSMallocBlock__: 0x600000054e80>放在堆*/
NSLog(@"%@",block);

定义一个全局属性方法

@property(strong,nonatomic) void(^block)();

使用strong修饰,如果使用weak修饰,会被销毁,如果不考虑防止值的改变,也尽量不要用copy

Block的循环引用

循环引用:两个对象互相引用

@interface BlockClass : NSObject

@property (strong, nonatomic) void(^block)();

@end

@implementation BlockClass

- (instancetype)init
{
    if(self = [super init])
    {
        self.block = ^{
            NSLog(@"%@",self);//警告:Capturing 'self' strongly in this block is likely to lead to a retain cycle,这样的情况就是循环引用
        };
    }
    return self;
}

@end

解决的办法

//要定义一个弱引用指向self
__weak typeof(self) weakSelf = self;
self.block = ^{
    NSLog(@"%@",weakSelf);
};

如果block中有延时操作,延时以后还需要用到self,还需这样:

//先定义一个弱引用指向self
__weak typeof(self) weakSelf = self;

//再定义一个强引用指向weakSelf
self.block = ^{
    __strong typeof (weakSelf) strongSelf = weakSelf;

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",strongSelf);
    });
};

Block变量传递

如果是局部变量,在block中是值传递

- (void)viewDidLoad{
    int a = 3;

    void(^block)() = ^{
        NSLog(@"%d",a);//输出3
    };

    a = 5;

    block();
}

如果是静态变量,在block中是指针传递

- (void)viewDidLoad{
    static int a = 3;

    void(^block)() = ^{
        NSLog(@"%d",a);//输出5
    };

    a = 5;

    block();
}

如果是全局变量,在block中是指针传递

int a = 3;

- (void)viewDidLoad{
    void(^block)() = ^{
        NSLog(@"%d",a);//输出5
    };

    a = 5;

    block();
}

如果是__block修饰,在block中是指针传递

__block int a = 3;

- (void)viewDidLoad{
    void(^block)() = ^{
        NSLog(@"%d",a);//输出5
    };

    a = 5;

    block();
}

Block作为方法的参数

CacultorManager.h

@interface CacultorManager:NSObject

@property (nonatomic, assign) NSInteger result;

// 计算
- (void)cacultor:(NSInteger(^)(NSInteger result))cacultorBlock;

@end

CacultorManager.m

@implementation CacultorManager
- (void)cacultor:(NSInteger (^)(NSInteger))cacultorBlock
{
    if (cacultorBlock) {
      _result =  cacultorBlock(_result);
    }
}

@end

ViewController.m

...

- (void)viewDidLoad {
    [super viewDidLoad];

    [self test:3];

    // 创建计算器管理者
    CacultorManager *mgr = [[CacultorManager alloc] init];
    [mgr cacultor:^(NSInteger result){
        result += 5;
        result += 6;
        result *= 2;
        return result;
    }];

    NSLog(@"%ld",mgr.result);
}

...

Block当做返回值

- (void)viewDidLoad
{
    self.test();//只有返回值为block的方法才会这样调用

    //上面写法相当于:
    //void(^block)() = [self test];
    //block();
}

-(void(^)())test
{
    return ^{
        NSLog(@"调用了block");
    };
}

使用Block返回值实现的链式编程思想

#import <Foundation/Foundation.h>

@interface CalculatorManager : NSObject

@property (nonatomic, assign) int result;

- (CalculatorManager *(^)(int))add;

//使用方法实现
//- (CalculatorManager *)add:(int)value; 

@end

CalculatorManager.m

#import "CalculatorManager.h"

@implementation CalculatorManager
- (CalculatorManager *(^)(int))add
{
    return ^(int value){
        _result += value;

        return self;
    };
}

//使用方法实现
//- (CalculatorManager *)add:(int)value
//{
    //_result += value;
    //
    //return self;
//}

ViewController.m

...

- (void)viewDidLoad {
    [super viewDidLoad];

    CalculatorManager *mgr = [[CalculatorManager alloc] init];

    mgr.add(5).add(5).add(5).add(5);

    //使用方法实现,虽然实现,但写法不太美观
    //[[[[[mgr add:5] add:5] add:5] add:6] add:7];

    NSLog(@"%d",mgr.result);
...

results matching ""

    No results matching ""