ios block回调使用
突然觉得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,另外一件事情是可以自定义的
上面那个例子如果不存在网络加载这样的耗时操作,也可以不用异步加载多线程请求数据。大家明白其中原理就好。