1版述、什么是局部變量,什么是全局變量
? ? 局部變量分為自動(dòng)變量(就是我們平常在函數(shù)內(nèi)部定義的變量,只是默認(rèn)省略了auto修飾符)和靜態(tài)變量(在函數(shù)內(nèi)部定義悴务,用static修飾),局部變量之所以稱(chēng)為局部變量譬猫,是因?yàn)槌隽俗饔糜蚓蜁?huì)銷(xiāo)毀讯檐,但是static修飾的局部變量會(huì)一直在內(nèi)存中。
2染服、Block的本質(zhì)就是一個(gè)OC對(duì)象别洪,他有isa指針,并且Block是封裝了函數(shù)以及函數(shù)調(diào)用環(huán)境的OC對(duì)象? ?Block轉(zhuǎn)化成的結(jié)構(gòu)體中都擁有impl(里面包含了封裝函數(shù)的地址)和desc(這里包括了這個(gè)Block的size 保留對(duì)象柳刮, copy方法挖垛,這個(gè)方法是用來(lái)將block從棧拷貝到堆中使用的秉颗,還有dispose方法痢毒,這個(gè)方法是block銷(xiāo)毀的時(shí)候調(diào)用的,copy和dispose方法只有自動(dòng)變量是對(duì)象類(lèi)型的時(shí)候才會(huì)出現(xiàn)蚕甥,因?yàn)橹挥袑?duì)象類(lèi)型才需要進(jìn)行內(nèi)存操作)
3哪替、為了保證Block能夠訪問(wèn)外部的變量,Block有個(gè)外部變量捕獲機(jī)制梢灭,自動(dòng)變量和靜態(tài)變量都會(huì)被Block捕獲夷家,但是自動(dòng)變量是值捕獲,就是值存自動(dòng)變量的值敏释,但是靜態(tài)變量是指針捕獲库快,因?yàn)榻鹛┳兞恳恢痹趦?nèi)存中,所以可以直接調(diào)用就行钥顽,所以是指針捕獲义屏。捕獲局部變量的原因是自動(dòng)變量出了作用域就銷(xiāo)毀了,可是Block出了函數(shù)作用域還可以在別的函數(shù)中調(diào)用蜂大,而你封裝的Block內(nèi)部又訪問(wèn)了你已經(jīng)銷(xiāo)毀的局部變量闽铐,所以Block內(nèi)部必須把局部變量通過(guò)值捕獲或者指針捕獲保存在Block內(nèi)部
4、Block不會(huì)捕獲全局變量奶浦,因?yàn)槿肿兞康教幎寄茉L問(wèn)兄墅,跨函數(shù)也能訪問(wèn),所以根本沒(méi)必要再在Block內(nèi)部保存一份了澳叉,直接訪問(wèn)就可以了
5隙咸、需要注意的是? 如果Block內(nèi)部訪問(wèn)了self沐悦,那么這個(gè)self也會(huì)被捕獲,原因是self也是個(gè)局部變量五督,因?yàn)榉椒ㄞD(zhuǎn)換成C語(yǔ)言函數(shù)之后 都會(huì)變成XXX(self,_cmd),也就是說(shuō)方法轉(zhuǎn)換成C語(yǔ)言后都有固定的兩個(gè)參數(shù)藏否,一個(gè)是self,另一個(gè)是方法名稱(chēng)充包,作為參數(shù)副签,那么久肯定是局部變量,所以肯定會(huì)被捕獲
Block的類(lèi)型
1基矮、Block都是繼承自NSBlock類(lèi)型的淆储,Block分為_(kāi)_GlobalBlock__? ?、__ NSStackBlock__ 家浇、__ NSMallocBlock__三種類(lèi)型遏考,其中__GlobalBlock__ 存放在數(shù)據(jù)區(qū)、__ NSStackBlock__存放在棧區(qū)蓝谨、__ NSMallocBlock__存放在堆區(qū)
2、只要你不訪問(wèn)自動(dòng)變量青团,那么Block類(lèi)型就是__GlobalBlock__ 如果你訪問(wèn)了自動(dòng)變量譬巫,在MRC上你就會(huì)是__ NSStackBlock__類(lèi)型,但是在ARC上督笆,有下面4中情況芦昔,系統(tǒng)會(huì)自動(dòng)把BLock copy一份到堆中
????2.1、使用copy方法
? ? 2.2娃肿、賦值給strong指針
? ??2.3咕缎、block作為方法名字中含有UnsignBlock的方法參數(shù)(比如枚舉邊里數(shù)組)
????2.4、block作為作為GCD的方法參數(shù)? ?
這4中情況下Block就是__ NSMallocBlock__料扰,其余的 只要你沒(méi)有訪問(wèn)自動(dòng)變量凭豪,那就是__GlobalBlock__ ,訪問(wèn)了晒杈,那么你就是__ NSStackBlock__
3嫂伞、如果Block訪問(wèn)了自動(dòng)變量,但是你的這個(gè)Block只是棧上面的Block拯钻,那么這個(gè)Block內(nèi)部就不會(huì)堆自動(dòng)變量進(jìn)行引用帖努,強(qiáng)弱引用都不會(huì),因?yàn)锽lock都會(huì)隨時(shí)不保粪般,引用自動(dòng)變量也沒(méi)有多大意義拼余。如果Block被拷貝到了堆上面,那么就會(huì)調(diào)用Block內(nèi)部的Copy方法亩歹,copy法法內(nèi)部就會(huì)調(diào)用_Block_object_assign函數(shù)匙监,會(huì)根據(jù)自動(dòng)變量是weak類(lèi)型凡橱,還是strong類(lèi)型還是unsafe_unretained類(lèi)型,來(lái)對(duì)該自動(dòng)變量進(jìn)行強(qiáng)弱引用舅柜。當(dāng)Block銷(xiāo)毀的時(shí)候梭纹,會(huì)調(diào)用Block內(nèi)部的dispose方法,根據(jù)_Block_object_dispose函數(shù)來(lái)對(duì)已經(jīng)引用的自動(dòng)變量進(jìn)行釋放
Block修改自動(dòng)變量
? ? 1.block訪問(wèn)了自動(dòng)變量致份,自動(dòng)變量只是值傳遞变抽,如果你要在block內(nèi)部就改變不了這個(gè)自動(dòng)變量的值
? ? 2、但是如果你的自動(dòng)變量是指針傳遞氮块,那么因?yàn)槟愕膬?nèi)部引用了該指針绍载,所以你就能改變這個(gè)指針?biāo)笇?duì)象的值(static修飾的局部變量,全局變量)
? ? 3滔蝉、如果不能修改自動(dòng)變量击儡,你需要用__block來(lái)修飾該自動(dòng)變量,__block內(nèi)部是將該自動(dòng)變量包裝成了一個(gè)新的對(duì)象蝠引,這個(gè)新的對(duì)象中有個(gè)指向自己的指針阳谍,如果你要修改該自動(dòng)變量,他就會(huì)通過(guò)forwarding指針找到被包裝的這個(gè)對(duì)象螃概,然后修改里面的值
4矫夯、為什么非要弄一個(gè)forwarding指針來(lái)指向自己呢,為什么不通過(guò)Block內(nèi)部指向結(jié)構(gòu)體的指針找到你要修改的自動(dòng)變量來(lái)進(jìn)行修改呢
? ? 答:因?yàn)樽詣?dòng)變量生成的時(shí)候都是在棧區(qū)的吊洼,通過(guò)Block的自動(dòng)捕獲機(jī)制训貌,還有用__block修飾之后,把你的這個(gè)自動(dòng)變量包裝成了一個(gè)結(jié)構(gòu)體冒窍,Block內(nèi)部的指向結(jié)構(gòu)體的指針指向了這個(gè)結(jié)構(gòu)體递沪,Block一旦被copy到了堆區(qū),那么這個(gè)結(jié)構(gòu)體也被復(fù)制到了堆區(qū)综液,會(huì)調(diào)用block內(nèi)部的copy函數(shù)款慨,copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù),_Block_object_assign函數(shù)會(huì)對(duì)__block變量形成強(qiáng)引用(根據(jù)變量修飾符來(lái)決定)谬莹,但是我們修改變量后樱调,我們都希望只對(duì)堆取得自動(dòng)變量進(jìn)行修改,因?yàn)樾薷臈^(qū)的沒(méi)意義届良,但是吐過(guò)你訪問(wèn)的是戰(zhàn)區(qū)的自動(dòng)變量笆凌,然后修改了,那就達(dá)不到效果了士葫,這個(gè)時(shí)候乞而,就需要指向自己的指針了,如果你訪問(wèn)的是站上的自動(dòng)變量慢显,站上的自動(dòng)變量的forwarding指針指向的是堆中的__block包裝的結(jié)構(gòu)體爪模,然后再堆中的結(jié)構(gòu)體找到forwarding找到堆中結(jié)構(gòu)體里面的自動(dòng)變量進(jìn)行修改欠啤,如果你修改的是堆中的自動(dòng)變量,那就直接找到堆中的結(jié)構(gòu)體進(jìn)行修改屋灌,所以forwarding的作用就是無(wú)論你修改的是占中的自動(dòng)變量還是堆中的洁段,都能保證修改了堆中的自動(dòng)變量
5、Block在棧上時(shí)共郭,并不會(huì)對(duì)__block變量進(jìn)行強(qiáng)引用祠丝,當(dāng)block被copy到堆時(shí)會(huì)調(diào)用block內(nèi)部的copy函數(shù),copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)除嘹,_Block_object_assign函數(shù)會(huì)對(duì)__block變量形成強(qiáng)引用(非對(duì)象類(lèi)型写半,對(duì)象類(lèi)型還要根據(jù)修飾符決定是否強(qiáng)引用,如果是MRC? 那么一定是弱引用)
6尉咕、當(dāng)block從堆中移除時(shí)叠蝇,會(huì)調(diào)用block內(nèi)部的dispose函數(shù),dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)年缎,_Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的__block變量(release)