* author:conowen@大鐘
* E-mail:conowen@hotmail.com
1、Block的定義
Block是Objc赘艳、C、C++的一個語言級別擴充功能辆脸,Block其實就是一塊代碼段但校,你可以很方便地把一個代碼段傳遞到不同的方法里面或者不同的類,就像傳值一樣方便啡氢。Block可以當做Objc里面的一個對象状囱。(也就是說,你可以把它當做一個類似NSString的對象)
2倘是、Block的聲明
//As a local variable:
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
//As a property:
@property (nonatomic, copy, nullability) returnType (^blockName)(parameterTypes);
//As a method parameter:
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
//As an argument to a method call:
[someObject someMethodThatTakesABlock:^returnType (parameters) {...}];
//As a typedef:
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};
上述定義來源
3亭枷、Block聲明詳解
其實Block的定義有點類似函數(shù)指針
引申:指針函數(shù)與函數(shù)指針的區(qū)別
- a、指針函數(shù)
表示函數(shù)返回值是一個指針類型搀崭,定義如下
//類型標識符 *函數(shù)名(參數(shù)表)
int *fun(x叨粘,y);
- b猾编、函數(shù)指針
表示指向這個函數(shù)的指針變量,定義如下
類型標識符 (*函數(shù)名)(參數(shù)表)
int (*fun) (int x,y); //函數(shù)名前面有一個星號升敲,然后用小括號包起來
fun=funTest; /* 將funTest函數(shù)的首地址賦給指針
而Block就是
int (^fun) (int,int);
3答倡、Block的應(yīng)用場景
3.1、定義一個Block驴党,然后輸出打印信息
int (^addFun)(int,int) = ^int(int a,int b){
return a + b;
};
NSLog(@"addValue = %d",addFun(1,2));
打印消息是
2016-06-01 11:27:14.191 Runtime[10910:4558911] addValue = 3
3.2瘪撇、Block與Delegate的區(qū)別
這是最簡單的Block使用,一般我們使用Block來做一些有趣的事情港庄,例如代替delegate倔既,平常我們在不同的類傳值的話,一般使用delegate鹏氧,雖然也能實現(xiàn)渤涌,但是寫法比較繁瑣,用Block就能很輕松實現(xiàn)度帮,而且代碼量少了不少歼捏。
下面的小Demo就依次對比了Delegate與Block在不同類的傳值的區(qū)別
第一個ViewController的代碼如下
//
// ViewController.m
// Runtime
//
// Created by idealMac2 on 16/5/20.
// Copyright ? 2016年 GValley. All rights reserved.
//
#import "ViewController.h"
#import "SecondViewController.h"
@interface ViewController () <SecondViewControllerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 60.0, 20.0)];
[btn setTitle:@"open" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(openAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)openAction:(id)sender{
NSLog(@"openAction");
SecondViewController *secondViewController = [SecondViewController new];
secondViewController.callBackValue = ^ void (NSString *str){
NSLog(@"Block str = %@",str);
};
secondViewController.delegate = self;
[self presentViewController:secondViewController animated:YES completion:nil];
}
#pragma mark SecondViewControllerDelegate
- (void)closeAction:(NSString *) str{
NSLog(@"delegate str = %@",str);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
第二個ViewController的頭文件如下
//
// SecondViewController.h
// Runtime
//
// Created by idealMac2 on 16/6/1.
// Copyright ? 2016年 GValley. All rights reserved.
//
#import <UIKit/UIKit.h>
//聲明delegate
@protocol SecondViewControllerDelegate <NSObject>
@optional
- (void)closeAction:(NSString *) str;
@end
@interface SecondViewController : UIViewController
//聲明Block
@property (nonatomic,copy) void(^callBackValue)(NSString *);
@property (nonatomic,weak) id<SecondViewControllerDelegate> delegate;
@end
第二個ViewController的實現(xiàn)文件如下
//
// SecondViewController.m
// Runtime
//
// Created by idealMac2 on 16/6/1.
// Copyright ? 2016年 GValley. All rights reserved.
//
#import "SecondViewController.h"
@interface SecondViewController ()
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 200, 60.0, 20.0)];
[btn setTitle:@"close" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)closeAction:(id)sender{
NSString *strA = @"closed";
//Block的方式
self.callBackValue(strA);
//Delegate的方式
if (self.delegate && [self.delegate respondsToSelector:@selector(closeAction:)]) {
[self.delegate closeAction:strA];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
打印消息如下
2016-06-01 12:10:31.211 Runtime[10959:4573582] block str = closed
2016-06-01 12:10:31.211 Runtime[10959:4573582] delegate str = closed
4、Block與外部變量的關(guān)系
我們知道笨篷,Block有一個神奇之處瞳秽,它可以直接使用Block之外的變量,如下面的代碼率翅。
int c = 0;
int (^addFun)(int,int) = ^int(int a,int b){
return a + b + c;
};
NSLog(@"addValue = %d",addFun(1,2));
但是如果要修改外部變量练俐,就會出現(xiàn)無法修改的問題,同時冕臭,使用外部變量腺晾,也會存在引起循環(huán)引用的問題。
4.1辜贵、如何修改Block外部變量
解決這個問題有兩種方法:
一種是C語言的方法悯蝉,因為C語言中的靜態(tài)變量、靜態(tài)全局變量托慨,全局變量是允許Block修改其值的鼻由。因為“全局變量” 和“ 全局靜態(tài)變量” 由于作用域是全局,所以在 Block 內(nèi)訪問和讀寫這兩類變量和普通函數(shù)沒什么區(qū)別厚棵。但是“ 靜態(tài)變量” 作用域在 block 之外蕉世,那Block是怎么對它進行讀寫呢?其實“靜態(tài)變量” 是通過指針傳遞婆硬,將變量傳遞到 Block 里面狠轻,所以可以修改變量值。普通的非全局變量彬犯,都是通過傳值進去Block里面向楼,當然無法修改這個變量的值查吊。
如下面的代碼
static int c = 0;//靜態(tài)變量
int (^addFun)(int,int) = ^int(int a,int b){
c = 1;
return a + b + c;
};
NSLog(@"addValue = %d",addFun(1,2))
還有一種方法就是通過在變量外部加上“__block”說明符,其實加了__Block之后蜜自,這個變量就變成了一個結(jié)構(gòu)體指針變量菩貌,這個原理和靜態(tài)變量一樣,由傳值方式改為指針傳遞重荠,所以就可以更改變量了箭阶。
如下所示
__block int c = 0;
int (^addFun)(int,int) = ^int(int a,int b){
c = 1;
return a + b + c;
};
NSLog(@"addValue = %d",addFun(1,2));
4.2、如何避免Block的循環(huán)引用
** 待補充**