前言:Block從會(huì)用俱济,到理解,到頓悟债蜜;清新的簡書晴埂,記錄清楚的簡述。
不說block你看我就夠了-寻定。-
iOSer英語是不應(yīng)該成為攔路虎的水果官方block文檔
第一部分儒洛,定義和使用block
- (void)viewDidLoad
{
[super?viewDidLoad];
//(1)定義無參無返回值的Block
void(^printBlock)()?=?^(){
printf("no?number");
};
- (void)viewDidLoadprintBlock();
printBlock(9);
intmutiplier?=?7;
//(3)定義名為myBlock的代碼塊,返回值類型為int
int(^myBlock)(int)?=?^(intnum){
returnnum*mutiplier;
}
//使用定義的myBlock
intnewMutiplier?=?myBlock(3);
printf("newMutiplier?is?%d",myBlock(3));
}
//定義在-viewDidLoad方法外部
//(2)定義一個(gè)有參數(shù)狼速,沒有返回值的Block
void(^printNumBlock)(int)?=?^(intnum){
printf("int?number?is?%d",num);
};
{
[super viewDidLoad];
//(1)定義無參無返回值的Block
void (^printBlock)() = ^(){
printf("no number");
};
printBlock();
printBlock(9);
int mutiplier = 7;
//(3)定義名為myBlock的代碼塊琅锻,返回值類型為int
int (^myBlock)(int) = ^(int num){
return num*mutiplier;
}
//使用定義的myBlock
int newMutiplier = myBlock(3);
printf("newMutiplier is %d",myBlock(3));
}
//定義在-viewDidLoad方法外部
//(2)定義一個(gè)有參數(shù),沒有返回值的Block
void (^printNumBlock)(int) = ^(int num){
printf("int number is %d",num);
};
定義Block變量向胡,就相當(dāng)于定義了一個(gè)函數(shù)恼蓬。但是區(qū)別也很明顯,因?yàn)楹瘮?shù)肯定是在-viewDidLoad方法外面定義僵芹,而Block變量定義在了viewDidLoad方法內(nèi)部处硬。當(dāng)然,我們也可以把Block定義在-viewDidLoad方法外部淮捆,例如上面的代碼塊printNumBlock的定義郁油,就在-viewDidLoad外面。
再來看看上面代碼運(yùn)行的順序問題攀痊,以第(3)個(gè)myBlock距離來說桐腌,在定義的地方,并不會(huì)執(zhí)行Block{}內(nèi)部的代碼苟径,而在myBlock(3)調(diào)用之后才會(huì)執(zhí)行其中的代碼案站,這跟函數(shù)的理解其實(shí)差不多,就是只要在調(diào)用Block(函數(shù))的時(shí)候才會(huì)執(zhí)行Block體內(nèi)(函數(shù)體內(nèi))的代碼棘街。所以上面的簡單代碼示例蟆盐,我可以作出如下的結(jié)論,
(1)在類中遭殉,定義一個(gè)Block變量石挂,就像定義一個(gè)函數(shù);
(2)Block可以定義在方法內(nèi)部险污,也可以定義在方法外部痹愚;
(3)只有調(diào)用Block時(shí)候,才會(huì)執(zhí)行其{}體內(nèi)的代碼蛔糯;
(PS:關(guān)于第(2)條拯腮,定義在方法外部的Block,其實(shí)就是文件級(jí)別的全局變量)
那么在類中定義一個(gè)Block蚁飒,特別是在-viewDidLoad方法體內(nèi)定義一個(gè)Block到底有什么意義呢动壤?我表示這時(shí)候只把它當(dāng)做私有函數(shù)就可以了。我之前說過淮逻,Block其實(shí)就相當(dāng)于代理琼懊,那么這時(shí)候我該怎樣將其與代理類比以了解呢。這時(shí)候我可以這樣說:本類中的Block就相當(dāng)于類自己服從某個(gè)協(xié)議爬早,然后讓自己代理自己去做某個(gè)事情肩碟。很拗口吧?看看下面的代碼凸椿,
//定義一個(gè)協(xié)議
@protocol?ViewControllerDelegate
-?(void)selfDelegateMethod;
@end
//本類實(shí)現(xiàn)這個(gè)協(xié)議ViewControllerDelegate
@interface?ViewController?()
@property?(nonatomic,?assign)?id?delegate;
@end
接著在-viewDidLoad中的代碼如下削祈,
- (void)viewDidLoad
{
[super?viewDidLoad];
//?Do?any?additional?setup?after?loading?the?view?from?its?nib.
self.delegate?=?self;
if(self.delegate?&&?[self.delegate?respondsToSelector:@selector(selfDelegateMethod)])?{
[self.delegate?selfDelegateMethod];
}
}
#pragma?mark?-?ViewControllerDelegate?method
//實(shí)現(xiàn)協(xié)議中的方法
-?(void)selfDelegateMethod
{
NSLog(@"自己委托自己實(shí)現(xiàn)的方法");
}
代理形象說:
nextController姑且稱為B
ViewController姑且稱為A
B說:我這里有錢(你需要的值)但是你們誰要的話必須遵守我的規(guī)則(協(xié)議)
并且按照我的規(guī)定(協(xié)議)去做一些事情(實(shí)現(xiàn)方法)
第二部分:
__block關(guān)鍵字的使用
在Block的{}體內(nèi),是不可以對(duì)外面的變量進(jìn)行更改的脑漫,比如下面的語句髓抑,
- (void)viewDidLoad
{
//將Block定義在方法內(nèi)部
intx?=?100;
void(^sumXAndYBlock)(int)?=?^(inty){
x?=?x+y;
printf("new?x?value?is?%d",x);
};
sumXAndYBlock(50);
}
這樣是修改不了x的值的,如果你想在block里面修改外部的值的話
你需要這樣
__block intx = 100;
第三部分:
把block作為參數(shù)优幸,在頁面之間穿梭吧
Block作為property屬性實(shí)現(xiàn)頁面之間傳值
需求:在ViewController中吨拍,點(diǎn)擊Button,push到下一個(gè)頁面NextViewController网杆,在NextViewController的輸入框TextField中輸入一串字符羹饰,返回的時(shí)候伊滋,在ViewController的Label上面顯示文字內(nèi)容,
(1)第一種方法:首先看看通過“協(xié)議/代理”是怎么實(shí)現(xiàn)兩個(gè)頁面之間傳值的吧队秩,
//NextViewController是push進(jìn)入的第二個(gè)頁面
//NextViewController.h?文件
//定義一個(gè)協(xié)議笑旺,前一個(gè)頁面ViewController要服從該協(xié)議,并且實(shí)現(xiàn)協(xié)議中的方法
@protocol?NextViewControllerDelegate?
-?(void)passTextValue:(NSString?*)tfText;
@end
@interface?NextViewController?:?UIViewController
@property?(nonatomic,?assign)?id?delegate;
@end
//NextViewController.m?文件
//點(diǎn)擊Button返回前一個(gè)ViewController頁面
-?(IBAction)popBtnClicked:(id)sender?{
if(self.delegate?&&?[self.delegate?respondsToSelector:@selector(passTextValue:)])?{
//self.inputTF是該頁面中的TextField輸入框
[self.delegate?passTextValue:self.inputTF.text];
}
[self.navigationController?popViewControllerAnimated:YES];
}
接下來我們在看看ViewController文件中的內(nèi)容馍资,
//ViewController.m 文件
@interface?ViewController?()
@property?(strong,?nonatomic)?IBOutlet?UILabel?*nextVCInfoLabel;
@end
//點(diǎn)擊Button進(jìn)入下一個(gè)NextViewController頁面
-?(IBAction)btnClicked:(id)sender
{
NextViewController?*nextVC?=?[[NextViewController?alloc]?initWithNibName:@"NextViewController"bundle:nil];
nextVC.delegate?=?self;//設(shè)置代理
[self.navigationController?pushViewController:nextVC?animated:YES];
}
//實(shí)現(xiàn)協(xié)議NextViewControllerDelegate中的方法
#pragma?mark?-?NextViewControllerDelegate?method
-?(void)passTextValue:(NSString?*)tfText
{
//self.nextVCInfoLabel是顯示NextViewController傳遞過來的字符串Label對(duì)象
self.nextVCInfoLabel.text?=?tfText;
}
這是通過“協(xié)議/代理”來實(shí)現(xiàn)的兩個(gè)頁面之間傳值的方式筒主。
(2)第二種方法:使用Block作為property,實(shí)現(xiàn)兩個(gè)頁面之間傳值鸟蟹,
先看看NextViewController文件中的內(nèi)容乌妙,
//NextViewController.h 文件
@interface?NextViewController?:?UIViewController
@property?(nonatomic,?copy)void(^NextViewControllerBlock)(NSString?*tfText);
@end
//NextViewContorller.m?文件
-?(IBAction)popBtnClicked:(id)sender?{
if(self.NextViewControllerBlock)?{
self.NextViewControllerBlock(self.inputTF.text);
}
[self.navigationController?popViewControllerAnimated:YES];
}
再來看看ViewController文件中的內(nèi)容,
- (IBAction)btnClicked:(id)sender
{
NextViewController?*nextVC?=?[[NextViewController?alloc]?initWithNibName:@"NextViewController"bundle:nil];
nextVC.NextViewControllerBlock?=?^(NSString?*tfText){
[self?resetLabel:tfText];
};
[self.navigationController?pushViewController:nextVC?animated:YES];
}
#pragma?mark?-?NextViewControllerBlock?method
-?(void)resetLabel:(NSString?*)textStr
{
self.nextVCInfoLabel.text?=?textStr;
}
- 建钥。-完事兒藤韵,干活兒。