Block(一)

基本原理

  • Block 也是OC的对象
  • Objective-C 是对C 语言的扩展,block的实现是基于指针和函数指针
  • 代码输入 inlineBlock 就会出再一段block代码,类似于init

block 内存分类

 内存分布
 
 堆区 栈区 全局区  代码区
 
 1.没捕获有外部变量   GlobalBlock 全局区  
    
 2.有捕获外部变量:
  
    A. 全部变量 或 全局静态变量 或 局部静态变量
    copy 或 strong 或weak 修饰  GlobalBlock

    B. 普通外部变量:
    copy 或 strong 修饰  mallocBlock
    weak           修饰  stackBlock  意为着出了方法或函数范围就失效了 
 
 分析:
 有普通外部变量时:创建Block时本身在栈区,但赋值时用Stong或Copy时会将block 从栈区移到堆区
 

block 的创建


void(^blockName)(NSString *) = ^(NSString *param) {
        NSLog(@"%@",param);
    };
blockName(@"hello");

#声明 返回值类型(^block名称)(参数列表)
void(^Block1)( ); 

#实现 block = ^(参数列表){ 代码块 }
Block1 = ^( ){
   NSLog(@"我的代码块");
}
#调用 block名称(参数列表)
Block( );


block 作属性参数使用

@property (nonatomic, copy) void(^blockName)(NSString *);

//一般用 tyedef
tyedef NSString(^Block2 )(NSString *, NSString *)

block 做方法参数使用

void(^Block2)(int,int) = ^(int a, int b){
      NSLog(@"我的第二个代码块");
}
[self method:block2];
-(void)method:(void(^)(int,int))block{
      block(10,20)
}    

Tips

- (void)viewDidLoad
{
    [super viewDidLoad];

    int a = 3;
    void (^ block)() = ^{ 
        NSLog(@"%d",a);   
    };
    a = 5;

    block();
}
————————————————————————————————————
情况2:
- (void)viewDidLoad
{
    [super viewDidLoad];

   static int a = 3;                    ***区别点:静态变量***
    void (^ block)() = ^{ 
        NSLog(@"%d",a);   
    };
    a = 5;

    block();
}
————————————————————————————————————
情况3:
- (void)viewDidLoad
{
    [super viewDidLoad];

   __block int a = 3;                    ***区别点:被__block修饰***
    void (^ block)() = ^{ 
        NSLog(@"%d",a);   
    };
    a = 5;

    block();
}
————————————————————————————————————
情况4:
 __block int a = 3;                    ***区别点:全局变量***

- (void)viewDidLoad
{
    [super viewDidLoad];

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

    block();
}

//局部变量,block传值(值拷贝);
//静态变量,全局变量,__block修饰,blokc传址(址拷贝);

循环引用

一般我们为避免block中相互持有而造成谁都无法释放,引起循环引用,从而造成内存泄露,所以需要typeof(self)[1]

__weak typeof(self)  weakSelf = self; //推荐写法
__weak __typeof(self)  weakSelf = self;
__weak XXViewController *weakSelf = self;
__weak id weakSelf = self;
__weak __typeof(&*self)weakSelf = self;

//当然也可以写成宏定义
#define WF(weakSelf)  __weak typeof(self) weakSelf = self; 
NSString str = @"测试1";
typeof(a) b = @"测试2";
typeof(a) 表示得到对象a的类型

但有些情况可以直接使用self

  • 调用系统方法:
//block虽然对self 强引用,但self不持有这个静态方法
[UIView animateWithDuration:0.5 animations:^{
        NSLog(@"%@",self);
          }];
  • block 不是self 的属性
//self不持有这个block,所以也不存在循环引用
void(^block)(void) = ^(){
      NSLog("%@",self);
}

Block 与 Delegate

两者非常类似,用法也相近,比如我们自定义一个UITableViewCell,cell上显示文字信息和一个请情Button,点击button后push到下一个页面。但cell 没有能力实现 push 功能,因为只能是

[self.navigationController pushViewController:VC];

  • 如果用代理的话,Cell 需要制定协议,设置代理,委托代理实现 push 功能
//设置协议
@protocol CustomCellDelegate 
- (void)pushToNewPage;
@end

@interface CustomTableViewCell : UITableViewCell
@property(nonatomic, assign) id delegate;
@property (nonatomic, strong) UILabel *text1Label;
@property(nonatomic,strong) UIButton *detailBtn;
@end
//在cell的.m文件中给Button添加方法
[self.detailBtn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];

//对应的btnClicked方法
- (void)btnClicked:(UIButton *)btn{
  //最好做这种安全判断
    if (self.delegate && [self.delegaterespondsToSelector:@selector(pushToNewPage)]) {

        [self.delegate pushToNewPage];
     }
}
//在ViewController的.m文件中遵守协议
@interface ViewController ()
@end

//设置代理
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
       ····
    //很重要
    cell.delegate = self;
    return cell;

}
//实现协议方法
- (void)pushToNewPage{

   DetailViewController*detailVC = [[DetailViewController alloc] init];
   [self.navigationController pushViewController:detailVC animated:YES];
}
  • 如果用Block的,不需要制定协议
@interface CustomTableViewCell : UITableViewCell
//直接定义一个block
@property (nonatomic, copy) void (^ButtonBlock)();
@property (nonatomic, strong) UILabel *text1Label;
@property(nonatomic,strong) UIButton *detailBtn;
@end
//在cell的.m文件中给Button添加方法
[self.detailBtn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];

//对应的btnClicked方法
-(void)btnClicked:(UIButton *)btn{
    //最好做这种安全判断
    if (ButtonBlock) {
        ButtonBlock( )
     }
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
       ····
    //很重要
    cell.ButtonBlock = ^{
        [self pushToNewPage];
}

参考文档


  1. typeof(a) 和 __typeof(a) 都可以,但 可能是苹果比较推荐前者 ↩

你可能感兴趣的:(Block(一))