標籤:系統 c語言 二進位 pop 靜態變數 __weak 結束 font ios
Block是C語言的擴充功能。帶有自動變數(局部變數)的匿名函數。(不帶有名稱的函數)
非匿名函數:int func(int count);(聲明了名稱為func的函數)使用:int result =func(10);
匿名函數:
Block文法:
- ^傳回值類型 參數列表 運算式
- ^int ( int count) { return count+1};
- 省略傳回值:
- ^ ( int count) { return count+1};
- 省略傳回值和參數列表:
- ^ () { return count+1};或者^{ printf(“1223”);}
- 將Block賦值為Block類型變數:
傳回值類型(^塊名)(參數類型)=^參數列表 運算式
Int (^blk) (int) =^(int count){return count+1;};
按照調用函數的方式調用塊物件變數就可以了:
int result = myBlock(4); // result是 28
- 在函數參數和傳回值中使用block
- 函數參數:void func(int (^blk) (int) ){
}
Return ^ (int count) { return count+1}
}
2.使用typedef簡化(定義別名)
定義: typedef int (^blk_t)(int);
- 原本:void func(int (^blk) (int) ){
- 簡化:void func(blk_t blk)
- 原本:int(^func())(int){
- 簡化:blk_t func()
原本:typedef int (^MyBlock)(int, int);
int (^minusBlock) (int, int) = ^(int a, int b){
return a - b;
};
int (^multiBlock) (int, int) = ^(int a, int b){
return a * b;
};
下面的代碼更簡潔
MyBlock minusBlock = ^(int a, int b){
return a - b;
};
MyBlock multiBlock = ^(int a, int b){
return a * b;
};
- (1)在類中,定義一個Block變數,就像定義一個函數;
- (2)Block可以定義在方法內部,也可以定義在方法外部;
- (3)只有調用Block時候,才會執行其{}體內的代碼;
Block的幾個特性:
- 自動變數值的截獲
Int dmy=256;
Int val=10;
Const char *fmt=”val=%d\n”;
Void(^blk)(void)=^printf(fmt,val);};
Val=2;
Fmt=”these values were changed. Val=%d\n”;
blk();
Return 0;
}
輸出結果:val=10;
2.修改外部變數(加_block說明符)
//將Block定義在方法內部
int x = 100;
void (^sumXAndYBlock)(int) = ^(int y){
x = x+y;
printf("new x value is %d",x);
};
sumXAndYBlock(50);
出現編譯錯誤:error: Variable is not assigning (missing __block type)
這時候給int x = 100;語句前面加上__block關鍵字即可
__block int x = 100;
這樣在Block的{}體內,就可以修改外部變數了。
Block儲存域:
程式佔用記憶體分布的結構:
棧區(stack):由系統自動分配,一般存放函數參數值、局部變數的值等。由編譯器自動建立與釋放。其操作方式類似於資料結構中的棧,即後進先出、先進後出的原則。
堆區(heap):一般由程式員申請並指明大小,最終也由程式員釋放。如果程式員不釋放,程式結束時可能會由OS回收。
全域區/靜態區:顧名思義,全域變數和靜態變數儲存在這個地區。只不過初始化的全域變數和靜態變數儲存在一塊,未初始化的全域變數和靜態變數儲存在一塊。程式結束後由系統釋放。
文字常量區:這個地區主要儲存字串常量。程式結束後由系統釋放。
程式碼區:這個地區主要存放函數體的二進位代碼
int a = 0; // 全域初始化區
char *p1; // 全域未初始化區
main {
int b; // 棧
char s[] = "abc"; // 棧
char *p2; // 棧
char *p3 = "123456"; // 123456\0在常量區,p3在棧上
static int c =0; // 全域靜態初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); // 分配得來的10和20位元組的地區就在堆區
strcpy(p1, "123456"); // 123456\0在常量區,這個函數的作用是將"123456" 這串字串複製一份放在p1申請的10個位元組的堆地區中。
// p3指向的"123456"與這裡的"123456"可能會被編譯器最佳化成一個地址。
Block的使用:
1.Block傳值
將B介面的textField.text傳給A介面的Label
A頁面:RootViewControllers B頁面:DetailViewControllers
B頁面:DetailViewController檔案
#import <UIKit/Uikit.h>
typedef void (^DetailBlock)(NSString *);//block取別名。並且在參數列表中將需要傳遞的參數寫形參
@interface DetailViewController : UIViewController
@property (nonatomic, copy) PassingValueBlock passingvalue;//設定block屬性(注意使用copy)
@property (weak, nonatomic) UITextField *inputTF;
@end
- (IBAction)BtnAction:(id)sender {
//判斷block是否為空白
if (self. passingvalue) {
self. passingvalue (self.inputTF.text);
}
[self.navigationController popViewControllerAnimated:YES];
}//點擊按鈕到A介面
RootViewController.m
@property (strong, nonatomic) UILabel *textLabel;
-(void)handleButton: (NSString*)sender{
DetailViewController *detailViewController = [[DetailViewController alloc]init];
detailViewController.passingValue=^( NSString* str){
self. textLabel.text= str;}
[self.navigationController pushViewController:detailViewController animated:YES];
}
2.Block避免循環參考
由於我們很多行為會導致Block的copy,而當Block被copy時,會對block中用到的對象產生強引用(ARC下)或者引用計數加一(non-ARC下)。
如果遇到這種情況:
@property(nonatomic, readwrite, copy) completionBlock completionBlock;
self.completionBlock = ^ {
if (self.success) {
self.success(self.responseData);
}
}
};
對象有一個Block屬性,然而這個Block屬性中又引用了對象的其他成員變數,那麼就會對這個變數本身產生強應用,那麼變數本身和他自己的Block屬性就形成了循環參考。在ARC下需要修改成這樣:
@property(nonatomic, readwrite, copy) completionBlock completionBlock;
__weak typeof(self) weakSelf = self;
self.completionBlock = ^ {
if (weakSelf.success) {
weakSelf.success(weakSelf.responseData);
}
};
注1:iOS4.3之前版本就用__unsafe_unretained替代__weak
注2:如果是non-ARC環境下就將__weak替換為__block即可
iOS學習之block