block说明
block是苹果推荐使用的数据类型。这种数据类型保存了某一段代码,可以在恰当的时机(调用它的时候)再取出来执行.既然是数据类型,那么block也有定义,赋值,使用的过程,跟一般的NSString,NSInterger类似:
//定义一个变量名为myblock的block,类比NSString *str;
void(^myblock)();
//给myblock赋值,类比str = @"wuliao"
myblock = ^{
NSLog(@"hahahahshfAAAA");//{}大括号之间就保存了一个代码片段,在我们调用这个block的时候,就会执行这个代码片段。
};
//调用这个block。这里的用法又有点类似函数。
myblock();
简单的应用场景
我们要传递一个要消失的页面的数据的时候,我们会想到用delegate,通知中心,键值观察模式,甚至是单例。每种方式都会有它的局限性和优势。这里我们尝试用block来实现。
以下代码就模拟一个登陆的场景。通常我们的app中有些功能需要登陆后才能查看。大体流程是点击按钮,判断是否是登录状态,否,则跳到登录页面,在登录页面录入信息。登录成功,返回之前页面并把数据加载到之前的页面。
代码:我们只有两个viewcontroller,一个是用户未登陆下的界面,一个是登陆界面。
Talk is cheap show me the code
未登录的界面.m文件
#import "ViewController.h"
#import "LoginViewController.h"
@interface ViewController ()
{
UILabel *myName;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UIButton *bun = [UIButton buttonWithType:UIButtonTypeRoundedRect];
bun.backgroundColor = [UIColor orangeColor];
bun.frame = CGRectMake(10, 200, [UIScreen mainScreen].bounds.size.width-20, 30);
bun.layer.cornerRadius = 8;
bun.clipsToBounds = YES;
[bun setTitle:@"个人信息" forState:UIControlStateNormal];
[bun setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[bun addTarget:self action:@selector(loginsuccess:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:bun];
myName = [[UILabel alloc]initWithFrame:CGRectMake(100, 250, 100, 40)];
myName.frame = CGRectMake(10, CGRectGetMaxY(bun.frame)+10, [UIScreen mainScreen].bounds.size.width-20, 40);
[self.view addSubview:myName];
}
- (void)loginsuccess:(UIButton *)sender {
LoginViewController *login = [[LoginViewController alloc]init];
[login loginResult:^(NSDictionary *successDict) {
myName.text = successDict[@"myName"];
}];
[self presentViewController:login animated:YES completion:nil];
}
@end
登录界面 .h
#import <UIKit/UIKit.h>
typedef void(^LoginSuccess) (NSDictionary *successDict);
@interface LoginViewController : UIViewController
- (void)loginResult:(LoginSuccess)loginResult;
@end
另一种写法,直接在 登录界面 .h 定义一个block类型的成员变量
我们就不用typedef来定义Block类型,而是直接定义一个block类型的成员变量LoginSuccess
@property (nonatomic,copy) void (^LoginSuccess)(NSDictionary *successDict);
如果是按照这种写法,那么在 未登录.m 中,点击登录按钮的时候代码应该这样子写
login.LoginSuccess = ^(NSDictionary *successDict){
myName.text = successDict[@"myName"];
};
而且也不用在登录的控制器里,实现下面这句代码了
- (void)loginResult:(LoginSuccess)loginResult;
大家可以体会两种写法的好处
登录界面 .m
#import "LoginViewController.h"
@interface LoginViewController ()
{
UITextField *userName;
LoginSuccess _loginSuccess;
}
@end
@implementation LoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
userName = [[UITextField alloc]initWithFrame:CGRectMake(20, 250, [UIScreen mainScreen].bounds.size.width-40, 45)];
userName.placeholder = @"请输入用户名";
userName.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:userName];
UITextField *password = [[UITextField alloc]initWithFrame:CGRectMake(20, 320, [UIScreen mainScreen].bounds.size.width-40, 45)];
password.placeholder = @"请输入密码";
password.secureTextEntry = YES;
password.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:password];
//登录按钮
UIButton *bun = [UIButton buttonWithType:UIButtonTypeRoundedRect];
bun.backgroundColor = [UIColor orangeColor];
bun.tag = 1212;
bun.frame = CGRectMake(20, [UIScreen mainScreen].bounds.size.height-350, [UIScreen mainScreen].bounds.size.width-40, 45);
bun.layer.cornerRadius = 8;
bun.clipsToBounds = YES;
[bun setTitle:@"登陆" forState:UIControlStateNormal];
[bun setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[bun setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled];
[bun addTarget:self action:@selector(loginsuccess) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:bun];
//加载数据菊花
UIActivityIndicatorView *activityview = [[UIActivityIndicatorView alloc]init];
activityview.center = self.view.center;
activityview.tag = 1131;
activityview.color = [UIColor grayColor];
[activityview hidesWhenStopped];
activityview.accessibilityNavigationStyle = UIActivityIndicatorViewStyleGray;
[self.view addSubview:activityview];
}
-(void)loginResult:(LoginSuccess)loginResult
{
_loginSuccess = loginResult;
}
-(void)loginsuccess
{
[self.view endEditing:YES];
UIActivityIndicatorView *activityview = (UIActivityIndicatorView*)[self.view viewWithTag:1131];
[activityview startAnimating];
UIButton *bun = (UIButton *)[self.view viewWithTag:1212];
bun.enabled = NO;
[self performSelector:@selector(askData) withObject:self afterDelay:0.5];
}
-(void)askData
{
UIActivityIndicatorView *activityview = (UIActivityIndicatorView*)[self.view viewWithTag:1131];
[activityview stopAnimating];
NSDictionary *dic= @{@"state":@"登陆成功!",
@"myName":userName.text};
//调用空的block时 ,报错exc_bad_access,所有每次调用block的时候必须要,先检查
if (_loginSuccess) {
//登陆成功,把数据返回上个界面
_loginSuccess(dic);
}
[self dismissViewControllerAnimated:YES completion:^{
}];
}
@end
有说的不对的地方,也请大家不吝赐教哈谢谢