Block 的初步理解
- 例如定義一個(gè)block:
void(^myblock)(int);=>與int a;比較 - block的類型:
void(^)(int);=>等價(jià)于int - block的變量名:
myblock=>等價(jià)于a - 注意:
- 定義block時(shí)若有輸入?yún)?shù)(本例為int),參數(shù)名可有(int x)可無(wú)(int)但必須有參數(shù)的類型,但實(shí)現(xiàn)是必須有參數(shù)的類型和變量名.
- 實(shí)現(xiàn)block時(shí),也可以將block返回類型寫在實(shí)現(xiàn)中(通常不寫),寫在僅僅挨著
^后面,不需要(),這樣有利于讓實(shí)現(xiàn)者知道該block返回什么值,(其實(shí)這樣寫更加規(guī)范,蘋果官方有使用:當(dāng)帶有返回值的block作為一個(gè)方法的參數(shù)時(shí),當(dāng)調(diào)用這個(gè)方法時(shí),系統(tǒng)的提示代碼在block實(shí)現(xiàn)中會(huì)加上返回類型,具體看典例)
//實(shí)現(xiàn)中寫返回參數(shù)類型
NSString *(^myblockx)(int) = ^NSString *(int a){
return @"";
};
//實(shí)現(xiàn)中不寫返回參數(shù)類型
NSString *(^myblockx2)(int) = ^(int a){
return @"";
};
定義一個(gè)block
-
無(wú)返回值有參數(shù)
//定義一個(gè)block變量,然后給這個(gè)變量賦值:myblock //此時(shí)void(^)(int)為類型名,myblock1為變量名 //int a ; a = 3; void(^myblock1)(int); myblock1 = ^(int a){ }; //定義一個(gè)block變量并賦值//int a = 3; void(^myblock2)(int) = ^(int a){ }; -
無(wú)返回值無(wú)參數(shù)
//1.先定義,在賦值 void(^myblock0)(); myblock0 = ^{ }; //2.定義時(shí)賦值(略) -
有返回值無(wú)參數(shù)
//1.先定義,在賦值(略) //2.定義時(shí)賦值 int(^myblock4)()=^{ return 3; }; -
有返回值有參數(shù)且參數(shù)(注意參數(shù)中可以有變量名也可以沒有變量名,變量名與實(shí)現(xiàn)時(shí)參數(shù)的變量名無(wú)關(guān)聯(lián))
//1.先定義,在賦值 int(^myblock7)(int c ,int d); myblock7 = ^(int a, int b){ return a + b; }; //2.定義時(shí)賦值 int(^myblock6)(int ,int) = ^(int a, int b){ return a + b; }; -
參數(shù)為block
//重要:block的傳入?yún)?shù)為block類,理解!!!! //1.定義時(shí)賦值(參數(shù)block無(wú)變量名) //同理當(dāng)傳入?yún)?shù)為block時(shí),可以有變量名,也可以無(wú)變量名 //傳入的block類型為void(^)():無(wú)返回值無(wú)參數(shù)型 int(^blockx)(void(^)())= ^(void(^x)()){ return 2; }; //2.先定義,在賦值(參數(shù)block有變量名:mmm,參數(shù)block中的參數(shù)名q也是可有可無(wú)) //傳入的block類型為int(^)(int):有返回值有參數(shù)型 int(^blocky)(int(^mmm)(int q)); blocky = ^(int(^x)(int a)){ return 2; };
使用typedef定義block類
- 面向?qū)ο笏枷?將block定義成一個(gè)自定義類,然后使用這個(gè)類創(chuàng)建變量賦值block,使用typedef
//定義一個(gè)sumblock類(參數(shù)中的變量名可有可無(wú))
typedef int(^sumblock)(int c ,int d);
sumblock block = ^(int a,int b){
return a + b;
};
//實(shí)質(zhì):
// sumblock block;等價(jià)于 int(^block)(int,int);
//用block替換掉sumblock;
//舉例:定義一個(gè)blockz,傳入?yún)?shù)為sumblock類,然后賦值
//sumblock只是類型,變量名可有可無(wú),也可以傳入sumblock vvv
int(^blockz)(sumblock);
blockz = ^(sumblock block2){
return 2;
};
Block的常見使用
- block成為屬性
-
舉例:
@property (nonatomic, strong) void(^operation)(); @property (nonatomic, strong) NSString *operation; 作用: 把block保存到對(duì)象中,恰當(dāng)時(shí)機(jī)的時(shí)候才去調(diào)用
注意:這里容易引發(fā)循環(huán)引用,引起原因前面講過(guò),如何解決(weakself),不再贅述.
-
- block成為方法參數(shù):傳入一個(gè)block參數(shù)
-
舉例:
- (void)eat:(void(^)(int))block; - (void)eat:(nsstring *)block; 作用: 把block當(dāng)做方法的參數(shù)使用,外界不調(diào)用,都是方法內(nèi)部去調(diào)用,Block實(shí)現(xiàn)交給外界決定.(注意理解)
-
- 成為返回參數(shù):該方法返回一個(gè)block
-
舉例:
- (void(^)(int))run; -(nsstring *)run; 作用:把block當(dāng)做方法的返回值,目的就是為了代替方法,block交給內(nèi)部實(shí)現(xiàn),外界不需要知道Block怎么實(shí)現(xiàn),只管調(diào)用
-
舉例使用:
//Person.h
#import <Foundation/Foundation.h>
// name:類型的別名
typedef void(^BlockName)();
@interface Person : NSObject
//block作為屬性
// block:既可以使用copy,也可以使用strong,但是建議用copy
// block類型:void(^)()
@property (nonatomic, strong) void(^operation)();
//block 作為參數(shù)
// 參數(shù)類型:block類型
- (void)eat:(void(^)())block;
- (void)eat2:(BlockName)block;
//傳入?yún)?shù)block帶返回值類型
- (void)eat3:(NSString *(^)(int))block;
//block作為返回值
- (void)run:(int)metre;
- (void(^)(int))run;
@end
#import "Person.h"
@implementation Person
- (void)eat:(void (^)())block
{
block();
}
-(void)eat3:(NSString *(^)(int))block{
block(3);
}
- (void)run:(int)metre
{
NSLog(@"%d",metre);
}
- (void (^)(int))run
{
return ^(int meter){
NSLog(@"跑了%d米",meter);
};
}
-(void)eat2:(BlockName)block{
block();
}
@end
//viewcontroller
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic, strong) Person *p;
@end
@implementation ViewController
//block作為方法返回值(代碼在內(nèi)部,調(diào)用在外部)
- (void)block3
{
Person *p = [[Person alloc] init];
[p run:2];
//注意理解;p.run等價(jià)于[p run];
//注意這兩種調(diào)用結(jié)果一樣,第二種是第一種的實(shí)現(xiàn)過(guò)程
p.run(2);//調(diào)用方法:非常牛逼!!!!
void(^run)(int) = p.run;
run(2);
//雖然p.run返回的是一個(gè)void(^)(int)類型的block,但這樣寫也對(duì)void(^run)(),沒寫參數(shù)就是參數(shù)都為0,run()就是傳入?yún)?shù)為0
void(^run2)() = p.run;
run2();
}
//block作為方法參數(shù)(外部傳代碼,調(diào)用在內(nèi)部)
- (void)block2
{
Person *p = [[Person alloc] init];
void(^block)() = ^{
NSLog(@"吃東西");
};
[p eat:block];
[p eat2:block];
// 傳入block給參數(shù)的Block賦值
[p eat:^{
NSLog(@"吃東西");
}];
//該block實(shí)現(xiàn)可以沒有block返回類型:NSString *,但有更規(guī)范
[p eat3:^NSString *(int a) {
return [NSString stringWithFormat:@"該block實(shí)現(xiàn)中有返回值類型NSString,傳入?yún)?shù)為:%zd",a];
}];
}
//block作為屬性(保存一段代碼到對(duì)象中)
- (void)block1
{
Person *p = [[Person alloc] init];
void(^block)() = ^() {
NSLog(@"執(zhí)行對(duì)象中block");
};
p.operation = block;
p.operation = ^(){
NSLog(@"執(zhí)行對(duì)象中block");
};
_p = p;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//執(zhí)行對(duì)象中保存的block
_p.operation();
}
@end