❶ block調用時變數的生命周期有哪幾種
Block內存來管理的規則:
源1,Block指針會在方法或函數結束後release掉,此時內存是儲存在Stack里。
2,如果要在保存Block指針,需要用到方法(類似於NSObject),此時內存儲存在Heap里。
3,Block函數體里的變數會被自動Retain,等Block結束掉後會Release。
4,__block 前綴標明的變數,不會自動Reatin。
Block Copy時的注意事項:
1,在block里如果直接操作self,則self會自動retain。
2,在block里如果操作類變數,則變數所屬的類會自動retain
❷ block的嵌套調用方式,2個block怎麼相互嵌套
Block 變數擁有 blocks 的引用。你可以使用和聲明函數指針類似的語法來聲明它 們,除了它們使用^修飾符來替代 * 修飾符。Block 類型可以完全操作其他 C 系統 類型。以下都是合法的 block 聲明:
void (^)(void);
int (^)(int, char);
void (^[10])(int);
Blocks 還支持可變參數(...)。一個沒有使用任何參數的 block 必須在參數列表 上面用 void 標明。
Blocks 被設計為類型安全的,它通過給編譯器完整的元數據來合法使用 blocks、 傳遞到 blocks 的參數和分配的返回值。你可以把一個 block 引用強制轉換為任意類型 的指針,反之亦然。但是你不能通過修飾符 * 來解引用一個 block,因此一個 block 的大小是無法在編譯的時候計算的。
你同樣可以創建 blocks 的類型。當你在多個地方使用同一個給定的簽名的 block 時,這通常被認為是最佳的辦法。
typedef float (^MyBlockType)(float, float);
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;
3.2 創建一個block
你可以使用 ^ 修飾符來標識一個 block 表達式的開始。它通常後面跟著一個被 () 包含起來的參數列表。Block 的主體一般被包含在 {} 裡面。下面的示例定義了一個 簡單的 block,並把它賦值給前面聲明的變數(oneFrom)。這里 block 使用一個標准 C 的結束符 ; 來結束。
int (^oneFrom)(int);
oneFrom = ^(int anInt) {
return anInt - 1;
};
如果你沒有顯式的給 block 表達式聲明一個返回值,它會自動的從 block 內容推 斷出來。如果返回值是推斷的,而且參數列表也是 void,那麼你同樣可以省略參數列 表的 void。如果或者當出現多個返回狀態的時候,它們必須是完全匹配的(如果有必 要可以使用強制轉換)。
3.3 全局blocks
在文件級別,你可以把 block 作為全局標示符:
#import
int GlobalInt = 0;
int (^getGlobalInt)(void) = ^{ return GlobalInt; };
第四章 Blocks和變數
本文描述 blocks 和變數之間的交互,包括內存管理。
你可以引用三種標准類型的變數,就像你在函數裡面引用那樣:
全局變數,包括靜態局部變數。
全局函數(在技術上而言這不是變數)。
封閉范圍內的局部變數和參數。
Blocks 同樣支持其他兩種類型的變數:
在函數級別是__block變數。這些在block裡面是可變的(和封閉范圍),並任何引
用 block 的都被保存一份副本到堆裡面。
引入const。
最後,在實現方法裡面,blocks也許會引用Objective-C的實例變數。參閱「對象
和 Block 變數」部分。
在 block 裡面使用變數遵循以下規則:
全局變數可訪問,包括在相同作用域范圍內的靜態變數。
傳遞給block的參數可訪問(和函數的參數一樣)。
程序裡面屬於同一作用域范圍的堆(非靜態的)變數作為const變數(即只讀)。
它們的值在程序裡面的 block 表達式內使用。在嵌套 block 裡面,該值在最近的
封閉范圍內被捕獲。
屬於同一作用域范圍內並被__block存儲修飾符標識的變數作為引用傳遞因此是
可變的。
屬於同一作用域范圍內block的變數,就和函數的局部變數操作一樣。
每次調用 block 都提供了變數的一個拷貝。這些變數可以作為 const 來使用,或在 block 封閉范圍內作為引用變數。
下面的例子演示了使用本地非靜態變數:
int x = 123;
void (^printXAndY)(int) = ^(int y) {
printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 123 456
正如上面提到的,在 block 內試圖給 x 賦一個新值會導致錯誤發生:
int x = 123;
void (^printXAndY)(int) = ^(int y) {
x = x + y; // error
printf("%d %d\n", x, y);
};
為了可以在 block 內修改一個變數,你需要使用__block 存儲類型修飾符來標識該 變數。參閱「__block 存儲類型」部分。
4.2 __block存儲類型
你可以指定引入一個變數為可更改的,即讀-寫的,通過應用__block 存儲類型修 飾符。局部變數的__block 的存儲和 register、auto、static 等存儲類型相似,但它們之 間不兼容。
__block 變數保存在變數共享的作用域范圍內,所有的 blocks 和 block 副本都聲明 或創建在和變數的作用域相同范圍內。所以,如果任何 blocks 副本聲明在棧內並未超 出棧的結束時,該存儲會讓棧幀免於被破壞(比如封裝為以後執行)。同一作用域范 圍內給定的多個 block 可以同時使用一個共享變數。
作為一種優化,block存儲在棧上面,就像blocks本身一樣。如果使用Block_ 拷貝了 block 的一個副本(或者在 Objective-C 裡面給 block 發送了一條 消息), 變數會被拷貝到堆上面。所以一個__block 變數的地址可以隨時間推移而被更改。
使用__block 的變數有兩個限制:它們不能是可變長的數組,並且它們不能是包 含有 C99 可變長度的數組變數的數據結構。
以下舉例說明了如何使用__block 變數:
__block int x = 123; // x lives in block storage
void (^printXAndY)(int) = ^(int y) {
x = x + y;
printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 579 456
// x is now 579
下面的例子顯示了 blocks 和其他幾個類型變數間的交互:
extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void) {
++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block creation
localCharacter = 'a'; // sets localCharacter in enclosing scope
};
++localCounter; // unseen by the block
localCharacter = 'b';
aBlock(); // execute the block
// localCharacter now 'a'
}
4.3 對象(Object)和Block變數
Block 提供了支持 Objective-C 和 Objective-C++的對象,和其他 blocks 的變數。
4.3.1 Objective-C對象
在引用計數的環境裡面,默認情況下當你在 block 裡面引用一個 Objective-C 對象的時 候,該對象會被retain。當你簡單的引用了一個對象的實例變數時,它同樣被 retain。 但是被__block 存儲類型修飾符標記的對象變數不會被 retain. 注意:在垃圾回收機制裡面,如果你同時使用__weak 和__block 來標識一個變數,那麼該 block 將不會保證它是一直是有效的。
如果你在實現方法的時候使用了 block,對象的內存管理規則更微妙:
如果你通過引用來訪問一個實例變數,self 會被 retain。
如果你通過值來訪問一個實例變數,那麼變數會被 retain。
下面舉例說明兩個方式的不同:
dispatch_async(queue, ^{
// instanceVariable is used by reference, self is retained
doSomethingWithObject(instanceVariable);
});
id localVariable = instanceVariable;
dispatch_async(queue, ^{
// localVariable is used by value, localVariable is retained (not self)
doSomethingWithObject(localVariable);
4.3.2 C++對象
通常你可以在 block 內使用 C++的對象。在成員函數裡面,通過隱式的導入 this 指針引用成員變數和函數,結果會很微妙。有兩個條件可以讓 block 被拷貝:
如果你擁有__block存儲的類,它本來是一個基於棧的C++對象,那麼通常會使用 的構造函數。
如果你在 block 裡面使用任何其他 C++基於棧的對象,它必須包含一個 const 的構造函數。該 C++對象使用該構造函數來拷貝。
4.3.3 Blocks
當你拷貝一個 block 時,任何在該 block 裡面對其他 blocks 的引用都會在需要的 時候被拷貝,即拷貝整個目錄樹(從頂部開始)。如果你有 block 變數並在該 block 里 面引用其他的 block,那麼那個其他的 block 會被拷貝一份。
當你拷貝一個基於棧的 block 時,你會獲得一個新的 block。但是如果你拷貝一個 基於堆的 block,你只是簡單的遞增了該 block 的引用數,並把原始的 block 作為函數 或方法的返回值。
五章 使用Blocks
5.1 調用一個Block
如果你聲明了一個 block 作為變數,你可以把它作為一個函數來使用,如下面的
兩個例子所示:
int (^oneFrom)(int) = ^(int anInt) {
return anInt - 1;
};
printf("1 from 10 is %d", oneFrom(10));
// Prints "1 from 10 is 9"
float (^distanceTraveled) (float, float, float) =
^(float startingSpeed, float acceleration, float time) {
float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
return distance;
};
float howFar = distanceTraveled(0.0, 9.8, 1.0);
// howFar = 4.9
然而你通常會把 block 作為參數傳遞給一個函數或方法。在這種情況下,你通過 需要創建一個」內聯(inline)」的 block。
5.2 使用Block作為函數的參數
你可以把一個 block 作為函數的參數就像其他任何參數那樣。然而在很多情況下, 你不需要聲明blocks;相反你只要簡單在需要它們作為參數的地方內聯實現它們。下 面的例子使用 qsort_b 函數。qsort_b 和標准 qsort_r 函數類似,但是它最後一個參數用 block.
char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine"};
qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, constvoid *r) {
char *left = *(char **)l;
char *right = *(char **)r;
return strncmp(left, right, 1);
});
// Block implementation ends at "}"
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
注意函數參數列表包含了一個 block。
下一個例子顯示了如何在 dispatch_apply 函數裡面使用 block。dispatch_apply 聲明 如下:
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void(^block)(size_t));
該函數提交一個 block 給批處理隊列來多次調用。它需要三個參數;第一個指定 迭代器的數量;第二個指定一個要提交 block 的隊列;第三個是 block 它本身,它自 己需要一個參數(當前迭代器的下標)。
你可以使用 dispatch_apply 來簡單的列印出迭代器的下標,如下:
#include
size_t count = 10;
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(count, queue, ^(size_t i) {
printf("%u\n", i);
});
5.3 使用Block作為方法的參數
Cocoa 提供了一系列使用 block 的方法。你可以把一個 block 作為方法的參數就像 其他參數那樣。
下面的例子確定數組前面五個元素中第一個出現在給定的過濾器集中任何一個 的下標。
NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C", @"A",@"B", @"Z",@"G", @"are", @"Q", nil];
NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);
test = ^ (id obj, NSUInteger idx, BOOL *stop) {
if (idx < 5) {
if ([filterSet containsObject: obj]) {
return YES;
}
}
return NO;
};
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];
NSLog(@"indexes: %@", indexes);
下面的例子確定一個 NSSet 是否包含一個由局部變數指定的單詞,並且如果條件 成立把另外一個局部變數(found)設置為 YES(並停止搜索)。注意到 found 同時被聲 明為__block 變數,並且該 block 是內聯定義的:
__block BOOL found = NO;
NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma",@"X", nil];
NSString *string = @"gamma";
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
if ([obj :string] == NSOrderedSame) {
*stop = YES;
found = YES;
}
}];
// At this point, found == YES
5.4 拷貝Blocks
通常,你不需要 (或 retain)一個 block.在你希望 block 在它被聲明的作用域 被銷毀後繼續使用的話,你子需要做一份拷貝。拷貝會把 block 移到堆裡面。
你可以使用 C 函數來 和 release 一個 block:
Block_();
Block_release();
如果你使用 Objective-C,你可以給一個 block 發送 、retain 和 release(或 autorelease)消息。
為了避免內存泄露,你必須總是平衡 Block_()和 Block_release()。你必須平衡 或 retain 和release(或 autorelease)--除非是在垃圾回收的環境裡面。
5.5 需要避免的模式
一個 block 的文本(通常是^{...})是一個代表 block 的本地棧數據結構地址。 因此該本地棧數據結構的作用范圍是封閉的復合狀態,所以你應該避免下面例子顯示 的模式:
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// WRONG: The block literal scope is the "for" loop
}
}
void dontDoThisEither() {
void (^block)(void);
int i = random():
if (i > 1000) {
block = ^{ printf("got i at: %d\n", i); };
// WRONG: The block literal scope is the "then" clause
}
// ...
}
5.6 調試
你可以在 blocks 裡面設置斷點並單步調試。你可以在一個 GDB 的對話裡面使用
invoke-block 來調用一個 block。如下面的例子所示:
$ invoke-block myBlock 10 20
如果你想傳遞一個 C 字元串,你必須用引號括這它。例如,為了傳遞 this string 給doSomethingWithString 的 block,你可以類似下面這樣寫:
$ invoke-block doSomethingWithString ""this string""
結束語
Block 是 iOS 4.0 之後添加的新特性支持。本人親測感覺使用 Block 最大的便利就 是簡化的回調過程。以前使用 UIView 的動畫,進程要控制動畫結束後進行相應的處 理。iOS 4.0 之後,UIView 新增了對 Block 的支持,現在只要使用簡單的一個 Block 代碼就可以在寫動畫的代碼部分直接添加動畫結束後的操作。還有就是在使用Notification 時候 Block 也非常有幫助。反正多用就可以體會到 Block的優美了。
對了,使用 Block 要謹記別造成對象互相引用對方導致引用計數進入一個循環導 致對象無法被釋放。iOS 5.0 之後的 ARC 也是無法解決該潛在的互相引用的問題的。 所以寫 Block 的時候要注意這點。因為 Block 往往在後台自動對一些它引用了的對象 進行 retain 操作。具體形式這里就不距離了,大家在使用的時候多體會一下。
❸ ios 類方法block怎麼回調函數
其實,iOS中的Block就是C++中的函數指針,實現方式都是一樣的,下面貼出一個簡單的實踐。
首先,創建一個回調的類
BlockStudy.h
//
// BlockStudy.m
// BlockStudy
//
// Created by 杜甲 on 11/11/14.
// Copyright (c) 2014 杜甲. All rights reserved.
//
#import "BlockStudy.h"
@implementation BlockStudy
- (void)test
{
if (_testBlock) {
_testBlock();
}
}
- (void)StartBlock
{
[self performSelector:@selector(test) withObject:nil afterDelay:2.0];
}
@end
調用類ViewController.m
//
// ViewController.m
// BlockStudy
//
// Created by 杜甲 on 11/11/14.
// Copyright (c) 2014 杜甲. All rights reserved.
//
#import "ViewController.h"
#import "BlockStudy.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
BlockStudy *block = [[BlockStudy alloc] init];
block.testBlock = ^()
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Block學習" message:@"測試成功" delegate:self cancelButtonTitle:@"取消吧" otherButtonTitles:@"OK", nil];
[alert show];
};
[block StartBlock];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
❹ ios block回調在哪個線程
block 返回之前在哪個線程 返回過後還是在哪個線程 沒有線程的跳轉
❺ iOS回調傳值之block和delegate的區別
首先兩者作用都進行單調
通delegate象用象自調用代理協議函數完整流程
block傳遞函數指針利用函數指針執行進行調
內存管理需要注意delegate需要保存引用block引用數據處理
❻ 網路層的回調為什麼不建議使用Block
1.block很難追蹤,難以維護
我們在調試的時候經常會單步追蹤到某一個地方之後,發現版尼瑪這里有個block,如果想權知道這個block裡面都做了些什麼事情,這時候就比較蛋疼了。
2.block會延長相關對象的生命周期
block會給內部所有的對象引用計數加一,這一方面會帶來潛在的retain cycle,不過我們可以通過Weak Self的手段解決。另一方面比較重要就是,它會延長對象的生命周期。
在網路回調中使用block,是block導致對象生命周期被延長的其中一個場合,當ViewController從window中卸下時,如果尚有請求帶著block在外面飛,然後block裡面引用了ViewController(這種場合非常常見),那麼ViewController是不能被及時回收的,即便你已經取消了請求,那也還是必須得等到請求著陸之後才能被回收。
然而使用delegate就不會有這樣的問題,delegate是弱引用,哪怕請求仍然在外面飛,,ViewController還是能夠及時被回收的,回收之後指針自動被置為了nil,無傷大雅。
❼ block的嵌套調用方式,2個block怎麼相互嵌套
Block 變數擁有 blocks 的引用。你可以使用和聲明函數指針類似的語法來聲明它 們,除了它們使用^修飾專符來替代 * 修飾符。屬Block 類型可以完全操作其他 C 系統 類型。以下都是合法的 block 聲明: void (^)(void)...
❽ 網路請求中的block成功回調是怎麼回調的 求代碼
main()
{
int a,b,c;
a=5; b=6; c=7;
printf(「 ab c\tde\rf\n」);
printf(「hijk\tL\bM\n」);
}
3.5.3 字元變數
字元變數用來存儲字元常量,即單個字元。內
字元變數的類型說明符是容char。字元變數類型定義的格式和書寫規則都與整型變數相同。例如:
char a,b;
3.5.4 字元數據在內存中的存儲形式及使用方法
每個字元變數被分配一個位元組的內存空間,因此只能存放一個字元。字元值是以ASCII碼的形式存放在變數的內存單元之中的。
如x的十進制ASCII碼是120,y的十進制ASCII碼是121。
❾ CAD:用BLOCK命令建立的圖塊,只能插入到生成它的圖形文件中嗎
1、使用BLOCK做的塊是保存在當前圖紙當中,如果在其他圖紙中想調用這個塊回,可以打開設答計中心(ADC),在文件夾列表中找到之前的圖紙,然後點圖紙名前面的「+」號,雙擊塊,即可顯示該圖紙中所有的塊,在右側找到需要的塊,然後滑鼠左鍵點在塊上,安裝滑鼠左鍵不松,拖動到繪圖區域,然後按命令行提示,輸入插入比例即可。
❿ block+Gcd 非同步請求 在block回調里 刷新UI 為什麼實現不了
您好,很高興能幫抄助您
原因是我在 .h文件中聲明 block 變數時
@property(nomaric,assign) 定義的block類型 變數名;
中你可以看到我用了 assign,導致我在調用的 可能已經被釋放掉。
你可以查查 在使用block 做屬性申明時 ,。最好使用 但使用retain 也是可以的。。
希望能幫到你