iOS - block - 序

[toc]

參考

block

https://blog.csdn.net/u014600626/article/details/78697535

http://www.cocoachina.com/cms/wap.php?action=article&id=23147

http://www.reibang.com/p/d96d27819679

block 簡(jiǎn)介

block 是能夠捕獲外部變量的匿名函數(shù), 在 iOS4 中引入, 是對(duì)C語(yǔ)言的擴(kuò)充, C語(yǔ)言本身不存在這樣的匿名函數(shù)决帖。

block 本質(zhì)

block 本質(zhì)上是封裝了 函數(shù)調(diào)用(函數(shù)指針) 以及 函數(shù)調(diào)用環(huán)境(捕獲到的參數(shù)) 的 OC對(duì)象呛伴。既然是OC對(duì)象, 那就是一個(gè)內(nèi)部有isa指針的結(jié)構(gòu)體。

block 屬性策略

MRC下block屬性的建議寫法

@property (copy, nonatomic) void (^block)(void);

ARC下block屬性的建議寫法

@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);

代碼存放在堆區(qū)時(shí), 就需要特別注意, 因?yàn)槎褏^(qū)不像代碼區(qū)不變化, 堆區(qū)是不斷變化的(不斷創(chuàng)建銷毀)。因此當(dāng)沒有強(qiáng)指針指向時(shí), 代碼有可能會(huì)被銷毀, 如果這時(shí)再訪問(wèn)此段代碼則會(huì)程序崩潰向拆。
因此, 對(duì)于這種情況, 我們?cè)诙x一個(gè)block屬性時(shí)應(yīng)指定為strong, 或copy:

@property (nonatomic, strong) void (^myBlock)(void); // 這樣就有強(qiáng)指針指向它
@property (nonatomic, copy)  void (^myBlock)(void); 

block 相關(guān)源碼

Block.h
BLOCK_EXPORT void *_Block_copy(const void *aBlock);

BLOCK_EXPORT void _Block_release(const void *aBlock);

#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))

#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
Block_private.h
// (非完整)
enum {
    /* See function implementation for a more complete description of these fields and combinations */
    BLOCK_FIELD_IS_OBJECT   =  3,  /* id, NSObject, __attribute__((NSObject)), block, ... */
    BLOCK_FIELD_IS_BLOCK    =  7,  /* a block variable */
    BLOCK_FIELD_IS_BYREF    =  8,  /* the on stack structure holding the __block variable */
    BLOCK_FIELD_IS_WEAK     = 16,  /* declared __weak, only used in byref copy helpers */
    BLOCK_BYREF_CALLER      = 128  /* called from __block (byref) copy/dispose support routines. */
};

/* Runtime entry point called by compiler when assigning objects inside copy helper routines */
BLOCK_EXPORT void _Block_object_assign(void *destAddr, const void *object, const int flags);
    /* BLOCK_FIELD_IS_BYREF is only used from within block copy helpers */

/* runtime entry point called by the compiler when disposing of objects inside dispose helper routine */
BLOCK_EXPORT void _Block_object_dispose(const void *object, const int flags);
runtime.c
/* Copy, or bump refcount, of a block.  If really copying, call the copy helper if present. */
static void *_Block_copy_internal(const void *arg, const int flags) {
    struct Block_layout *aBlock;
    const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE;

    //printf("_Block_copy_internal(%p, %x)\n", arg, flags); 
    if (!arg) return NULL;
    
    
    // The following would be better done as a switch statement
    aBlock = (struct Block_layout *)arg;
    if (aBlock->flags & BLOCK_NEEDS_FREE) {
        // latches on high
        latching_incr_int(&aBlock->flags);
        return aBlock;
    }
    else if (aBlock->flags & BLOCK_IS_GC) {
        // GC refcounting is expensive so do most refcounting here.
        if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) {
            // Tell collector to hang on this - it will bump the GC refcount version
            _Block_setHasRefcount(aBlock, true);
        }
        return aBlock;
    }
    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
        return aBlock;
    }

    // Its a stack block.  Make a copy.
    if (!isGC) {
        struct Block_layout *result = malloc(aBlock->descriptor->size);
        if (!result) return (void *)0;
        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
        // reset refcount
        result->flags &= ~(BLOCK_REFCOUNT_MASK);    // XXX not needed
        result->flags |= BLOCK_NEEDS_FREE | 1;
        result->isa = _NSConcreteMallocBlock;
        if (result->flags & BLOCK_HAS_COPY_DISPOSE) {
            //printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);
            (*aBlock->descriptor->copy)(result, aBlock); // do fixup
        }
        return result;
    }
    else {
        // Under GC want allocation with refcount 1 so we ask for "true" if wantsOne
        // This allows the copy helper routines to make non-refcounted block copies under GC
        unsigned long int flags = aBlock->flags;
        bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0;
        struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR);
        if (!result) return (void *)0;
        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
        // reset refcount
        // if we copy a malloc block to a GC block then we need to clear NEEDS_FREE.
        flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK);   // XXX not needed
        if (wantsOne)
            flags |= BLOCK_IS_GC | 1;
        else
            flags |= BLOCK_IS_GC;
        result->flags = flags;
        if (flags & BLOCK_HAS_COPY_DISPOSE) {
            //printf("calling block copy helper...\n");
            (*aBlock->descriptor->copy)(result, aBlock); // do fixup
        }
        if (hasCTOR) {
            result->isa = _NSConcreteFinalizingBlock;
        }
        else {
            result->isa = _NSConcreteAutoBlock;
        }
        return result;
    }
}

// API entry point to release a copied Block
void _Block_release(void *arg) {
    struct Block_layout *aBlock = (struct Block_layout *)arg;
    int32_t newCount;
    if (!aBlock) return;
    newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK;
    if (newCount > 0) return;
    // Hit zero
    if (aBlock->flags & BLOCK_IS_GC) {
        // Tell GC we no longer have our own refcounts.  GC will decr its refcount
        // and unless someone has done a CFRetain or marked it uncollectable it will
        // now be subject to GC reclamation.
        _Block_setHasRefcount(aBlock, false);
    }
    else if (aBlock->flags & BLOCK_NEEDS_FREE) {
        if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock);
        _Block_deallocator(aBlock);
    }
    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
        ;
    }
    else {
        printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock);
    }
}

block 相關(guān) struct

block 在 clang編譯后的結(jié)構(gòu)體:
struct __block_impl {
    void *isa; // 指向block的具體類型
    int Flags;
    int Reserved;
    void *FuncPtr; // 函數(shù)指針 FunctionPointer, 指向block的實(shí)現(xiàn) __funcName_block_func_0
};
block 在 Block_private.h 中的聲明:
struct Block_layout {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};

struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市酪耳,隨后出現(xiàn)的幾起案子浓恳,更是在濱河造成了極大的恐慌,老刑警劉巖碗暗,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颈将,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡言疗,警方通過(guò)查閱死者的電腦和手機(jī)晴圾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)噪奄,“玉大人死姚,你說(shuō)我怎么就攤上這事∏诶海” “怎么了都毒?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)碰缔。 經(jīng)常有香客問(wèn)我账劲,道長(zhǎng),這世上最難降的妖魔是什么金抡? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任瀑焦,我火速辦了婚禮,結(jié)果婚禮上梗肝,老公的妹妹穿的比我還像新娘榛瓮。我一直安慰自己,他們只是感情好统捶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布榆芦。 她就那樣靜靜地躺著柄粹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匆绣。 梳的紋絲不亂的頭發(fā)上驻右,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音崎淳,去河邊找鬼堪夭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拣凹,可吹牛的內(nèi)容都是我干的森爽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼嚣镜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼爬迟!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起菊匿,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤付呕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后跌捆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徽职,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年佩厚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了姆钉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抄瓦,死狀恐怖潮瓶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闺鲸,我是刑警寧澤筋讨,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站摸恍,受9級(jí)特大地震影響悉罕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜立镶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一壁袄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧媚媒,春花似錦嗜逻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逆日。三九已至,卻和暖如春萄凤,著一層夾襖步出監(jiān)牢的瞬間室抽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工靡努, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坪圾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓惑朦,卻偏偏與公主長(zhǎng)得像兽泄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漾月,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 11,004評(píng)論 6 13
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,111評(píng)論 1 32
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔病梢,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡(jiǎn)書還為我保存起的...
    Jenaral閱讀 2,767評(píng)論 2 9
  • 周末連考兩天,其實(shí)也就是兩門苹粟,即《中國(guó)特色社會(huì)主義》和《高等統(tǒng)計(jì)學(xué)》。不出意外,這估計(jì)是在職研究生的最后兩門考試了...
    墨道院閱讀 199評(píng)論 2 1
  • 當(dāng)秋天的風(fēng)一過(guò)昔期,那些樹的葉子,花的種子就開始瑟瑟作響花墩,因?yàn)橹涝伲K有一天會(huì)于繁華的表象里脫離,水分從陽(yáng)光的懷抱里漸...
    春暖花開6091閱讀 340評(píng)論 0 0