之前学过代理、通知,今天看一下iOS中很常用的另一项技术:block 代码块,其实就是回调传值~
来看一下基础的用法:
// block 代码块
// 1,基本的写法 声明 赋值 调用
// 2,typedef
// 3,循环引用
// 类型定义
typedef void(^DCBlock)(int a);
@interface BlockViewController : UIViewController{
NSString * (^StrBlock) (int a);
DCBlock block8;
}
// block 可以被声明成全局的 局部的 或者属性
@property (nonatomic, copy) NSString *(^StrBlock2) (int b);
@end
- (void)viewDidLoad {
[super viewDidLoad];
// self.view.backgroundColor = [UIColor greenColor];
NSMutableArray *array = nil;
array = [[NSMutableArray alloc] init];
[array addObject:@"1"];
// block: 指针指向代码块
// 1,声明了一个block指针
// 返回值 (^指针的名字) (参数) = nil;
void (^block2) (void) = nil;
// 2,给这个指针赋值 给指针赋一段代码
/*
指针的名字 = ^(参数){
具体的代码
return 返回值;
}
*/
block2 = ^(void){
NSLog(@"这事block2 中的代码");
};
// 3,使用这个block(让这个指针所保存的代码执行)
block2();
// 声明一个 有(两个int类型的参数,一个字符串类型的返回值)这样的block
NSString * (^block3) (int a,int b) = nil;
block3 = ^(int a,int b){
int c = a + b;
NSLog(@"c %d",c);
return [NSString stringWithFormat:@"%d",c];
};
NSLog(@"11111");
NSString *str = block3(1,2);
NSLog(@"str %@",str);
NSString *str2 = block3(2,3);
NSLog(@"str2 %@",str2);
// 小结:
// 1,类似方法
// 2,调用的时候 不需要什么对象
// 3,格式上:声明 赋值 调用 格式要求很严格
// block 指的是具有一定类型的一个指针 指向一段有一定格式的代码,并且这段代码可以被调用
// 指针 指向(保存) 一段代码
NSString * (^getPathBlock) (NSString *fileName) = nil;
getPathBlock = ^(NSString *fileName){
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString *filePath = [NSString stringWithFormat:@"%@/%@",path,fileName];
return filePath;
};
NSString *path = getPathBlock(@"a.txt");
NSLog(@"path %@",path);
// 如果某一种格式的block在程序中 需要声明很多个,那么可以把这种类型的block 写成类型定义typedef
void (^block4) (int a) = ^(int a){
NSLog(@"这是block4 %d",a);
NSLog(@"111");
};
block4(4);
DCBlock block5 = ^(int a){
NSLog(@"这事block5 %d",a);
};
block5(5);
// 如果在一个block中 使用局部变量,那么block内部会把这个指针 复制 一份,
// 在block内部给指针重新赋值,全局的可以,有__block描述的也可以,没有经过__block描述的局部变量不可以
// 在吧block内部使用一个变量 ,全局的,局部的都可以
// 如果必须在block内部给指针赋值
// 1,把指针声明成全局的
// 2,局部的就加__block
__block NSMutableArray *array111 = nil;
DCBlock block6 = ^(int a){
NSLog(@"aaa %d",a);
array111 = [[NSMutableArray alloc] init];// 重新给指针赋值
// [array111 addObject:@"11"];// 使用指针
};
block6(6);
NSLog(@"111111 %@",array111);
// block中的循环引用
// 在一个属性描述过的block中 使用对象,这些对象引用计数都会+1
__block BlockViewController *otherSelf = self;
self.StrBlock2 = ^(int b){
NSLog(@"b %d",b);
// [self test];
[otherSelf test];
return [NSString stringWithFormat:@"%d",b];
};
self.StrBlock2(4);
// 由于给block赋一段代码的时候,block用的copy描述,然后block中使用过self 引用计数+1
// 1什么时候可以减掉?
// 当这个block被释放的时候 1会减掉
// block什么时候被释放?
// block被描述成属性了,属性在dealloc方法中释放
// dealloc方法什么时候调用?
// 当前类的对象(self)被释放时,dealloc才会调用
// 当前类的对象什么时候会被释放?
// self引用计数 = 0
// 什么情况下会出现循环引用?
// 1,这个block是属于谁的? self
// 2,是否在block中使用了这个对象
}
- (void)test{
NSLog(@"test");
}
iOS的系统库中有很多地方都用到了block,我们使用的三方库中也很多都用到了,之前我们也看到过,而且苹果也是比较鼓励使用block的,举两个应用的例子
第一个:登录的例子
//首页,可能不需要登录就能看到
- (IBAction)comment:(id)sender {
BOOL isLogin = NO;
UIStoryboard* mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
if (!isLogin){
// 模态一个登录界面
LoginViewController *loginVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
loginVC.pushBlock = ^(void){
CommentViewController *commentVC = [mainStoryboard instantiateViewControllerWithIdentifier:@"CommentViewController"];
[self.navigationController pushViewController:commentVC animated:YES];
};
[self presentViewController:loginVC animated:YES completion:nil];
}else{
// 直接push到评论界面
}
}
//登录界面
@interface LoginViewController : UIViewController
//这里声明了一个block操作
@property (nonatomic, copy) void (^pushBlock) (void);
@end
//点击登录按钮调用block操作
- (IBAction)login:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
self.pushBlock();
}];
}
第二个:封装数据请求类时候的操作
+ (void)startRegister:(void (^)(BOOL isSuccess, NSMutableArray *finishArray))finishBlock{
NSString *str = @"登录成功!";
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:@"1"];
if ([str isEqualToString:@"登录成功!"]){
// 把yes 或者 no 传递到视图控制器中去使用
finishBlock(YES,array);
}else{
finishBlock(NO,nil);
}
}