有時我連上網後我會用去amazon找一些書,有時我上網會去看看email,甚至上FB與人聊天,甚至我沒法保證我10天後會用網路作些什麼事,我要如何設計上網功能呢? 才能調性的確保我之後可以作些不一樣的事?! |
我是block程式區塊, 你可以透過我自行定義想要進行的操作, 你可以隨時定義你想作的事, 如此你就不用擔心未來上網後, 不能作你現在沒想到的事了。 |
1. 建立iPad
- 建立iPad類別
iPad.h
#import <Foundation/Foundation.h>
@interface iPad : NSObject
@end
2. 宣告上網後執行的block型別 - doBlock_type
- block其實就是一個函數,只是objective-c用block來表示,當然,功能與應用上加強了非常的多
- 在iPad.h檔中,使用typedef定義block的型別,如同函數分3部份,依順序分成回傳值、名稱、參數,每一部份皆以小括號來組成,回傳值與參數皆是"(void)",表示不回傳值也不傳入值,而中間的小括號中放入名稱doBlock_type,即是這個block型別的名稱
#import <Foundation/Foundation.h>
//定義傳入block型別,
//其實block型別定義的就是型別函數的型別,
//只是在此一個特別的名字block來表示一個函數的區段,
//就好像函數是以程式區段組成的。
//一個block如何函數有3個元素組成,
//回傳值,在此為void,不回傳資料,
//函數名稱,在此以"(^)"表示,在此因使用typedef定義block的型別,
//因此可在"^"之後加上block型別的名稱,即doBlock_type,
//最後的小括號"()"表示傳入的參數,代入void表示無傳入值。
typedef void (^doBlock_type)(void);
@interface iPad : NSObject
@end
3. 宣告接收doBlock_type型別的參數
- 為了讓iPad在連Wifi網路後,可執行使用者自訂的程式,以進行自已要作的事,我們把connectInternetWithWifi方法修改一下,加上doBlock_type型別的參數,以在連接網路上執行使用者自訂的程式
- 更改後的方法為connectInternetWithWifiThenDoBlock:
#import <Foundation/Foundation.h>
//定義傳入block型別,
//其實block型別定義的就是型別函數的型別,
//只是在此一個特別的名字block來表示一個函數的區段,
//就好像函數是以程式區段組成的。
//一個block如何函數有3個元素組成,
//回傳值,在此為void,不回傳資料,
//函數名稱,在此以"(^)"表示,在此因使用typedef定義block的型別,
//因此可在"^"之後加上block型別的名稱,即doBlock_type,
//最後的小括號"()"表示傳入的參數,代入void表示無傳入值。
typedef void (^doBlock_type)(void);
@interface iPad : NSObject
//定義connectInternetWithWifiThenDoBlock方法,
//其中代入doBlock_type型別的block,
//接收block的參數名為block_param,
//記住,block就是一段程式,
//由使用者自行定義此段程式的內容。
-(void) connectInternetWithWifiThenDoBlock: (doBlock_type)block_param;
@end
4. 實作connectInternetWithWifiThenDoBlock:方法
- 實作connectInternetWithWifiThenDoBlock:方法很簡單,就是在連接Wifi網路後,呼叫執行參數所代入的block,以執行使用者自訂在block中的程式
- 呼叫的方法如何呼叫函數一樣,加上小括號"()"代入參數就可以了
- 因doBlock_type型別的block並無需參數,所以加上小括號就"()"可呼叫執行block了
#import "iPad.h"
@implementation iPad
-(void) connectInternetWithWifiThenDoBlock: (doBlock_type)block_param;
{
NSLog(@"透過Wifi連上網路…已連線");
//執行block_param參數代入的block,
//執行的方法就如同呼叫函數一樣,
//加上小括號"()"代入參數即可,
//但…其執行的是什麼內容呢?!
//這就是block的功用,
//讓使用者自行決定要執行的程式,
//在此connectInternetWithWifiThenDoBlock方法的任務很簡單,
//就是連上wifi網路後,
//接著執行block,
//以執行使用者後續想要執行的作業。
block_param();
}
@end
5. 代入block,以在連網後進行不同的作業
- 現在使用者想在連接wifi後,想上網去Amazon、或去收email、或去FB聊天都沒問題,只要使用者在block中定義想要作的事就ok了
- 在傳送connectInternetWithWifiThenDoBlcok:訊息時代入block實體就可在連接wifi後作block中定義的事
- 產生block實體很簡單,只需使用"^{}"並符合doBlock_type型別所定義的函數格式就ok了,,因無參數也參回傳值,因此直接使用"^{}"就可建立block實體
- 當然,因為doBlock_type也是一種型別,因此可作為變數的型別使用
- 在此使用"^{}"建立block實體,其中的程式表示上Amazon買書,並帶入block1變數中,而後在代入connectInternetWithWifiThenDoBlock:訊息中,以在連網後去Amazon買書
- 當然,也可以另建立個block2,在連網後去收email
- 而block並不需要先存在變數中,也可以直接代入至訊息中,在此的第3個範例就是如此,直接上建立block實體後代入至connectInternetWithWifiThenDoBlock:訊息中,在連網後至FB聊天
#import "iPad.h"
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
iPad * pad1 = [[iPad alloc] init];
//建立doBlock_type型別的變數block1,
//透過"^{}"實際建立block的實體,
//在大括號中"{}"即可定義您想要執行的程式,
//在此為上Amazon買書去!
doBlock_type block1 = ^{
NSLog(@"上Amazon買書去!");
};
//現在透過iPad連wifi上網,
//同時在連上網後,
//執行block1中的程式,
//如此就達到上Amazon買書的需求。
[pad1 connectInternetWithWifiThenDoBlock:block1];
//現在想上網後去收email,
//調整block中的內容就ok了!
doBlock_type block2 = ^{
NSLog(@"上網去收email!");
};
[pad1 connectInternetWithWifiThenDoBlock:block2];
//當然block也可以透過"^{}"直接建立block實體後代入,
//只要符合block的型別doBlock_type,
//所定義的回傳值與參數就ok了
[pad1 connectInternetWithWifiThenDoBlock:^{
NSLog(@"上FB找朋友聊天!");
}];
}
return 0;
}
檔案連結:objective_c_block.zip
帶有參數與回傳值的block:
- block即然是函數,那當然也會有回傳值和參數
- 因此我們可以在typedef時,就定義block的格式
- 在下列範例中定義一個帶有參數與回傳值的block型別,如下:
iPad.h
#import <Foundation/Foundation.h>
//宣告一個有回傳值與參數的block型別,
//typedef後接的就是型別,
//在此使用NSString,用以表示block以執行在執行後的結果字串,
//在最後一個小括號中加入BOOL,
//表示會帶入一個BOOL參數,
//在參數用以代入網路是否開啟成功。
typedef NSString* (^doBlock_type)(BOOL);
@interface iPad : NSObject
//定義connectInternetWithWifiThenDoBlock方法,
//其中代入doBlock_type型別的block
-(void) connectInternetWithWifiThenDoBlock: (doBlock_type)block_param;
@end
iPad.m
#import "iPad.h"
@implementation iPad
-(void) connectInternetWithWifiThenDoBlock: (doBlock_type)block_param;
{
NSLog(@"透過Wifi連上網路…已連線");
//代入YES,表示網路開啟成功
//並使用resultString變數接收執行結果的字串
NSString * resultString = block_param(YES);
NSLog(@"執行完畢:%@", resultString);
}
@end
main.m
#import <Foundation/Foundation.h>
#import "iPad.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
//使用"^{}"建立doBlock_type型別的block實體,
//因doBlock_type定義block需代有一個參數,
//因此在^後加上小括號,其中帶入一個BOOL參數,
//此參數在此範例表示是否網路已開啟,
//而因doBlock_type型別有定義NSString型別的回傳值,
//因此,程式中需使用return將資料回傳
doBlock_type block1 = ^(BOOL isInternetOpened){
if(isInternetOpened == YES)
{
NSLog(@"上FB聊天真開心!");
return @"上FB聊天完畢!";
}
else
{
return @"很傷心,無法上網聊FB...";
}
};
iPad * pad1 = [[iPad alloc] init];
[pad1 connectInternetWithWifiThenDoBlock:block1];
}
return 0;
}
多個參數的block:
- 當然,block也可以帶入多個參數,如同函數一樣,如下:
#import <Foundation/Foundation.h>
//宣告帶有多個參數的block型別,
//在最後一個小括號中,
//只要定義參數的型別與個數,
//每個參數以逗號","隔開即可。
typedef NSString* (^doBlock_type)(BOOL, NSString*, NSInteger);
定義匿名的block型別:
- block其實是可以不用透過typedef事先定義block的型別的
- 當然,最大不同的地方是,宣告匿名block的格式,而匿名的意思是這個block型別不需要名字,只有宣告block的格式,如下:
iPad.h
#import <Foundation/Foundation.h>
@interface iPad : NSObject
//直接在參數的型別上定義block的格式,
//特別的是這個匿名block型別沒有名稱,
//因此第2個小括號中僅有一個"^"即(^),
//在此匿名block的格式,
//回傳值為void
//(^)沒有block型別沒有名字,
//(void)沒有任何參數
-(void) connectInternetWithWifiThenDoBlock: (void(^)(void))block_param;
@end
更多block的應用: