学习iosblock
1.Block的声明: 返回值类型(^block名称)(参数)
例如:声明一个无参数无返回值的block:
// 声明:返回值类型(^block变量名)(参数) void(^block)();
2.Block的定义:
- 
- 方式一:
 
void(^block1)() = ^(){
NSLog(@"调用block1");
};
- 
- 方式二:block如果没有参数,可以省略()
 
void(^block2)() = ^{
        
    };
- 
- 方式三:block定义中,返回值可以省略
 
int(^block3)() = ^int{//int可以省略
        
        return 2;
    };
3.Block的作用:保存一段代码,在调用Block的时候执行.
4.Block的调用:block名(参数);
// 调用Block,就会去查看Block所保存代码
    block1();
5.Xcode快捷生成block的方式:inlineBlock
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
        <#statements#>
    };
6.Block起别名:
// BlockType就是类型别名 typedef void(^BlockType)();
7.Block定义属性:
// Block怎么声明.就怎么定义属性 // block:属性名 @property (nonatomic ,strong) void(^block)();
二.Block开发使用场景---保存代码(不常用)
例:新建一个CellItem作为TableViewController的模型
#import <Foundation/Foundation.h> @interface CellItem : NSObject @property (nonatomic ,strong) void(^block)(); @property (nonatomic ,strong) NSString *title; @end @implementation CellItem @end
#import <UIKit/UIKit.h>
@interface TableViewController : UITableViewController
@end
#import "CellItem.h"
// tableView:打电话,发短信,发邮件
@interface TableViewController ()
@property (nonatomic ,strong) NSArray *cellArr;
@end
@implementation TableViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 打电话
    CellItem *item = [[CellItem alloc] init];
    item.title = @"打电话";
    item.block = ^{
        NSLog(@"打电话");
    };
    
    // 发短信
    CellItem *item1 = [[CellItem alloc] init];
    item1.title = @"发短信";
    item1.block = ^{
        NSLog(@"发短信");
    };
    
    // 发邮件
    CellItem *item2 = [[CellItem alloc] init];
    item2.title = @"发邮件";
    item2.block = ^{
        NSLog(@"发邮件");
    };
    
    self.cellArr = @[item,item1,item2];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    return self.cellArr.count;
    
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *ID = @"cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    
    cell.textLabel.text = [self.cellArr[indexPath.row] title];
    
    
    return cell;
}
// 点击cell就会调用
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    CellItem *item = self.cellArr[indexPath.row];
    
    if (item.block) {
        item.block();
    }
}
@end
三.Block开发使用场景---传值(常用)
数据传值分顺传和逆传.
假设:A控制器push(modal)到B控制器,若A要给B传值,则此种传值方式为顺传;B给A传值则为逆传.
开发中,大家比较熟悉的方法:顺传--->定义属性;逆传--->使用代理.
下文介绍,使用Block替换代理实现数据逆传.
- 首先[使用代理]的情况: ModalViewController给ViewController传值
#import <UIKit/UIKit.h>
@class ModalViewController;
@protocol ModalViewControllerDelegate <NSObject>
@optional
// 代理方法:想要告诉代理做什么事情
- (void)modalViewController:(ModalViewController *)modalVc receiveStr:(NSString *)str;
@end
@interface ModalViewController : UIViewController
@property (nonatomic, weak) id<ModalViewControllerDelegate> delegate;
@end
@implementation ModalViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 传值给ViewController
    if ([self.delegate respondsToSelector:@selector(modalViewController:receiveStr:)]) {
        
        [self.delegate modalViewController:self receiveStr:@"123"];
    }
}
@end
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ModalViewController.h"
@interface ViewController ()<ModalViewControllerDelegate>
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    ModalViewController *modalVc = [[ModalViewController alloc] init];
    
    modalVc.delegate = self;
    
    modalVc.view.backgroundColor = [UIColor yellowColor];
    
    [self presentViewController:modalVc animated:YES completion:nil];
    
}
#pragma mark -ModalViewControllerDelegate
- (void)modalViewController:(ModalViewController *)modalVc receiveStr:(NSString *)str
{
    NSLog(@"接收到值%@",str);
}
@end
- [使用Block]的情况:将会在点击modal控制器的时候打印:接收到123.
#import <UIKit/UIKit.h>
@interface ModalViewController : UIViewController
@property (nonatomic ,strong) void(^valueBlock)(NSString *value);
@end
@implementation ModalViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    
    if (self.valueBlock) {
        self.valueBlock(@"123");
    }
}
@end
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ModalViewController.h"
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    ModalViewController *modalVc = [[ModalViewController alloc] init];
  
    modalVc.valueBlock = ^(NSString *value){
    
        NSLog(@"接收到%@",value);
        
    };
    
    modalVc.view.backgroundColor = [UIColor yellowColor];
    
    [self presentViewController:modalVc animated:YES completion:nil];
    
}
@end
四.Block内存管理
首先需要搞清楚一个问题:block是对象吗?
苹果官方文档告诉你,没错,她就是对象.这样我们可以通过%@来打印她.
1.在非ARC中:
- block若访问了[外部局部变量],block存放[栈]里面
@interface ViewController ()
@property (nonatomic, copy) void(^block)();
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    
    int a = 0;
    
    void(^block)() = ^{
        
        NSLog(@"调用block");
        
        NSLog(@"%d",a);
    };
    
    self.block = block;
    
    NSLog(@"block - %@",block);//block - <__NSStackBlock__: 0x7fff5b9fa9c8> [栈]
    
    NSLog(@"self.block - %@",self.block);// self.block - <__NSMallocBlock__: 0x7fd2e0418310> [堆]
}
- block[没有访问外部局部变量],则存放到[全局区]
@interface ViewController ()
@property (nonatomic, copy) void(^block)();
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    
    int a = 0;
    
    void(^block)() = ^{
        
        NSLog(@"调用block");
        
        //NSLog(@"%d",a);
    };
    
    self.block = block;
    
    NSLog(@"block - %@",block); //block - <__NSGlobalBlock__: 0x105d01080>
    
    NSLog(@"self.block - %@",self.block);//self.block - <__NSGlobalBlock__: 0x105d01080>
}
@interface ViewController ()
@property (nonatomic, copy) void(^block)();
@end
static NSString *str = @"iOS";
- (void)viewDidLoad {
    [super viewDidLoad];
    
    int a = 0;
    
    void(^block)() = ^{
        
        NSLog(@"调用block");
        
        //NSLog(@"%d",a);
        
        NSLog(@"%@",str);
    };
    
    self.block = block;
    
    NSLog(@"block - %@",block); //block - <__NSGlobalBlock__: 0x100b8e080>
    
    NSLog(@"self.block - %@",self.block); //block - <__NSGlobalBlock__: 0x100b8e080>
}
 注意: 在非ARC中.不能使用retain引用block,因为block访问外部局部变量时,retain不会把block放在堆里面(仍然存放在栈里),生命周期没有得到延长.
     在非ARC中使用copy,才会把block放在堆里面.
@interface ViewController ()
//@property (nonatomic, copy) void(^block)();
@property (nonatomic, retain) void(^block)();
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    int a = 0;   
    void(^block)() = ^{
        
        NSLog(@"调用block");
        
        NSLog(@"%d",a);
        
        //NSLog(@"%@",str);
    };
    
    self.block = block;
    
    NSLog(@"block - %@",block);// block - <__NSStackBlock__: 0x7fff55d5b9c8>
    
    NSLog(@"self.block - %@",self.block);//self.block - <__NSStackBlock__: 0x7fff55d5b9c8>
}
2. ARC环境:
- block访问[外部局部变量],block存放[堆]里面
可以使用strong去引用
@interface ViewController ()
@property (nonatomic, strong) void(^block)();
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    
    int a = 0;
    
    // ARC中,默认局部对象变量都是强指针
    
    void(^block)() = ^{
        
        NSLog(@"调用block");
        
        NSLog(@"%d",a);
    };
    
    self.block = block;
    
    NSLog(@"%@",block);//<__NSMallocBlock__: 0x7f9218c3b810>
    NSLog(@"%@",self.block);// <__NSMallocBlock__: 0x7f86fa6133d0>
}
归纳:只要block访问的变量是整个app运行过程中都存在的变量,那么block肯定存放在全局区.
五.Block循环引用
   Block循环引用,跟block调用没有关系
   block只要访问外部强指针对象变量,就会对这个变量进行强引用.
 1 #import <UIKit/UIKit.h>
 2 
 3 @interface ModalViewController : UIViewController
 4 
 5 @end
 6 
 7 @interface ModalViewController ()
 8 
 9 @property (nonatomic ,strong) void(^block)();
10 
11 @end
12 
13 @implementation ModalViewController
14 
15 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
16 {
17     [self dismissViewControllerAnimated:YES completion:nil];
18 }
19 
20 - (void)dealloc
21 {
22     NSLog(@"%@对象销毁",self);
23 }
24 
25 - (void)viewDidLoad {
26     [super viewDidLoad];
27     
28     // Block循环引用,跟block调用没有关系
29     // block只要访问外部强指针对象变量,就会对这个变量进行强引用.
30     
31     self.block = ^{
32         NSLog(@"延迟打印%@",self);      
33     };
34     
35     self.block();
36 }
37 @end
 1 #import <UIKit/UIKit.h>
 2 
 3 @interface ViewController : UIViewController
 4 
 5 @end
 6 
 7 #import "ModalViewController.h"
 8 
 9 @implementation ViewController
10 
11 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
12 {
13     ModalViewController *modalVc = [[ModalViewController alloc] init];
14     
15     modalVc.view.backgroundColor = [UIColor redColor];
16     
17    //self.presentedViewController强引用modalVc
18     [self presentViewController:modalVc animated:YES completion:nil];
19 }
20 @end
点击viewController的屏幕modal出来ModalViewController,然而再点击ModalViewController的屏幕会发现ModalViewController并没有被销毁.
原因:发生了循环引用.block只要访问外部强指针对象变量(self==ModalViewController),就会对这个变量进行强引用.而ModalViewController对block也进行着强引用.
解决办法:使用__weak修饰符.让block对modalVc进行弱引用.
 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     
 4     // Block循环引用,跟block调用没有关系
 5     // block只要访问外部强指针对象变量,就会对这个变量进行强引用.
 6     __weak typeof(self) weakSelf = self;
 7     
 8     self.block = ^{
 9         
10     NSLog(@"延迟打印%@",weakSelf);
11 
12     };
13     
14     //self.block();
15 }
16 @end
需求:在block中处理延时操作,需要访问modalVc即使马上dismiss控制器,保证仍能访问.即实现dismiss延迟销毁控制器.
 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3     
 4     // Block循环引用,跟block调用没有关系
 5     // block只要访问外部强指针对象变量,就会对这个变量进行强引用.
 6     __weak typeof(self) weakSelf = self;
 7     
 8     self.block = ^{
 9         
10         __strong typeof(weakSelf) strongSelf = weakSelf;
11 
12         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
13         // 引用的为内部强指针
14         NSLog(@"延迟打印%@",strongSelf);
15         
16         });
17     
18     };
19     
20     self.block();
21 }
2016-04-10 20:08:19.918 06-Block循环引用[7884:212378] 延迟打印<ModalViewController: 0x7f9a31e1ebe0>
2016-04-10 20:08:19.936 06-Block循环引用[7884:212378] <ModalViewController: 0x7f9a31e1ebe0>对象销毁
 
self.block();执行完毕并且dismiss,仍然有系统的强指针指向after那个block块,保证modalVc不被立即销毁.当延时block快执行完毕,strongSelf指针不再强引用modalVc,此时modalVc控制器对象才能销毁.
六.Block变量传递
- 如果[局部变量]被static,__block修饰,那么都是指针传递
- [全局变量],也是指针传递
- 默认的局部变量,在block中是值传递
 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3 
 4     // 如果局部变量被static,__block修饰,那么都是指针传递
 5     // 全局变量.也是指针传递
 6     __block int a = 5;
 7     
 8     // 默认局部变量 在block中 是 值传递
 9     void(^block)() = ^{
10       
11         NSLog(@"%d",a);//10
12     };
13     
14     a = 10;
15     
16     block();
17 }
 1 int a = 5;
 2 
 3 @implementation ViewController
 4 
 5 - (void)viewDidLoad {
 6     [super viewDidLoad];
 7 
 8     // 如果局部变量被static,__block修饰,那么都是指针传递
 9     // 全局变量.也是指针传递
10     //__block int a = 5;
11     
12     // 默认局部变量 在block中 是 值传递
13     void(^block)() = ^{
14       
15         NSLog(@"%d",a);//10
16     };
17     
18     a = 10;
19     
20     block();
21 }
22 
23 @end
 1 - (void)viewDidLoad {
 2     [super viewDidLoad];
 3 
 4     // 如果局部变量被static,__block修饰,那么都是指针传递
 5     // 全局变量.也是指针传递
 6     int a = 5;
 7     
 8     // 默认局部变量 在block中 是 值传递
 9     void(^block)() = ^{
10       
11         NSLog(@"%d",a);//5
12     };
13     
14     a = 10;
15     
16     block();
17 }
七.Block开发使用场景---方法参数使用
其实Block作为方法的参数使用,我们开发中经常使用.
例如:
    [UIView animateWithDuration:1 animations:^{
        
    }];
  只要方法参数带有^,就表示把block当做参数去使用.
  以上的例子中,把block当做参数去使用,block并不是我们调用,而是系统调用.
- 那么,为什么需要把block当做参数去使用呢?
   使用场景: 当自己封装一个类的时候,有些事情比如怎么做由外部决定,但是什么时候去做,由内部决定,这时候采取使用block.
 
需求:封装一个计算器,提供一个计算方法,怎么计算由外界去决定,什么时候计算,自己管理.
 1 #import <Foundation/Foundation.h>
 2 
 3 @interface CalculateManager : NSObject
 4 
 5 /** 保存计算的结果 */
 6 @property (nonatomic, assign) int result;
 7 
 8 /**
 9  *  计算
10  *
11  *  @param block 交待怎么计算的block
12  */
13 - (void)calculate:(int(^)(int))block;
14 
15 @end
16 
17 @implementation CalculateManager
18 
19 - (void)calculate:(int (^)(int))block
20 {
21      self.result =  block(self.result);
22 }
23 @end
 1 #import <UIKit/UIKit.h>
 2 
 3 @interface ViewController : UIViewController
 4 
 5 @end
 6 
 7 
 8 #import "CalculateManager.h"
 9 
10 @interface ViewController ()
11 
12 @end
13 
14 @implementation ViewController
15 
16 - (void)viewDidLoad {
17     [super viewDidLoad];
18     
19     // 创建计算器管理者
20     CalculateManager *mgr = [[CalculateManager alloc] init];
21    
22     [mgr calculate:^(int result){
23         // 计算
24         result += 5;
25         result *= 2;
26         
27         return result;
28     }];
29     
30     NSLog(@"%d",mgr.result);
31     
32 }
33 @end
八.Block开发使用场景---方法返回值
其实Block作为方法的返回值使用,我们开发中可能很多人都用过.
例如:目前最流行的AutoLayout框架Masonry
    [targetView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.view).offset(-20);
        make.leading.equalTo(self.view).offset(20);
        make.size.mas_equalTo(CGSizeMake(100, 100));
    }];
一般调用方法后面接(),就是把block当做返回值去用.
 编程思想:
 链式编程:把方法的调用 通过.语法 链接起来,可读性非常好.
#import <Foundation/Foundation.h>
@interface CalculateManager : NSObject
/** 保存计算的结果 */
@property (nonatomic, assign) int result;
/**
 *  加一个值返回一个计算管理对象
 */
- (CalculateManager *)add:(int)value;
/**
 *  返回一个 带有整形参数返回值是计算管理对象的 block
 */
- (CalculateManager *(^)(int))add;
@end
@implementation CalculateManager
- (CalculateManager *)add:(int)value
{
    self.result += value;
    
    return self;
}
- (CalculateManager *(^)(int))add
{
    return ^(int value){
        
        self.result += value;
        return self;
    };
}
@end
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "CalculateManager.h"
/*
需求:封装计算器类,提供加号方法,用于处理加法计算.
 */
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    CalculateManager *mgr = [[CalculateManager alloc] init];
    
    [[[[[mgr add:5] add:5] add:5] add:5] add:5];
    
    mgr.add(5).add(5).add(5).add(5).add(5);
    
    NSLog(@"%d",mgr.result);//50
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号