block的简单使用

来源:互联网 发布:打印机,输入端口名称 编辑:程序博客网 时间:2024/05/18 00:00
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int (^sum)(int, int) = ^(int a, int b) {
            return a+b;
        };
        int a = 2, b = 3;
        NSLog(@"%d", sum(a, b));
    }
    return 0;
}

————————————————————————————————————————————————————————————————————————

typedef block
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        typedef int (^blockType)(int, int);
        blockType sum = ^(int a, int b) {
            return  a+b;
        };
        int a = 2, b = 3;
        NSLog(@"%d", sum(a, b));
    }
    return 0;
}

————————————————————————————————————————————————————————————————————————

block本身可以copy和release。
但是,block在创建的时候,它的内存默认是分配在栈(stack)上,而不是在堆(heap)上。
他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。
示例:

#import "RootViewController.h"

typedef void (^MyBlock)(void);

@interface RootViewController ()
{
    MyBlock _block;
}
@end

@implementation RootViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    int value = 1;
    _block = ^(void) {
        NSLog(@"value: %d", value);
    };
    // _block = [_block copy];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button setFrame:CGRectMake(20, 60, self.view.bounds.size.width-40, 35)];
    [button setTitle:@"Test" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}

- (void)buttonClick:(id)sender {
    _block(); // 这个方法一旦调用就会引起程序crash: EXC_BAD_ACCESS,解决方法是把_block = [_block copy]; 这行代码取消注释,因为copy会把block从栈上移动到堆上,这样就可以在其他地方调用了
}

- (void)dealloc {
    [_block release];
    [super dealloc];
}

@end

注:为什么对block常使用copy和release而不使用retain?
因为对于block, 有相应的Block_copy和Block_release, 而没有Block_retain
当然,对于上面block引起的crash问题,是在非ARC环境下需要注意的问题,在ARC下,ARC会自动帮忙做处理

————————————————————————————————————————————————————————————————————————

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        typedef void (^MyBlock)(void);
        int value = 1;
        MyBlock block = ^(void) {
            NSLog(@"value: %d", value);
            // value = 2;
        };
        block(); // 1
        
        value = 2;
        block(); // 1
        /**
         *  这里在调用block()之前,value的值明明已经变成了2的。但是为什么这里会打印1呢?
         *  因为在block生成的时候会把value当作常量编码到block中,如果要在block中修改外部变量的值,则会报错
         *  解决方法:引用__block标识符,告诉编译器__block所修饰的变量是引用的外部变量
         *  请看下面的示例2
         */
    }
    return 0;
}

————————————————————————————————————————————————————————————————————————

用block实现两个视图控制器之间的传值:
#import <UIKit/UIKit.h>

typedef void (^BlockType1)(NSString *str);

@interface SecodViewController : UIViewController

@property (nonatomic, copy) BlockType1 blockHandler1;
- (void)setBlockHandler1:(BlockType1)blockHandler1;

@property (nonatomic, copy) void (^blockHandler2)(NSString *str);
- (void)setBlockHandler2:(void (^)(NSString *str))blockHandler2;

@end

————————————————————————————————————————————————————————————————————————
// 对象有一个Block属性,然而这个Block属性中又引用了对象的其他成员变量,那么就会对这个变量本身产生强应用,那么变量本身和他自己的Block属性就形成了循环引用
// bad
- (void)loopTest {
    self.myBlock = ^{
        if (self.blockHandler3) {
            self.blockHandler3(self.student);
        }
    };
    
    self.myBlock();
    
    [self.navigationController popViewControllerAnimated:YES];
}

// ok
- (void)loopTest {
    __block SecodViewController *_self = self;
    self.myBlock = ^{
        if (_self.blockHandler3) {
            _self.blockHandler3(_self.student);
        }
    };
    
    self.myBlock();
    
    [self.navigationController popViewControllerAnimated:YES];
}

// ok
- (void)loopTest {
    __block typeof(self) weakSelf = self;
    self.myBlock = ^{
        if (weakSelf.blockHandler3) {
            weakSelf.blockHandler3(weakSelf.student);
        }
    };
    
    self.myBlock();
    
    [self.navigationController popViewControllerAnimated:YES];
}

0 0