iOS - block語法塊

block語法塊,相似於方法,分爲無返回值無參數,有返回值有參數,有返回值無參數,有返回值有參數。block的聲明,block的調用。block總體做爲屬性,block總體做爲函數中的參數的使用。 html


把block當作一個變量,這個變量的實質相似一個方法,表明的一些操做。 數組

總結自 async

 http://www.cnblogs.com/jy578154186/archive/2012/09/30/2709130.html 以及一些本身的理解 函數


一。最簡單的使用 spa

//block最簡單的  左邊聲明,右邊實現,block能夠做爲變量,此種狀況下可把block當作函數般調用,使用時可直接調用block函數,有返回值時可輸出 代理

// 直接使用block   並不須要將block爲聲明爲變量,能夠直接在須要使用block的地方直接用內嵌的方式將block的內容寫出來,寫的是block的實現部分  須要block參數的方法就能夠在傳block類型的參數時直接寫實現 htm

// __block變量  通常來講,block內只能讀取在同一做用域的變量並且沒有辦法修改在block外定義的任何變量,此時若想要這些變量可以在block中被修改,就必須在前面掛上__block變量的修飾詞。 對象


// __block int mul = 9; blog

// int(^myBlock)(int) = ^(int num) { 索引

// if (num < 0) {

// return mul;

// } else {

// mul = num;

// }

// return num;

// };

//

// NSLog(@"\n%d mul = %d", myBlock(-4), mul);

// NSLog(@"\n%d mul = %d", myBlock(4), mul);


二。block的使用時機

 block的使用時機   block通常是用來表示、簡化一小段的程序代碼,它特別適合用來創建一些同步執行的代碼片斷、封裝一些小型的工做或是用來作爲某一個工做完成時的回傳呼叫(callback)。 block被大量用來取代傳統的delegatecallback,而新的iOS API會大量使用block主要是基於如下倆個緣由:

1.能夠在程序代碼中撰寫等會要接着執行的程式,直接將程式碼變爲函數的參數傳入函數中,這是新API最常使用block的地方。就相似協議傳參數,而後到必定條件讓代理人幹什麼活,乾的活寫在了協議實現裏,block把乾的活直接寫在作爲參數的block裏。真正這個block裏的代碼或者協議實現裏的代碼什麼時候觸發,這是同一個問題,同時這又是另外一個問題了。哪裏觸發,哪裏天然會調用的。若是用協議寫,調用block的地方,就是讓delegate調用協議方法的地方。用block省了delegate的設置和協議方法的聲明,用block比協議代碼乾淨的多。這樣就有問題了,blockdelegate功能上有區別嗎?好比有隻有block能夠實現,delegate幹不了的嗎?或者反過來幹不了的。

2.能夠存取區域變量(贊成個{}裏面的變量),在傳統的callback實做時,若想要存取區域變量得將變量封裝成結構才能使用,而block則是能夠很方便地直接存取區域變量。   不太懂,有個例子多好


三。全域的block

示例:

int GloabalInt = 0;

int (^getGloabalInt)(void) = ^(void) {return GloabalInt;};

 

能夠把上面倆行代碼寫到@implementation的上面,可使用下面的調用看一下效果

NSLog(@"%@\n%d", getGloabalInt, getGloabalInt()) ;


四。block和變量

4.1

// 能夠在block中遇到日常在函數中會遇到的變量類型:全域(global)變量或是靜態的區域變數(static local), 全域的函數, 區域變量和由封閉領域(enclosing scope)傳入的參數。除了上述以外block額外支援了另外倆種變量:(1)在函數內可使用__block變量, 這些變量在block中是可被修改的(2)匯入常數(const imports),個人理解就是常量

//下面的規則能夠套用到在block中變量的使用:能夠存取全域變量和在同一領域(enclosing lexical scope)中的靜態變量,能夠存取傳入block的參數(使用方式和傳入函數的參數相同),在同一領域的區域變數在block中將視爲常量(const),能夠存取在同一領域中以__block 爲修飾詞的變量,在block中聲明的區域變量,使用方式和日常函數使用區域變數的方式相同

// __block 型態變量

// 咱們能夠藉由將一個由外部匯入block的變量放上修飾詞__block來讓這個變量由惟讀變成能夠讀和寫,不過有一個限制就是傳入的變量在記憶體中必須是一個佔有固定長度記憶體的變量,__block修飾詞沒法使用於像是變更長度的陣列(數組)這類不定長度的變量{ 下面咱們使用一個範例來介紹各種型的變數和block之間的互動:

下面這倆行代碼寫到@interface的上方,(extern和static修飾符的意思:extern是擴展的意思,表示後面的變量在別的類中已定義,直接使用別的類中的該變量,static表示該變量只初始化一次,始終保持上一次的值。全局的靜態變量,表示它的使用範圍i是整個類均可用,但外部是不可用的,即便寫到.h中,外部也不可用,這是OC的特殊處,要用,能夠寫類方法返回該變量的值。外部能夠調用類方法訪問。)

extern NSInteger CounterGlobal;(這個變量必須在其餘類中定義且聲明)

static NSInteger CounterStatic;

把下面這段代碼寫到viewdidload裏

 NSLog(@"wai%ld", (long)CounterStatic);

  NSLog(@"wai%ld", (long)CounterGlobal);

 

  NSInteger localCounter = 42;

__block char localCharacter;

void (^aBlock)(void) = ^(void) {

++CounterGlobal;//能夠存取。 外部的全局變量

++CounterStatic;//能夠存取。 全局靜態變量

NSLog(@"%ld", (long)CounterStatic);

NSLog(@"%ld", (long)CounterGlobal);

 

CounterGlobal = localCounter;//localCounter在block 創建時就不可變了

NSLog(@"%ld", (long)CounterGlobal);

 

localCharacter = 'a';//設定外面定義的localCharacter 變數。

};

++localCharacter;//不會影響的block 中的值

localCharacter = 'b';

aBlock();//執行block 的內容。

// 執行完後,localCharachter 會變成'a'


4.2關於block裏的變量和引用計數(我沒理解了,可能還沒遇到過吧,先寫上,之後遇到再說)

// 在擁有引用計數(reference-counted)的環境中,若咱們在block中用到Objective-C的對象,在通常的狀況下它將會自動增長對象的引用計數,不過若以__block爲修飾詞的對象,引用計數則是不受影響。若是咱們在Objective-C的方法中使用block時,如下幾個和記憶體管理的事是須要額外注意的: 若直接存取實體變量(instance variable),self的引用計數將被加1。若透過變數存取實體變數的值,則只變量的引用計數將被加1。如下程式碼說明上面兩種狀況,在這個假設instanceVariable是實體變數:

// dispatch_async (queue, ^{

// // 由於直接存取實體變數instanceVariable ,因此self 的retain count 會加1

// doSomethingWithObject (instanceVariable);

//     });

// id localVaribale = instanceVariable;

// dispatch_async (queue, ^{

// //localVariable 是存取值,因此這時只有localVariable 的retain count 加1

// //self 的 return count  並不會增長。

// doSomethingWithObject (localVaribale);

//      });

五。block的使用

block聲明成一個變量時,咱們能夠像使用通常函數的方式來使用它,其實就是直接調用block,傳遞須要的參數便可。

 在通常常見的狀況中,如果將block當作是參數傳入函數,咱們一般會使用內嵌的方式來使用block

 1.將block當作函數的參數。咱們能夠像通常函數使用參數的方式,將block以函數參數的形式傳入函數中,在這種狀況下,大多數咱們使用block的方式將不是傾向於聲明block而是直接之內嵌的方式來將block傳入,這也是目前新版sdk中主流的作法

2.將block當作方法的參數 在SDK中提供了許多使用block的方法,咱們能夠像傳遞通常參數的方式來傳遞block,下面這個範例示範瞭如何在一個數組的前5筆數據中取出咱們想要的數據的索引值:

//全部的數據

NSArray *array = [NSArray arrayWithObjects: @"A" , @"B" , @"C" , @"A" , @"B" , @"Z" , @"G" , @"are" , @" Q" ,nil];

// 咱們只要這個集合內的數據

NSSet *filterSet = [NSSet setWithObjects:@"A", @"B", @"Z", @"Q", nil];

BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);

    test =  ^(id obj, NSUInteger idx, BOOL *stop) {

//只對前5筆數據作檢查

if (idx < 5) {

if ([filterSet containsObject:obj]) {

    return YES;

}

}

return NO;

};

// [array indexesOfObjectsPassingTest:<#^BOOL(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)predicate#>]

NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];

NSLog(@"indexex: %@", indexes);

// 結果:indexex: <NSIndexSet: 0x7fa960510b30>[number of indexes: 4 (in 2 ranges), indexes: (0-1 3-4)]

//前5筆數據中,有4逼符合條件,它們的索引值分別是0-1 3-4

五。該避免的使用方式

總結一句話:注意block的有效範圍,在無效範圍內就不要調用了。

關於靜態變量和static後面會有一個博客專門說這個的。

程序的存儲,堆區,棧區,靜態區,代碼區,分別存放什麼,搞明白了
相關文章
相關標籤/搜索