Block 的理解和使用


理解和推倒


C 的声明符

先复习一下 C 的声明符:

1、基本申明

int a

int指定了类型,a是变量的名称。
声明符可以使用修饰符,C 有三种修饰符:*[]()


1.1 指针

int *a

a是指向int的一个指针。


1.2 数组

int a[]

a是一个由int组成的数组。


1.3 函数

int f()

f是一个返回int的函数。


2、混合申明

这些修饰符可以混合使用。混合时,从变量名称开始往右读,读到尽头或闭括号之后再从变量名称开始往左读

2.1 int *a[]

先往右读,[]是有一个数组,再往左读int *是指向int的指针。
所以int *a[]就是由 指向int的指针 组成的数组,等价于int *(a[])。数组a 中的元素,都是指向 int 的指针。


2.2 int (*a)[]

先由a往右读,碰到),因此再往左读,读到*,因此是一个指针。然后再往右读[],再往左读int。所以最后int (*a)[]是指向由int组成的数组的指针。


2.3 int* f()

//声明一个函数f,返回类型为int* ;
比如

int* f(){  // 返回一个new 的 int,要记得delete哦~~
  return new int();
}

2.4 int (*f)()

f 是个指向函数的指针,所指向的函数没有参数,返回int。
这是一个函数指针,指向一个 int f() 这样的函数。比如有函数:

int get1() { return 1; }
int get2() { return 2; }

Block 的申明符

block 修饰符和指向函数的指针非常相似。上面我们提到int (*f)()是一个指向返回int函数的指针,类似地,int (^b)() 是一个指向返回int函数的 block 指针,简称返回int的 block。

因为 block 总是指向函数的,所以int ^a和int ^b()都是非法的,因为不存在指向int的 block。

block 和指向函数的指针的区别在于,block 创建了一个闭包。

代码块(也称闭包)修饰符(^)
该修饰符只能用于函数,所以int ^a;是错误的


“block是一个OC对象,这意味着它能被添加到集合,比如NSArray、NSDictionary”


申明一个block变量

1、无入参、无出参的 blcok
void (^myBlock)();

其中第一个void是返回值,可以是任意类型;
中间括号中^后面的是这个block变量的名字,我把它命名为myBlock;
最后一个括号中是参数;

//返回值类型(^block的名字)(参数类型) = ^(参数类型和参数名) {};

  void(^block)() = ^(){
      NSLog(@"调用了block");
  };
//当然,没有参数的时候可以把括号省去
  void(^block)() = ^{
      NSLog(@"调用了block");
  };


2、多参数有返回值的 block,可以写成如下样式:

int (^myBlock)(int,int);

同样,你也可以给参数起名字:

int (^myBlock)(int a,int b);

使用

    int(^block)(int) = ^(int a){
        return a + 1;
    };
    
    NSLog(@"block5 : %d",block(5));

inline:系统提供的定义block的宏

block快捷方式 输入:inline

returnType(^blockName)(parameterTypes) = ^(parameters) {
      statements
    };

设置block类型私有变量

1、申明

@property (nonatomic,copy) void (^progressHandle)(double progress);

2、初始化

self.progressHandle = ^(double progress){
    
        NSLog(@"progress:%f",progress);
        
    };

3、调用

- (IBAction)btnOnClick:(id)sender {
    self.progressHandle(1.2333);
}

函数入参为block

##1、 没有入参、没有出参的block

//创建传入block的方法
//方法名中,block 是变量名称,修饰block 的void,代表这个block返回为空,(^)代表这是一个block,()代表传入参数为空
-(void)btnClickwithClock:(void (^)())block{
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1.0];

    block();
   
    [UIView commitAnimations];
   
}

//调用
 [self btnClickwithClock:^{
        NSLog(@"btnClickwithClock ---- ");
    }];

##2、 有入参、没有出参的block

//入参为两个字符串的block
-(void)btnClickwithClock2:(void (^)(NSString *str0,NSString *str1))block{
    
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1.0];
    
    block(@"1",@"2");
    
    [UIView commitAnimations];
    
}

 [self btnClickwithClock2:^(NSString *str0, NSString *str1) {
       NSLog(@"str0 : %@ , str1 : %@",str0,str1);
   }];
    

##3、 有入参、有出参的block

1、定义


//入参为两个字符串、出参为一个整数的block,
-(void)btnClickwithClock2:(NSInteger (^)(NSString *str0,NSString *str1))block{
    
    
    NSInteger a = block(@"1",@"2");
    NSLog(@"a : %ld",(long)a);
    
}

//入参为两个字符串、出参为一个字符串的block,
-(void)btnClickwithClock3:(NSString *(^)(NSString *str0,NSString *str1))block{
    
    NSString *b = block(@"1",@"2");
    NSLog(@"b : %@",b);
    
}

2、调用

    [self btnClickwithClock2:^NSInteger(NSString *str0, NSString *str1) {
       
       return 5;
   }];
    
    [self btnClickwithClock3:^NSString *(NSString *str0, NSString *str1) {
        
        return @"123";
    }];

打印结果

 a : 5

自定义block:使用block保存代码

1、创建名称、设置返回类型

typedef void(^MSBlockButtonOnClick)(void);
typedef void(^MSBlockSelectPeriod)(NSString *startTime,NSString *endTime);
typedef void(^MSBlockDidSelectPhoto)(NSArray <UIImage *>*photoArray);

2、设置变量及初始化方法

@property (nonatomic,copy) MSBlockButtonOnClick blockBtnOnClick;
@property (nonatomic,copy) MSBlockDidSelectPhoto blockDidSelectPhoto;
@property (nonatomic,copy) MSBlockSelectPeriod blockSelectPeriod;

-(void)setBlockCommitBtnOnClick:(MSBlockButtonOnClick)blockCommitBtnOnClick
{
    _blockCommitBtnOnClick = blockCommitBtnOnClick;
}

-(void)setBlockDidSelectPhoto:(MSBlockDidSelectPhoto)blockDidSelectPhoto
{
    _blockDidSelectPhoto = blockDidSelectPhoto;
}

//选择控制器
- (void)datePicker:(MSTimePicker *)datePicker didSelectDate:(MSTimeModel *)datePickerDate{
    
    if (_blockSelectPeriod) {
        
        NSString *startStr = [MSTimeTools getStrFromDate:self.startDate withStyle:MSTimeStyleDateTime];
        NSString *endStr = [MSTimeTools getStrFromDate:self.endDate withStyle:MSTimeStyleDateTime];
        
        _blockSelectPeriod(startStr,endStr);
    }
    
}

3、调用

- (void)ensureBtnOnClick{
    
    if (_blockCommitBtnOnClick) {
        
        _blockCommitBtnOnClick();
    }
    
}

- (void)setImgContent:(UIImage *)image{
    
    if (_blockDidSelectPhoto) {
        _blockDidSelectPhoto(@[image]);
    }
}

block里面调用变量

在Block中使用附有__strong修饰符的对象类型自动变量,那么Block从栈复制到堆时,该对象为Block所持有。因而容易引起循环引用。

为避免此类事件,可用__weak修饰对象。

常用的宏

//block 中使用Self
#define WS(weakSelf)        __weak __typeof(&*self)weakSelf = self
//block 中调用cell
#define WC(weakCell,cell)   __weak __typeof(&*cell)weakCell = cell

当在block内部使用,block外部定义的局部变量时,如果变量没有被__block修饰,则在block内部是readonly(只读的),不能对他修改。如果想修改,变量前必须要有__block修饰。
__block的作用告诉编译器,编译时在block内部不要把外部变量当做常量使用,还是要当做变量使用.
如果再block中访问全局变量,就不需要__block修饰.



参考资料

发布了41 篇原创文章 · 获赞 163 · 访问量 66万+

猜你喜欢

转载自blog.csdn.net/lovechris00/article/details/78123690
今日推荐