突然觉得block用来写回调方法,显得非常直观。建议使用.
基本使用如下:
#import "ViewController.h"
typedef void (^done1)(NSString *testString);
typedef int (^done2)(NSString *testString);
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self testBlock1WithDone:^(NSString *testString){
NSLog(@"%@",testString);
}];
[self testBlock1_1WithDone:^(NSString *testString){
if ([testString isEqualToString:@"test1_1"]) {
return 1;
}else{
return 2;
}
}];
[self testBlock2WithDone:^(NSString *testString){
NSLog(@"%@",testString);
}];
[self testBlock2_1WithDone:^(NSString *testString){
if ([testString isEqualToString:@"test2_1"]) {
return 3;
}else{
return 4;
}
}];
}
-(void)testBlock1WithDone:(void(^)(NSString *testString))completion{
completion(@"test1");
}
-(void)testBlock1_1WithDone:(int(^)(NSString *testString))completion{
NSLog(@"%d",completion(@"test1_1"));
}
-(void)testBlock2WithDone:(done1)completion{
completion(@"test2");
}
-(void)testBlock2_1WithDone:(done2)completion{
NSLog(@"%d",completion(@"test2_1"));
}
@end
运行打印结果:
2014-11-30 19:44:18.397 BlockDemo[4609:96915] test1
2014-11-30 19:44:18.397 BlockDemo[4609:96915] 1
2014-11-30 19:44:18.397 BlockDemo[4609:96915] test2
2014-11-30 19:44:18.398 BlockDemo[4609:96915] 3
以上我用两种方法实现了有返回值和无返回值的两种block的写法。block的语法跟我们常用语言的语法有蛮大区别,很多程序员并不能很快的适应。
block是一个特殊的OC对象, 它建立在栈上, 而不是堆上, 这么做一个是为性能考虑,还有就是方便访问局部变量.
默认情况下block使用到的局部变量都会被复制,而不是保留.
所以它无法改变局部变量的值.
如果在变量面前加上__block, 那么编译器回去不会复制变量, 而是去找变量的地址, 通过地址来访问变量, 实际上就是直接操作变量.
另外块是在栈上分配的, 所以一旦离开作用域, 就会释放, 因此如果你要把快用在别的地方, 必须要复制一份.
所以在属性定义一个快的时候需要使用copy: @property (nonatomic, copy) void (^onTextEntered)(NSString *enteredText);
块是不能保留的, retain对块没有意义.
//
// MartinLiViewController.m
// Dispatch_async
//
// Created by dongway on 14-7-23.
// Copyright (c) 2014年 dongway. All rights reserved.
//
#import "MartinLiViewController.h"
#import "InteractWithServerOnJSON.h"
#import "SVProgressHUD.h"
@interface MartinLiViewController ()
@end
@implementation MartinLiViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)dispatchLoadData:(id)sender {
NSString *urlString = @"http://old.idongway.com/sohoweb/q?method=store.get&format=json&cat=1";
//只需要写这么一句代码就可以加载出来网络数据了,包括提交网络请求,或者网络耗时操作。
[self dispatchLoadDataWithUrlString:urlString complite:^(id result){
NSArray *stores = [result objectForKey:@"stores"]; //获取网络数据,并可以在这个位置刷新主线程UI
NSLog(@"%@",[[stores firstObject] valueForKey:@"storeName"]);
}];
}
-(void)dispatchLoadDataWithUrlString:(NSString *)urlString complite:(void(^)(id dict))compliteAction{
[SVProgressHUD show];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//InteractWithServerOnJSON interactWithServerOnJSON 这是我自己封装的加载json数据的方法
NSDictionary *result = [InteractWithServerOnJSON interactWithServerOnJSON:urlString];
dispatch_sync(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
compliteAction(result);
});
});
}
@end
//这里是加载http请求
+(NSDictionary *)interactWithServerOnJSON:(NSString *)urlString
{
NSError *error;
NSString *urlStringEncoding = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@",urlStringEncoding);
//加载一个NSURL对象
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStringEncoding]];
//将请求的url数据放到NSData对象中
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if (response != nil && error == nil) {
return [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&error];
} else {
return nil;
}
}
回调的使用场景:
1,要求必须在某件事情做完后才能做另外一件事情
2,另外一件事情是可以自定义的
上面那个例子如果不存在网络加载这样的耗时操作,也可以不用异步加载多线程请求数据。大家明白其中原理就好。