Concurrent Programming in Mac OS X and iOS
Concurrent Programming in Mac OS X and iOS
9DQGDG 1DKDYDQGLSRRU
Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo
Concurrent Programming in Mac OS X and iOS E\ 9DQGDG 1DKDYDQGLSRRU &RS\ULJKW ‹ 9DQGDG 1DKDYDQGLSRRU $OO ULJKWV UHVHUYHG 3ULQWHG LQ WKH 8QLWHG 6WDWHV RI $PHULFD 3XEOLVKHG E\ 2¦5HLOO\ 0HGLD ,QF *UDYHQVWHLQ +LJKZD\ 1RUWK 6HEDVWRSRO &$ 2¦5HLOO\ ERRNV PD\ EH SXUFKDVHG IRU HGXFDWLRQDO EXVLQHVV RU VDOHV SURPRWLRQDO XVH 2QOLQH HGLWLRQV DUH DOVR DYDLODEOH IRU PRVW WLWOHV KWWS P\ VDIDULERRNVRQOLQH FRP )RU PRUH LQIRUPDWLRQ FRQWDFW RXU FRUSRUDWH LQVWLWXWLRQDO VDOHV GHSDUWPHQW RU FRUSRUDWH#RUHLOO\ FRP
Editor: $QG\ 2UDP Production Editor: 7HUHVD (OVH\ Proofreader: 7HUHVD (OVH\
Cover Designer: .DUHQ 0RQWJRPHU\ Interior Designer: 'DYLG )XWDWR Illustrator: 5REHUW 5RPDQR
Printing History: -XQH
)LUVW (GLWLRQ
1XWVKHOO +DQGERRN WKH 1XWVKHOO +DQGERRN ORJR DQG WKH 2¦5HLOO\ ORJR DUH UHJLVWHUHG WUDGHPDUNV RI 2¦5HLOO\ 0HGLD ,QF &RQFXUUHQW 3URJUDPPLQJ LQ 0DF 26 ; DQG L26 WKH LPDJH RI D 5XVVLDQ JUH\KRXQG DQG UHODWHG WUDGH GUHVV DUH WUDGHPDUNV RI 2¦5HLOO\ 0HGLD ,QF 0DQ\ RI WKH GHVLJQDWLRQV XVHG E\ PDQXIDFWXUHUV DQG VHOOHUV WR GLVWLQJXLVK WKHLU SURGXFWV DUH FODLPHG DV WUDGHPDUNV :KHUH WKRVH GHVLJQDWLRQV DSSHDU LQ WKLV ERRN DQG 2¦5HLOO\ 0HGLD ,QF ZDV DZDUH RI D WUDGHPDUN FODLP WKH GHVLJQDWLRQV KDYH EHHQ SULQWHG LQ FDSV RU LQLWLDO FDSV :KLOH HYHU\ SUHFDXWLRQ KDV EHHQ WDNHQ LQ WKH SUHSDUDWLRQ RI WKLV ERRN WKH SXEOLVKHU DQG DXWKRUV DVVXPH QR UHVSRQVLELOLW\ IRU HUURUV RU RPLVVLRQV RU IRU GDPDJHV UHVXOWLQJ IURP WKH XVH RI WKH LQIRUPDWLRQ FRQ WDLQHG KHUHLQ
,6%1 >/6,@
Table of Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii 1. Introducing Block Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 6KRUW ,QWURGXFWLRQ WR %ORFN 2EMHFWV &RQVWUXFWLQJ %ORFN 2EMHFWV DQG 7KHLU 6\QWD[ 9DULDEOHV DQG 7KHLU 6FRSH LQ %ORFN 2EMHFWV ,QYRNLQJ %ORFN 2EMHFWV 0HPRU\ 0DQDJHPHQW IRU %ORFN 2EMHFWV
2. Programming Grand Central Dispatch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 6KRUW ,QWURGXFWLRQ WR *UDQG &HQWUDO 'LVSDWFK 'LIIHUHQW 7\SHV RI 'LVSDWFK 4XHXHV 'LVSDWFKLQJ 7DVNV WR *UDQG &HQWUDO 'LVSDWFK 3HUIRUPLQJ 8, 5HODWHG 7DVNV 3HUIRUPLQJ 1RQ 8, 5HODWHG 7DVNV 6\QFKURQRXVO\ 3HUIRUPLQJ 1RQ 8, 5HODWHG 7DVNV $V\QFKURQRXVO\ 3HUIRUPLQJ 7DVNV $IWHU D 'HOD\ 3HUIRUPLQJ D 7DVN DW 0RVW 2QFH 5XQQLQJ D *URXS RI 7DVNV 7RJHWKHU &RQVWUXFWLQJ <RXU 2ZQ 'LVSDWFK 4XHXHV
v
Preface
:LWK WKH LQWURGXFWLRQ RI PXOWLFRUH GHYLFHV VXFK DV WKH L3DG DQG WKH TXDG FRUH 0DF %RRN 3UR ZULWLQJ PXOWLWKUHDGHG DSSV WKDW WDNH DGYDQWDJH RI PXOWLSOH FRUHV RQ D GHYLFH KDV EHFRPH RQH RI WKH ELJJHVW KHDGDFKHV IRU GHYHORSHUV 7DNH IRU LQVWDQFH WKH LQWUR GXFWLRQ RI L3DG 2Q WKH ODXQFK GD\ RQO\ D IHZ DSSOLFDWLRQV EDVLFDOO\ WKRVH UHOHDVHG E\ $SSOH ZHUH DEOH WR WDNH DGYDQWDJH RI LWV PXOWLSOH FRUHV $SSOLFDWLRQV OLNH 6DIDUL SHUIRUPHG YHU\ ZHOO RQ WKH L3DG FRPSDUHG WR WKH RULJLQDO L3DG EXW VRPH WKLUG SDUW\ EURZVHUV GLG QRW SHUIRUP DV ZHOO DV 6DIDUL 7KH UHDVRQ EHKLQG WKLV LV WKDW $SSOH KDV XWLOL]HG *UDQG &HQWUDO 'LVSDWFK *&' LQ 6DIDUL¦V FRGH EDVH *&' LV D ORZ OHYHO & $3, WKDW DOORZV GHYHORSHUV WR ZULWH PXOWLWKUHDGHG DSSOLFDWLRQV ZLWKRXW WKH QHHG WR PDQDJH WKUHDGV DW DOO $OO GHYHORSHUV KDYH WR GR LV GHILQH WDVNV DQG OHDYH WKH UHVW WR *&' 7KH WUHQG LQ WKH LQGXVWU\ LV PRELOLW\ 0RELOH GHYLFHV ZKHWKHU WKH\ DUH DV FRPSDFW DV DQ L3KRQH RU DV VWURQJ DQG IXOO IOHGJHG DV DQ $SSOH 0DF%RRN 3UR KDYH PDQ\ IHZHU UHVRXUFHV WKDQ FRPSXWHUV VXFK DV WKH 0DF 3UR EHFDXVH DOO WKH KDUGZDUH KDV WR EH SODFHG LQVLGH WKH VPDOO GHYLFHV¦ FRPSDFW ERGLHV %HFDXVH RI WKLV LW LV YHU\ LPSRUWDQW WR ZULWH DSSOLFDWLRQV WKDW ZRUN VPRRWKO\ RQ PRELOH GHYLFHV VXFK DV WKH L3KRQH :H DUH QRW WKDW IDU DZD\ IURP KDYLQJ TXDG FRUH RU FRUH VPDUWSKRQHV 2QFH ZH KDYH FRUHV LQ WKH &38 DQ DSS H[HFXWHG RQ RQO\ RQH RI WKH FRUHV ZLOO UXQ WUHPHQGRXVO\ PRUH VORZO\ WKDQ DQ DSS WKDW KDV EHHQ RSWLPL]HG ZLWK D WHFKQRORJ\ VXFK DV *&' ZKLFK DOORZV WKH FRGH WR EH VFKHGXOHG RQ PXOWLSOH FRUHV ZLWKRXW WKH SURJUDPPHU KDYLQJ WR PDQDJH WKLV V\QFKURQL]DWLRQ $SSOH LV SXVKLQJ GHYHORSHUV DZD\ IURP XVLQJ WKUHDGV DQG LV VORZO\ VWDUWLQJ WR LQWHJUDWH *&' LQWR LWV YDULRXV IUDPHZRUNV )RU LQVWDQFH SULRU WR WKH LQWURGXFWLRQ RI *&' LQ L26 RSHUDWLRQV DQG RSHUDWLRQ TXHXHV XVHG WKUHDGV :LWK WKH LQWURGXFWLRQ RI *&' $SSOH FRPSOHWHO\ FKDQJHG WKH LPSOHPHQWDWLRQ RI RSHUDWLRQV DQG RSHUDWLRQ TXHXHV E\ XVLQJ *&' LQVWHDG RI WKUHDGV 7KLV ERRN LV ZULWWHQ IRU WKRVH RI \RX ZKR ZDQW WR GR ZKDW $SSOH VXJJHVWV DQG ZKDW VHHPV OLNH WKH EULJKW IXWXUH IRU VRIWZDUH GHYHORSPHQW PLJUDWLQJ DZD\ IURP WKUHDGV DQG DOORZLQJ WKH RSHUDWLQJ V\VWHP WR WDNH FDUH RI WKUHDGV IRU \RX E\ UHSODFLQJ WKUHDG SURJUDPPLQJ ZLWK *&'
vii
Audience ,Q WKLV ERRN , DVVXPH WKDW \RX KDYH D IDLUO\ EDVLF XQGHUVWDQGLQJ RI WKH XQGHUO\LQJ WHFKQRORJLHV XVHG LQ ZULWLQJ L26 DQG RU 0DF 26 ; DSSOLFDWLRQV :H ZLOO QRW EH GLV FXVVLQJ VXEMHFWV UHODWHG WR &RFRD 7RXFK RU &RFRD :H ZLOO EH XVLQJ FRGH WKDW ZRUNV LQ SULQFLSOH DQG *&' OD\HU ERWK ZLWK L26 DQG 0DF 26 ; 7KHUHIRUH \RX ZLOO QHHG WR NQRZ WKH EDVLFV RI 2EMHFWLYH & DQG \RXU ZD\ DURXQG EDVLF IXQFWLRQDOLWLHV XWLOL]HG E\ &RUH )RXQGDWLRQ VXFK DV VWULQJ PDQLSXODWLRQ DQG DUUD\V 2¦5HLOO\¦V L26 3URJUDPPLQJ &RRNERRN LV D JRRG VRXUFH IRU PRUH DERXW REMHFW DOORFDWLRQ DUUD\V DQG 8, UHODWHG FRGH LQ FDVH \RX DUH ORRNLQJ WR EURDGHQ \RXU SHUVSHFWLYH WRZDUG L26 SURJUDPPLQJ
Conventions Used in This Book 7KH IROORZLQJ W\SRJUDSKLFDO FRQYHQWLRQV DUH XVHG LQ WKLV ERRN ,WDOLF ,QGLFDWHV QHZ WHUPV 85/V HPDLO DGGUHVVHV ILOHQDPHV DQG ILOH H[WHQVLRQV Constant width
8VHG IRU SURJUDP OLVWLQJV DV ZHOO DV ZLWKLQ SDUDJUDSKV WR UHIHU WR SURJUDP HOHPHQWV VXFK DV YDULDEOH RU IXQFWLRQ QDPHV GDWDEDVHV GDWD W\SHV HQYLURQPHQW YDULDEOHV VWDWHPHQWV DQG NH\ZRUGV Constant width bold
6KRZV FRPPDQGV RU RWKHU WH[W WKDW VKRXOG EH W\SHG OLWHUDOO\ E\ WKH XVHU Constant width italic
6KRZV WH[W WKDW VKRXOG EH UHSODFHG ZLWK XVHU VXSSOLHG YDOXHV RU E\ YDOXHV GHWHU PLQHG E\ FRQWH[W 7KLV LFRQ VLJQLILHV D WLS VXJJHVWLRQ RU JHQHUDO QRWH
Using Code Examples 7KLV ERRN LV KHUH WR KHOS \RX JHW \RXU MRE GRQH ,Q JHQHUDO \RX PD\ XVH WKH FRGH LQ WKLV ERRN LQ \RXU SURJUDPV DQG GRFXPHQWDWLRQ <RX GR QRW QHHG WR FRQWDFW XV IRU SHUPLVVLRQ XQOHVV \RX¦UH UHSURGXFLQJ D VLJQLILFDQW SRUWLRQ RI WKH FRGH )RU H[DPSOH ZULWLQJ D SURJUDP WKDW XVHV VHYHUDO FKXQNV RI FRGH IURP WKLV ERRN GRHV QRW UHTXLUH SHUPLVVLRQ 6HOOLQJ RU GLVWULEXWLQJ D &' 520 RI H[DPSOHV IURP 2¦5HLOO\ ERRNV GRHV UHTXLUH SHUPLVVLRQ $QVZHULQJ D TXHVWLRQ E\ FLWLQJ WKLV ERRN DQG TXRWLQJ H[DPSOH viii | Preface
FRGH GRHV QRW UHTXLUH SHUPLVVLRQ ,QFRUSRUDWLQJ D VLJQLILFDQW DPRXQW RI H[DPSOH FRGH IURP WKLV ERRN LQWR \RXU SURGXFW¦V GRFXPHQWDWLRQ GRHV UHTXLUH SHUPLVVLRQ :H DSSUHFLDWH EXW GR QRW UHTXLUH DWWULEXWLRQ $Q DWWULEXWLRQ XVXDOO\ LQFOXGHV WKH WLWOH DXWKRU SXEOLVKHU DQG ,6%1 )RU H[DPSOH £&RQFXUUHQW 3URJUDPPLQJ LQ 0DF 26 ; DQG L26 E\ 9DQGDG 1DKDYDQGLSRRU 2¦5HLOO\ &RS\ULJKW 9DQGDG 1DKDYDQGLSRRU ¤ ,I \RX IHHO \RXU XVH RI FRGH H[DPSOHV IDOOV RXWVLGH IDLU XVH RU WKH SHUPLVVLRQ JLYHQ DERYH IHHO IUHH WR FRQWDFW XV DW SHUPLVVLRQV#RUHLOO\ FRP
Safari® Books Online 6DIDUL %RRNV 2QOLQH LV DQ RQ GHPDQG GLJLWDO OLEUDU\ WKDW OHWV \RX HDVLO\ VHDUFK RYHU WHFKQRORJ\ DQG FUHDWLYH UHIHUHQFH ERRNV DQG YLGHRV WR ILQG WKH DQVZHUV \RX QHHG TXLFNO\ :LWK D VXEVFULSWLRQ \RX FDQ UHDG DQ\ SDJH DQG ZDWFK DQ\ YLGHR IURP RXU OLEUDU\ RQOLQH 5HDG ERRNV RQ \RXU FHOO SKRQH DQG PRELOH GHYLFHV $FFHVV QHZ WLWOHV EHIRUH WKH\ DUH DYDLODEOH IRU SULQW DQG JHW H[FOXVLYH DFFHVV WR PDQXVFULSWV LQ GHYHORSPHQW DQG SRVW IHHGEDFN IRU WKH DXWKRUV &RS\ DQG SDVWH FRGH VDPSOHV RUJDQL]H \RXU IDYRULWHV GRZQ ORDG FKDSWHUV ERRNPDUN NH\ VHFWLRQV FUHDWH QRWHV SULQW RXW SDJHV DQG EHQHILW IURP WRQV RI RWKHU WLPH VDYLQJ IHDWXUHV 2¦5HLOO\ 0HGLD KDV XSORDGHG WKLV ERRN WR WKH 6DIDUL %RRNV 2QOLQH VHUYLFH 7R KDYH IXOO GLJLWDO DFFHVV WR WKLV ERRN DQG RWKHUV RQ VLPLODU WRSLFV IURP 2¦5HLOO\ DQG RWKHU SXE OLVKHUV VLJQ XS IRU IUHH DW KWWS P\ VDIDULERRNVRQOLQH FRP
How to Contact Us 3OHDVH DGGUHVV FRPPHQWV DQG TXHVWLRQV FRQFHUQLQJ WKLV ERRN WR WKH SXEOLVKHU 2¦5HLOO\ 0HGLD ,QF *UDYHQVWHLQ +LJKZD\ 1RUWK 6HEDVWRSRO &$ LQ WKH 8QLWHG 6WDWHV RU &DQDGD
LQWHUQDWLRQDO RU ORFDO
ID[
:H KDYH D ZHE SDJH IRU WKLV ERRN ZKHUH ZH OLVW HUUDWD H[DPSOHV DQG DQ\ DGGLWLRQDO LQIRUPDWLRQ <RX FDQ DFFHVV WKLV SDJH DW KWWS ZZZ RUHLOO\ FRP FDWDORJ 7R FRPPHQW RU DVN WHFKQLFDO TXHVWLRQV DERXW WKLV ERRN VHQG HPDLO WR ERRNTXHVWLRQV#RUHLOO\ FRP
Preface | ix
)RU PRUH LQIRUPDWLRQ DERXW RXU ERRNV FRXUVHV FRQIHUHQFHV DQG QHZV VHH RXU ZHEVLWH DW KWWS ZZZ RUHLOO\ FRP )LQG XV RQ )DFHERRN KWWS IDFHERRN FRP RUHLOO\ )ROORZ XV RQ 7ZLWWHU KWWS WZLWWHU FRP RUHLOO\PHGLD :DWFK XV RQ <RX7XEH KWWS ZZZ \RXWXEH FRP RUHLOO\PHGLD
Acknowledgments :RUNLQJ ZLWK 2¦5HLOO\ WR ZULWH ERRNV KDV DOZD\V EHHQ D SOHDVXUH DQG WKLV ERRN LV QRW DQ H[FHSWLRQ , PXVW VD\ , DP YHU\ IRUWXQDWH WR KDYH IDQWDVWLF IULHQGV DQG D IDQWDVWLF VXSSRUW WHDP DURXQG PH IRU ZLWKRXW WKHP , ZRXOGQ¦W EH WKH SHUVRQ , DP WRGD\ DQG \RX ZRXOGQ¦W EH UHDGLQJ WKLV ERRN $QG\ 2UDP DQG %ULDQ -HSVRQ KDYH EHHQ LQFUHGLEO\ VXSSRUWLYH RI P\ HIIRUWV DQG KDYH IRU WKH IRXUWK WLPH JLYHQ PH D FKDQFH WR UHDFK RXW WR WKRVH ZKR ZDQW WR EH HGXFDWHG IXUWKHU LQ FXWWLQJ HGJH WHFKQRORJLHV VXFK DV *UDQG &HQWUDO 'LVSDWFK , DP JUDWHIXO IRU P\ ZRQGHUIXO IULHQGV ZKR KDYH EHHQ D FRQWLQXRXV VRXUFH RI LQVSLUDWLRQ DQG VXSSRUW 7KDQNV WR P\ IULHQGV DQG FROOHDJXHV 6XVKLO 6KLUNH 6KHQF\ 5HYLQGUDQ $QJHOD 5RU\ &KULV +DUPDQ 1DWDOLH 6]UDMEHU 6LPRQ :KLWW\ 6KDXQ 3XFNULQ *DU\ 0F&DUYLOOH 0DUN +DUULV DQG .LUN 3DWWLQVRQ , ZRXOG DOVR OLNH WR WKDQN HYHU\ERG\ IURP 2¦5HLOO\ ZKR KDV KHOSHG PH VR IDU ZLWK P\ VRPHWLPHV LQFUHGLEO\ DQQR\LQJ UHTXHVWV 7KDQNV WR 6DUDK 6FKQHLGHU IRU KHOSLQJ PH ZLWK 691 VHWXS DQG RWKHU WHFKQLFDO 'RF%RRN TXHVWLRQV 7KDQNV WR 5DFKHO -DPHV IRU KHOSLQJ PH PDQDJH UHDGHUV¦ UHTXHVWV IRU P\ H[LVWLQJ ERRNV $ ELJ WKDQN \RX JRHV WR %HWV\ :DOLV]HZVNL DQG *UHWFKHQ *LOHV RI 2¦5HLOO\ IRU DUUDQJLQJ D WKUHH GD\ KDOI SULFH RIIHU RQ PDQ\ 2¦5HLOO\ WLWOHV WR KHOS ZLWK -DSDQHVH GLVDVWHU UHOLHI :LWK DOO \RX ZRQ GHUIXO UHDGHUV¦ KHOS 2¦5HLOO\ GRQDWHG WR -DSDQHVH GLVDVWHU UHOLHI LQ 0DUFK /DVW EXW QRW OHDVW , ZRXOG OLNH WR WKDQN \RX IRU UHDGLQJ WKLV ERRN <RXU EHOLHI LQ P\ ZRUN LV ZKDW NHHSV PH ZULWLQJ PRUH ERRNV WKDW KHOS UHDGHUV EH PRUH SURGXFWLYH DQG FUHDWLYH
x | Preface
CHAPTER 1
Introducing Block Objects
%ORFN REMHFWV DUH SDFNDJHV RI FRGH WKDW XVXDOO\ DSSHDU LQ WKH IRUP RI PHWKRGV LQ 2EMHFWLYH & %ORFN REMHFWV WRJHWKHU ZLWK *UDQG &HQWUDO 'LVSDWFK *&' FUHDWH D KDUPRQLRXV HQYLURQPHQW LQ ZKLFK \RX FDQ GHOLYHU KLJK SHUIRUPDQFH PXOWLWKUHDGHG DSSV LQ L26 DQG 0DF 26 ; :KDW¦V VR VSHFLDO DERXW EORFN REMHFWV DQG *&' \RX PLJKW DVN" ,W¦V VLPSOH QR PRUH WKUHDGV $OO \RX KDYH WR GR LV WR SXW \RXU FRGH LQ EORFN REMHFWV DQG DVN *&' WR WDNH FDUH RI WKH H[HFXWLRQ RI WKDW FRGH IRU \RX ,Q WKLV FKDSWHU \RX ZLOO OHDUQ WKH EDVLFV RI EORFN REMHFWV IROORZHG E\ VRPH PRUH DG YDQFHG VXEMHFWV <RX ZLOO XQGHUVWDQG HYHU\WKLQJ \RX QHHG WR NQRZ DERXW EORFN REMHFWV EHIRUH PRYLQJ WR WKH *UDQG &HQWUDO 'LVSDWFK FKDSWHU )URP P\ H[SHULHQFH WKH EHVW ZD\ WR OHDUQ EORFN REMHFWV LV WKURXJK H[DPSOHV VR \RX ZLOO VHH D ORW RI WKHP LQ WKLV FKDSWHU 0DNH VXUH \RX WU\ WKH H[DPSOHV IRU \RXUVHOI LQ ;FRGH WR UHDOO\ JHW WKH V\QWD[ RI EORFN REMHFWV
Short Introduction to Block Objects %ORFN REMHFWV LQ 2EMHFWLYH & DUH ZKDW WKH SURJUDPPLQJ ILHOG FDOOV ILUVW FODVV REMHFWV 7KLV PHDQV \RX FDQ EXLOG FRGH G\QDPLFDOO\ SDVV D EORFN REMHFW WR D PHWKRG DV D SDUDPHWHU DQG UHWXUQ D EORFN REMHFW IURP D PHWKRG $OO RI WKHVH WKLQJV PDNH LW HDVLHU WR FKRRVH ZKDW \RX ZDQW WR GR DW UXQWLPH DQG FKDQJH WKH DFWLYLW\ RI D SURJUDP ,Q SDUWLFXODU EORFN REMHFWV FDQ EH UXQ LQ LQGLYLGXDO WKUHDGV E\ *&' %HLQJ 2EMHFWLYH & REMHFWV EORFN REMHFWV FDQ EH WUHDWHG OLNH DQ\ RWKHU REMHFW \RX FDQ UHWDLQ WKHP UHOHDVH WKHP DQG VR IRUWK %ORFN REMHFWV FDQ DOVR EH FDOOHG FORVXUHV %ORFN REMHFWV DUH VRPHWLPHV UHIHUUHG WR DV FORVXUHV
&RQVWUXFWLQJ EORFN REMHFWV LV VLPLODU WR FRQVWUXFWLQJ WUDGLWLRQDO & IXQFWLRQV DV ZH ZLOO VHH LQ £&RQVWUXFWLQJ %ORFN 2EMHFWV DQG 7KHLU 6\QWD[¤ RQ SDJH %ORFN REMHFWV FDQ 1
KDYH UHWXUQ YDOXHV DQG FDQ DFFHSW SDUDPHWHUV %ORFN REMHFWV FDQ EH GHILQHG LQOLQH RU WUHDWHG DV D VHSDUDWH EORFN RI FRGH VLPLODU WR D & IXQFWLRQ :KHQ FUHDWHG LQOLQH WKH VFRSH RI YDULDEOHV DFFHVVLEOH WR EORFN REMHFWV LV FRQVLGHUDEO\ GLIIHUHQW IURP ZKHQ D EORFN REMHFW LV LPSOHPHQWHG DV D VHSDUDWH EORFN RI FRGH *&' ZRUNV ZLWK EORFN REMHFWV :KHQ SHUIRUPLQJ WDVNV ZLWK *&' \RX FDQ SDVV D EORFN REMHFW ZKRVH FRGH FDQ JHW H[HFXWHG V\QFKURQRXVO\ RU DV\QFKURQRXVO\ GHSHQG LQJ RQ ZKLFK PHWKRGV \RX XVH LQ *&' 7KXV \RX FDQ FUHDWH D EORFN REMHFW WKDW LV UHVSRQVLEOH IRU GRZQORDGLQJ D 85/ SDVVHG WR LW DV D SDUDPHWHU 7KDW VLQJOH EORFN REMHFW FDQ WKHQ EH XVHG LQ YDULRXV SODFHV LQ \RXU DSS V\QFKURQRXVO\ RU DV\QFKURQRXVO\ GH SHQGLQJ RQ KRZ \RX ZRXOG OLNH WR UXQ LW <RX GRQ¦W KDYH WR PDNH WKH EORFN REMHFW V\QFKURQRXV RU DV\QFKURQRXV SHU VH \RX ZLOO VLPSO\ FDOO LW ZLWK V\QFKURQRXV RU DV\Q FKURQRXV *&' PHWKRGV DQG WKH EORFN REMHFW ZLOO MXVW ZRUN %ORFN REMHFWV DUH TXLWH QHZ WR SURJUDPPHUV ZULWLQJ L26 DQG 26 ; DSSV ,Q IDFW EORFN REMHFWV DUH QRW DV SRSXODU DV WKUHDGV \HW SHUKDSV EHFDXVH WKHLU V\QWD[ LV D ELW GLIIHUHQW IURP SXUH 2EMHFWLYH & PHWKRGV DQG PRUH FRPSOLFDWHG 1RQHWKHOHVV EORFN REMHFWV DUH HQRUPRXVO\ SRZHUIXO DQG $SSOH LV PDNLQJ D ELJ SXVK WRZDUG LQFRUSRUDWLQJ WKHP LQWR $SSOH OLEUDULHV <RX FDQ DOUHDG\ VHH WKHVH DGGLWLRQV LQ FODVVHV VXFK DV NSMutableArray ZKHUH SURJUDPPHUV FDQ VRUW WKH DUUD\ XVLQJ D EORFN REMHFW 7KLV FKDSWHU LV GHGLFDWHG HQWLUHO\ WR FRQVWUXFWLQJ DQG XVLQJ EORFN REMHFWV LQ L26 DQG 0DF 26 ; DSSV , ZRXOG OLNH WR VWUHVV WKDW WKH RQO\ ZD\ WR JHW XVHG WR EORFN REMHFWV¦ V\QWD[ LV WR ZULWH D IHZ RI WKHP IRU \RXUVHOI +DYH D ORRN DW WKH VDPSOH FRGH LQ WKLV FKDSWHU DQG WU\ LPSOHPHQWLQJ \RXU RZQ EORFN REMHFWV
Constructing Block Objects and Their Syntax %ORFN REMHFWV FDQ HLWKHU EH LQOLQH RU FRGHG DV LQGHSHQGHQW EORFNV RI FRGH /HW¦V VWDUW ZLWK WKH ODWWHU W\SH 6XSSRVH \RX KDYH D PHWKRG LQ 2EMHFWLYH & WKDW DFFHSWV WZR LQWHJHU YDOXHV RI W\SH NSInteger DQG UHWXUQV WKH GLIIHUHQFH RI WKH WZR YDOXHV E\ VXEWUDFWLQJ RQH IURP WKH RWKHU DV DQ NSInteger - (NSInteger) subtract:(NSInteger)paramValue from:(NSInteger)paramFrom{ return paramFrom - paramValue; }
7KDW ZDV YHU\ VLPSOH ZDVQ¦W LW" 1RZ OHW¦V WUDQVODWH WKLV 2EMHFWLYH & FRGH WR D SXUH & IXQFWLRQ WKDW SURYLGHV WKH VDPH IXQFWLRQDOLW\ WR JHW RQH VWHS FORVHU WR OHDUQLQJ WKH V\QWD[ RI EORFN REMHFWV NSInteger subtract(NSInteger paramValue, NSInteger paramFrom){ return paramFrom - paramValue; }
2 | Chapter 1: Introducing Block Objects
<RX FDQ VHH WKDW WKH & IXQFWLRQ LV TXLWH GLIIHUHQW LQ V\QWD[ IURP LWV 2EMHFWLYH & FRXQ WHUSDUW 1RZ OHW¦V KDYH D ORRN DW KRZ ZH FRXOG FRGH WKH VDPH IXQFWLRQ DV D EORFN REMHFW NSInteger (^subtract)(NSInteger, NSInteger) = ^(NSInteger paramValue, NSInteger paramFrom){ return paramValue - paramValue; };
%HIRUH , JR LQWR GHWDLOV DERXW WKH V\QWD[ RI EORFN REMHFWV OHW PH VKRZ \RX D IHZ PRUH H[DPSOHV 6XSSRVH ZH KDYH D IXQFWLRQ LQ & WKDW WDNHV D SDUDPHWHU RI W\SH NSUInteger DQ XQVLJQHG LQWHJHU DQG UHWXUQV LW DV D VWULQJ RI W\SH NSString +HUH LV KRZ ZH LP SOHPHQW WKLV LQ & NSString* intToString (NSUInteger paramInteger){ return [NSString stringWithFormat:@"%lu", (unsigned long)paramInteger]; }
7R OHDUQ DERXW IRUPDWWLQJ VWULQJV ZLWK V\VWHP LQGHSHQGHQW IRUPDW VSHFLILHUV LQ 2EMHFWLYH & SOHDVH UHIHU WR 6WULQJ 3URJUDPPLQJ *XLGH L26 'HYHORSHU /LEUDU\ RQ $SSOH¦V ZHEVLWH
7KH EORFN REMHFW HTXLYDOHQW RI WKLV & IXQFWLRQ LV VKRZQ LQ ([DPSOH ([DPSOH ([DPSOH EORFN REMHFW GHILQHG DV IXQFWLRQ NSString* (^intToString)(NSUInteger) = ^(NSUInteger paramInteger){ NSString *result = [NSString stringWithFormat:@"%lu", (unsigned long)paramInteger]; return result; };
7KH VLPSOHVW IRUP RI DQ LQGHSHQGHQW EORFN REMHFW ZRXOG EH D EORFN REMHFW WKDW UHWXUQV void DQG GRHV QRW WDNH DQ\ SDUDPHWHUV LQ void (^simpleBlock)(void) = ^{ /* Implement the block object here */ };
%ORFN REMHFWV FDQ EH LQYRNHG LQ WKH H[DFW VDPH ZD\ DV & IXQFWLRQV ,I WKH\ KDYH DQ\ SDUDPHWHUV \RX SDVV WKH SDUDPHWHUV WR WKHP OLNH D & IXQFWLRQ DQG DQ\ UHWXUQ YDOXH FDQ EH UHWULHYHG H[DFWO\ DV \RX ZRXOG UHWULHYH D & IXQFWLRQ¦V UHWXUQ YDOXH +HUH LV DQ H[DPSOH
Constructing Block Objects and Their Syntax | 3
NSString* (^intToString)(NSUInteger) = ^(NSUInteger paramInteger){ NSString *result = [NSString stringWithFormat:@"%lu", (unsigned long)paramInteger]; return result; }; - (void) callIntToString{ NSString *string = intToString(10); NSLog(@"string = %@", string); }
7KH callIntToString 2EMHFWLYH & PHWKRG LV FDOOLQJ WKH intToString EORFN REMHFW E\ SDVVLQJ WKH YDOXH DV WKH RQO\ SDUDPHWHU WR WKLV EORFN REMHFW DQG SODFLQJ WKH UHWXUQ YDOXH RI WKLV EORFN REMHFW LQ WKH string ORFDO YDULDEOH 1RZ WKDW ZH NQRZ KRZ WR ZULWH EORFN REMHFWV DV LQGHSHQGHQW EORFNV RI FRGH OHW¦V KDYH D ORRN DW SDVVLQJ EORFN REMHFWV DV SDUDPHWHUV WR 2EMHFWLYH & PHWKRGV :H ZLOO KDYH WR WKLQN D ELW DEVWUDFWO\ WR XQGHUVWDQG WKH JRDO RI WKH IROORZLQJ H[DPSOH 6XSSRVH ZH KDYH DQ 2EMHFWLYH & PHWKRG WKDW DFFHSWV DQ LQWHJHU DQG SHUIRUPV VRPH NLQG RI WUDQVIRUPDWLRQ RQ LW ZKLFK PD\ FKDQJH GHSHQGLQJ RQ ZKDW HOVH LV KDSSHQLQJ LQ RXU SURJUDP :H NQRZ WKDW ZH¦OO KDYH DQ LQWHJHU DV LQSXW DQG D VWULQJ DV RXWSXW EXW ZH¦OO OHDYH WKH H[DFW WUDQVIRUPDWLRQ XS WR D EORFN REMHFW WKDW FDQ EH GLIIHUHQW HDFK WLPH RXU PHWKRG UXQV 7KLV PHWKRG WKHUHIRUH ZLOO DFFHSW DV SDUDPHWHUV ERWK WKH LQ WHJHU WR EH WUDQVIRUPHG DQG WKH EORFN WKDW ZLOO WUDQVIRUP LW )RU RXU EORFN REMHFW ZH¦OO XVH WKH VDPH intToString EORFN REMHFW WKDW ZH LPSOHPHQWHG HDUOLHU LQ ([DPSOH 1RZ ZH QHHG DQ 2EMHFWLYH & PHWKRG WKDW ZLOO DFFHSW DQ XQ VLJQHG LQWHJHU SDUDPHWHU DQG D EORFN REMHFW DV LWV SDUDPHWHU 7KH XQVLJQHG LQWHJHU SDUDPHWHU LV HDV\ EXW KRZ GR ZH WHOO RXU PHWKRG WKDW LW KDV WR DFFHSW D EORFN REMHFW RI WKH VDPH W\SH DV WKH intToString EORFN REMHFW" )LUVW ZH typedef WKH VLJQDWXUH RI WKH intToString EORFN REMHFW ZKLFK WHOOV WKH FRPSLOHU ZKDW SDUDPHWHUV RXU EORFN REMHFW VKRXOG DFFHSW typedef NSString* (^IntToStringConverter)(NSUInteger paramInteger);
7KLV typedef MXVW WHOOV WKH FRPSLOHU WKDW EORFN REMHFWV WKDW DFFHSW DQ LQWHJHU SDUDPHWHU DQG UHWXUQ D VWULQJ FDQ VLPSO\ EH UHSUHVHQWHG E\ DQ LGHQWLILHU QDPHG IntToString Converter 1RZ OHW¦V JR DKHDG DQG ZULWH RXU 2EMHFWLYH & PHWKRG WKDW DFFHSWV ERWK DQ LQWHJHU DQG D EORFN REMHFW RI W\SH IntToStringConverter - (NSString *) convertIntToString:(NSUInteger)paramInteger usingBlockObject:(IntToStringConverter)paramBlockObject{ return paramBlockObject(paramInteger); }
4 | Chapter 1: Introducing Block Objects
$OO ZH KDYH WR GR QRZ LV FDOO WKH convertIntToString: PHWKRG ZLWK RXU EORFN REMHFW RI FKRLFH ([DPSOH ([DPSOH &DOOLQJ WKH EORFN REMHFW LQ DQRWKHU PHWKRG - (void) doTheConversion{ NSString *result = [self convertIntToString:123 usingBlockObject:intToString]; NSLog(@"result = %@", result); }
1RZ WKDW ZH NQRZ VRPHWKLQJ DERXW LQGHSHQGHQW EORFN REMHFWV OHW¦V WXUQ WR LQOLQH EORFN REMHFWV ,Q WKH doTheConversion PHWKRG ZH MXVW VDZ ZH SDVVHG WKH intTo String EORFN REMHFW DV WKH SDUDPHWHU WR WKH convertIntToString:usingBlockObject: PHWKRG :KDW LI ZH GLGQ¦W KDYH D EORFN REMHFW UHDG\ WR EH SDVVHG WR WKLV PHWKRG" :HOO WKDW ZRXOGQ¦W EH D SUREOHP $V PHQWLRQHG EHIRUH EORFN REMHFWV DUH ILUVW FODVV IXQFWLRQV DQG FDQ EH FRQVWUXFWHG DW UXQWLPH /HW¦V KDYH D ORRN DW DQ DOWHUQDWLYH LPSOHPHQWDWLRQ RI WKH doTheConversion PHWKRG ([DPSOH ([DPSOH ([DPSOH EORFN REMHFW GHILQHG DV IXQFWLRQ - (void) doTheConversion{ IntToStringConverter inlineConverter = ^(NSUInteger paramInteger){ NSString *result = [NSString stringWithFormat:@"%lu", (unsigned long)paramInteger]; return result; }; NSString *result = [self convertIntToString:123 usingBlockObject:inlineConverter]; NSLog(@"result = %@", result); }
&RPSDUH ([DPSOH WR WKH HDUOLHU ([DPSOH , KDYH UHPRYHG WKH LQLWLDO FRGH WKDW SURYLGHG WKH EORFN REMHFW¦V VLJQDWXUH ZKLFK FRQVLVWHG RI D QDPH DQG DUJXPHQW (^intToString)(NSUInteger) , OHIW DOO WKH UHVW RI WKH EORFN REMHFW LQWDFW ,W LV QRZ DQ DQRQ\PRXV REMHFW %XW WKLV GRHVQ¦W PHDQ , KDYH QR ZD\ WR UHIHU WR WKH EORFN REMHFW , DVVLJQ LW XVLQJ DQ HTXDO VLJQ WR D W\SH DQG D QDPH IntToStringConverter inline Converter 1RZ , FDQ XVH WKH GDWD W\SH WR HQIRUFH SURSHU XVH LQ PHWKRGV DQG XVH WKH QDPH WR DFWXDOO\ SDVV WKH EORFN REMHFW ,Q DGGLWLRQ WR FRQVWUXFWLQJ EORFN REMHFWV LQOLQH DV MXVW VKRZQ ZH FDQ FRQVWUXFW D EORFN REMHFW ZKLOH SDVVLQJ LW DV D SDUDPHWHU
Constructing Block Objects and Their Syntax | 5
- (void) doTheConversion{ NSString *result = [self convertIntToString:123 usingBlockObject:^NSString *(NSUInteger paramInteger) { NSString *result = [NSString stringWithFormat:@"%lu", (unsigned long)paramInteger]; return result; }]; NSLog(@"result = %@", result); }
&RPSDUH WKLV H[DPSOH ZLWK ([DPSOH %RWK PHWKRGV XVH D EORFN REMHFW WKURXJK WKH usingBlockObject V\QWD[ %XW ZKHUHDV WKH HDUOLHU YHUVLRQ UHIHUUHG WR D SUHYLRXVO\ GHFODUHG EORFN REMHFW E\ QDPH intToString WKLV RQH VLPSO\ FUHDWHV D EORFN REMHFW RQ WKH IO\ ,Q WKLV FRGH ZH FRQVWUXFWHG DQ LQOLQH EORFN REMHFW WKDW JHWV SDVVHG WR WKH convertIntToString:usingBlockObject: PHWKRG DV WKH VHFRQG SDUDPHWHU , EHOLHYH WKDW DW WKLV SRLQW \RX NQRZ HQRXJK DERXW EORFN REMHFWV WR EH DEOH WR PRYH WR PRUH LQWHUHVWLQJ GHWDLOV ZKLFK ZH¦OO EHJLQ ZLWK LQ WKH IROORZLQJ VHFWLRQ
Variables and Their Scope in Block Objects +HUH LV D EULHI VXPPDU\ RI ZKDW \RX PXVW NQRZ DERXW YDULDEOHV LQ EORFN REMHFWV Â&#x2021; /RFDO YDULDEOHV LQ EORFN REMHFWV ZRUN H[DFWO\ WKH VDPH DV LQ 2EMHFWLYH & PHWKRGV Â&#x2021; )RU LQOLQH EORFN REMHFWV ORFDO YDULDEOHV FRQVWLWXWH QRW RQO\ YDULDEOHV GHILQHG ZLWKLQ WKH EORFN EXW DOVR WKH YDULDEOHV WKDW KDYH EHHQ GHILQHG LQ WKH PHWKRG WKDW LPSOH PHQWV WKDW EORFN REMHFW ([DPSOHV ZLOO FRPH VKRUWO\
Â&#x2021; <RX FDQQRW UHIHU WR self LQ LQGHSHQGHQW EORFN REMHFWV LPSOHPHQWHG LQ DQ 2EMHFWLYH & FODVV ,I \RX QHHG WR DFFHVV self \RX PXVW SDVV WKDW REMHFW WR WKH EORFN REMHFW DV D SDUDPHWHU :H ZLOO VHH DQ H[DPSOH RI WKLV VRRQ Â&#x2021; <RX FDQ UHIHU WR self LQ DQ LQOLQH EORFN REMHFW RQO\ LI self LV SUHVHQW LQ WKH OH[LFDO VFRSH LQVLGH ZKLFK WKH EORFN REMHFW LV FUHDWHG Â&#x2021; )RU LQOLQH EORFN REMHFWV ORFDO YDULDEOHV WKDW DUH GHILQHG LQVLGH WKH EORFN REMHFW¦V LPSOHPHQWDWLRQ FDQ EH UHDG IURP DQG ZULWWHQ WR ,Q RWKHU ZRUGV WKH EORFN REMHFW KDV UHDG ZULWH DFFHVV WR YDULDEOHV GHILQHG LQVLGH WKH EORFN REMHFW¦V ERG\ Â&#x2021; )RU LQOLQH EORFN REMHFWV YDULDEOHV ORFDO WR WKH 2EMHFWLYH & PHWKRG WKDW LPSOHPHQWV WKDW EORFN FDQ RQO\ EH UHDG IURP QRW ZULWWHQ WR 7KHUH LV DQ H[FHSWLRQ WKRXJK D EORFN REMHFW FDQ ZULWH WR VXFK YDULDEOHV LI WKH\ DUH GHILQHG ZLWK WKH __block VWRUDJH W\SH :H ZLOO VHH DQ H[DPSOH RI WKLV DV ZHOO
6 | Chapter 1: Introducing Block Objects
Â&#x2021; 6XSSRVH \RX KDYH DQ REMHFW RI W\SH NSObject DQG LQVLGH WKDW REMHFW¦V LPSOHPHQ WDWLRQ \RX DUH XVLQJ D EORFN REMHFW LQ FRQMXQFWLRQ ZLWK *&' ,QVLGH WKLV EORFN REMHFW \RX ZLOO KDYH UHDG ZULWH DFFHVV WR GHFODUHG SURSHUWLHV RI WKDW NSObject LQVLGH ZKLFK \RXU EORFN LV LPSOHPHQWHG Â&#x2021; <RX FDQ DFFHVV GHFODUHG SURSHUWLHV RI \RXU NSObject LQVLGH LQGHSHQGHQW EORFN RE MHFWV RQO\ LI \RX XVH WKH VHWWHU DQG JHWWHU PHWKRGV RI WKHVH SURSHUWLHV <RX FDQQRW DFFHVV GHFODUHG SURSHUWLHV RI DQ REMHFW XVLQJ GRW QRWDWLRQ LQVLGH DQ LQGHSHQGHQW EORFN REMHFW /HW¦V ILUVW VHH KRZ ZH FDQ XVH YDULDEOHV WKDW DUH ORFDO WR WKH LPSOHPHQWDWLRQ RI WZR EORFN REMHFWV 2QH LV DQ LQOLQH EORFN REMHFW DQG WKH RWKHU DQ LQGHSHQGHQW EORFN REMHFW void (^independentBlockObject)(void) = ^(void){ NSInteger localInteger = 10; NSLog(@"local integer = %lu", (unsigned long)localInteger); localInteger = 20; NSLog(@"local integer = %lu", (unsigned long)localInteger); };
,QYRNLQJ WKLV EORFN REMHFW WKH YDOXHV ZH DVVLJQHG DUH SULQWHG WR WKH FRQVROH ZLQGRZ local integer = 10 local integer = 20
6R IDU VR JRRG 1RZ OHW¦V KDYH D ORRN DW LQOLQH EORFN REMHFWV DQG YDULDEOHV WKDW DUH ORFDO WR WKHP - (void) simpleMethod{ NSUInteger outsideVariable = 10; NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"obj1", @"obj2", nil]; [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSUInteger insideVariable = 20; NSLog(@"Outside variable = %lu", (unsigned long)outsideVariable); NSLog(@"Inside variable = %lu", (unsigned long)insideVariable); /* Return value for our block object */ return NSOrderedSame; }]; [array release]; }
Variables and Their Scope in Block Objects | 7
7KH sortUsingComparator: LQVWDQFH PHWKRG RI NSMutableArray DWWHPSWV WR VRUW D PXWDEOH DUUD\ 7KH JRDO RI WKLV H[DPSOH FRGH LV MXVW WR GHP RQVWUDWH WKH XVH RI ORFDO YDULDEOHV VR \RX GRQ¦W KDYH WR NQRZ ZKDW WKLV PHWKRG DFWXDOO\ GRHV
7KH EORFN REMHFW FDQ UHDG DQG ZULWH LWV RZQ insideVariable ORFDO YDULDEOH +RZHYHU WKH EORFN REMHFW KDV UHDG RQO\ DFFHVV WR WKH outsideVariable YDULDEOH E\ GHIDXOW ,Q RUGHU WR DOORZ WKH EORFN REMHFW WR ZULWH WR outsideVariable ZH PXVW SUHIL[ outside Variable ZLWK WKH __block VWRUDJH W\SH - (void) simpleMethod{ __block NSUInteger outsideVariable = 10; NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"obj1", @"obj2", nil]; [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSUInteger insideVariable = 20; outsideVariable = 30; NSLog(@"Outside variable = %lu", (unsigned long)outsideVariable); NSLog(@"Inside variable = %lu", (unsigned long)insideVariable); /* Return value for our block object */ return NSOrderedSame; }]; [array release]; }
$FFHVVLQJ self LQ LQOLQH EORFN REMHFWV LV ILQH DV ORQJ DV self LV GHILQHG LQ WKH OH[LFDO VFRSH LQVLGH ZKLFK WKH LQOLQH EORFN REMHFW LV FUHDWHG )RU LQVWDQFH LQ WKLV H[DPSOH WKH EORFN REMHFW ZLOO EH DEOH WR DFFHVV self VLQFH simpleMethod LV DQ LQVWDQFH PHWKRG RI DQ 2EMHFWLYH & FODVV - (void) simpleMethod{ NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"obj1", @"obj2", nil]; [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSLog(@"self = %@", self); /* Return value for our block object */ return NSOrderedSame;
8 | Chapter 1: Introducing Block Objects
}]; [array release]; }
<RX FDQQRW ZLWKRXW D FKDQJH LQ \RXU EORFN REMHFW¦V LPSOHPHQWDWLRQ DFFHVV self LQ DQ LQGHSHQGHQW EORFN REMHFW $WWHPSWLQJ WR FRPSLOH WKLV FRGH ZLOO JLYH \RX D FRPSLOH WLPH HUURU void (^incorrectBlockObject)(void) = ^{ NSLog(@"self = %@", self); /* self is undefined here */ };
,I \RX ZDQW WR DFFHVV self LQ DQ LQGHSHQGHQW EORFN REMHFW VLPSO\ SDVV WKH REMHFW WKDW self UHSUHVHQWV DV D SDUDPHWHU WR \RXU EORFN REMHFW void (^correctBlockObject)(id) = ^(id self){ NSLog(@"self = %@", self); }; - (void) callCorrectBlockObject{ correctBlockObject(self); }
<RX GRQ¦W KDYH WR DVVLJQ WKH QDPH self WR WKLV SDUDPHWHU <RX FDQ VLP SO\ FDOO WKLV SDUDPHWHU DQ\WKLQJ HOVH +RZHYHU LI \RX FDOO WKLV SDUDPHWHU self \RX FDQ VLPSO\ JUDE \RXU EORFN REMHFW¦V FRGH ODWHU DQG SODFH LW LQ DQ 2EMHFWLYH & PHWKRG¦V LPSOHPHQWDWLRQ ZLWKRXW KDYLQJ WR FKDQJH HY HU\ LQVWDQFH RI \RXU YDULDEOH¦V QDPH WR self IRU LW WR EH XQGHUVWRRG E\ WKH FRPSLOHU
/HW¦V KDYH D ORRN DW GHFODUHG SURSHUWLHV DQG KRZ EORFN REMHFWV FDQ DFFHVV WKHP )RU LQOLQH EORFN REMHFWV \RX FDQ XVH GRW QRWDWLRQ WR UHDG IURP RU ZULWH WR GHFODUHG SURS HUWLHV RI self )RU LQVWDQFH OHW¦V VD\ ZH KDYH D GHFODUHG SURSHUW\ RI W\SH NSString FDOOHG stringProperty LQ RXU FODVV #import <UIKit/UIKit.h> @interface GCDAppDelegate : NSObject <UIApplicationDelegate> { @protected NSString *stringProperty; } @property (nonatomic, retain) NSString
*stringProperty;
@end
Variables and Their Scope in Block Objects | 9
1RZ ZH FDQ VLPSO\ DFFHVV WKLV SURSHUW\ LQ DQ LQOLQH EORFN REMHFW OLNH VR #import "GCDAppDelegate.h" @implementation GCDAppDelegate @synthesize stringProperty; - (void) simpleMethod{ NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"obj1", @"obj2", nil]; [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSLog(@"self = %@", self); self.stringProperty = @"Block Objects"; NSLog(@"String property = %@", self.stringProperty); /* Return value for our block object */ return NSOrderedSame; }]; [array release]; } - (void) dealloc{ [stringProperty release]; [super dealloc]; } @end
,Q DQ LQGHSHQGHQW EORFN REMHFW KRZHYHU \RX FDQQRW XVH GRW QRWDWLRQ WR UHDG IURP RU ZULWH WR D GHFODUHG SURSHUW\ void (^correctBlockObject)(id) = ^(id self){ NSLog(@"self = %@", self); /* Should use setter method instead of this */ self.stringProperty = @"Block Objects"; /* Compile-time Error */ /* Should use getter method instead of this */ NSLog(@"self.stringProperty = %@", self.stringProperty); /* Compile-time Error */ };
,QVWHDG RI GRW QRWDWLRQ LQ WKLV VFHQDULR XVH WKH JHWWHU DQG WKH VHWWHU PHWKRGV RI WKLV V\QWKHVL]HG SURSHUW\ 10 | Chapter 1: Introducing Block Objects
void (^correctBlockObject)(id) = ^(id self){ NSLog(@"self = %@", self); /* This will work fine */ [self setStringProperty:@"Block Objects"]; /* This will work fine as well */ NSLog(@"self.stringProperty = %@", [self stringProperty]); };
:KHQ LW FRPHV WR LQOLQH EORFN REMHFWV WKHUH LV RQH YHU\ LPSRUWDQW UXOH WKDW \RX KDYH WR UHPHPEHU LQOLQH EORFN REMHFWV FRS\ WKH YDOXH IRU WKH YDULDEOHV LQ WKHLU OH[LFDO VFRSH ,I \RX GRQ¦W XQGHUVWDQG ZKDW WKDW PHDQV GRQ¦W ZRUU\ /HW¦V KDYH D ORRN DW DQ H[DPSOH typedef void (^BlockWithNoParams)(void); - (void) scopeTest{ NSUInteger integerValue = 10; /*************** Definition of internal block object ***************/ BlockWithNoParams myBlock = ^{ NSLog(@"Integer value inside the block = %lu", (unsigned long)integerValue); }; /*************** End definition of internal block object ***************/ integerValue = 20; /* Call the block here after changing the value of the integerValue variable */ myBlock(); NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue); }
:H DUH GHFODULQJ DQ LQWHJHU ORFDO YDULDEOH DQG LQLWLDOO\ DVVLJQLQJ WKH YDOXH RI WR LW :H WKHQ LPSOHPHQW RXU EORFN REMHFW EXW GRQ¦W FDOO WKH EORFN REMHFW \HW $IWHU WKH EORFN REMHFW LV LPSOHPHQWHG ZH VLPSO\ FKDQJH WKH YDOXH RI WKH ORFDO YDULDEOH WKDW WKH EORFN REMHFW ZLOO ODWHU WU\ WR UHDG ZKHQ ZH FDOO LW 5LJKW DIWHU FKDQJLQJ WKH ORFDO YDULDEOH¦V YDOXH WR ZH FDOO WKH EORFN REMHFW <RX ZRXOG H[SHFW WKH EORFN REMHFW WR SULQW WKH YDOXH IRU WKH YDULDEOH EXW LW ZRQ¦W ,W ZLOO SULQW DV \RX FDQ VHH KHUH Integer value inside the block = 10 Integer value outside the block = 20
:KDW¦V KDSSHQLQJ KHUH LV WKDW WKH EORFN REMHFW LV NHHSLQJ D UHDG RQO\ FRS\ RI WKH integerValue YDULDEOH IRU LWVHOI ULJKW ZKHUH WKH EORFN LV LPSOHPHQWHG <RX PLJKW EH WKLQNLQJ ZK\ LV WKH EORFN REMHFW FDSWXULQJ D UHDG RQO\ YDOXH RI WKH ORFDO YDULDEOH
Variables and Their Scope in Block Objects | 11
integerValue" 7KH DQVZHU LV VLPSOH DQG ZH¦YH DOUHDG\ OHDUQHG LW LQ WKLV VHFWLRQ 8QOHVV SUHIL[HG ZLWK VWRUDJH W\SH __block ORFDO YDULDEOHV LQ WKH OH[LFDO VFRSH RI D EORFN REMHFW
DUH MXVW SDVVHG WR WKH EORFN REMHFW DV UHDG RQO\ YDULDEOHV 7KHUHIRUH WR FKDQJH WKLV EHKDYLRU ZH FRXOG FKDQJH WKH LPSOHPHQWDWLRQ RI RXU scopeTest PHWKRG WR SUHIL[ WKH integerValue YDULDEOH ZLWK __block VWRUDJH W\SH OLNH VR - (void) scopeTest{ __block NSUInteger integerValue = 10; /*************** Definition of internal block object ***************/ BlockWithNoParams myBlock = ^{ NSLog(@"Integer value inside the block = %lu", (unsigned long)integerValue); }; /*************** End definition of internal block object ***************/ integerValue = 20; /* Call the block here after changing the value of the integerValue variable */ myBlock(); NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue); }
1RZ LI ZH JHW WKH UHVXOWV IURP WKH FRQVROH ZLQGRZ DIWHU WKH scopeTest PHWKRG LV FDOOHG ZH ZLOO VHH WKLV Integer value inside the block = 20 Integer value outside the block = 20
7KLV VHFWLRQ VKRXOG KDYH JLYHQ \RX VXIILFLHQW LQIRUPDWLRQ DERXW XVLQJ YDULDEOHV ZLWK EORFN REMHFWV , VXJJHVW WKDW \RX ZULWH D IHZ EORFN REMHFWV DQG XVH YDULDEOHV LQVLGH WKHP DVVLJQLQJ WR WKHP DQG UHDGLQJ IURP WKHP WR JHW D EHWWHU XQGHUVWDQGLQJ RI KRZ EORFN REMHFWV XVH YDULDEOHV .HHS FRPLQJ EDFN WR WKLV VHFWLRQ LI \RX IRUJHW WKH UXOHV WKDW JRYHUQ YDULDEOH DFFHVV LQ EORFN REMHFWV
Invoking Block Objects :H¦YH VHHQ H[DPSOHV RI LQYRNLQJ EORFN REMHFWV LQ £&RQVWUXFWLQJ %ORFN 2EMHFWV DQG 7KHLU 6\QWD[¤ RQ SDJH DQG £9DULDEOHV DQG 7KHLU 6FRSH LQ %ORFN 2E MHFWV¤ RQ SDJH 7KLV VHFWLRQ FRQWDLQV PRUH FRQFUHWH H[DPSOHV ,I \RX KDYH DQ LQGHSHQGHQW EORFN REMHFW \RX FDQ VLPSO\ LQYRNH LW MXVW OLNH \RX ZRXOG LQYRNH D & IXQFWLRQ void (^simpleBlock)(NSString *) = ^(NSString *paramString){ /* Implement the block object here and use the paramString parameter */
12 | Chapter 1: Introducing Block Objects
}; - (void) callSimpleBlock{ simpleBlock(@"O'Reilly"); }
,I \RX ZDQW WR LQYRNH DQ LQGHSHQGHQW EORFN REMHFW ZLWKLQ DQRWKHU LQGHSHQGHQW EORFN REMHFW IROORZ WKH VDPH LQVWUXFWLRQV E\ LQYRNLQJ WKH QHZ EORFN REMHFW MXVW DV \RX ZRXOG LQYRNH D & PHWKRG /*************** Definition of first block object ***************/ NSString *(^trimString)(NSString *) = ^(NSString *inputString){ NSString *result = [inputString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return result; }; /*************** End definition of first block object ***************/ /*************** Definition of second block object ***************/ NSString *(^trimWithOtherBlock)(NSString *) = ^(NSString *inputString){ return trimString(inputString); }; /*************** End definition of second block object ***************/ - (void) callTrimBlock{ NSString *trimmedString = trimWithOtherBlock(@" NSLog(@"Trimmed string = %@", trimmedString);
O'Reilly
");
}
,Q WKLV H[DPSOH JR DKHDG DQG LQYRNH WKH callTrimBlock 2EMHFWLYH & PHWKRG [self callTrimBlock];
7KH callTrimBlock PHWKRG ZLOO FDOO WKH trimWithOtherBlock EORFN REMHFW DQG WKH trim WithOtherBlock EORFN REMHFW ZLOO FDOO WKH trimString EORFN REMHFW LQ RUGHU WR WULP WKH JLYHQ VWULQJ 7ULPPLQJ D VWULQJ LV DQ HDV\ WKLQJ WR GR DQG FDQ EH GRQH LQ RQH OLQH RI FRGH EXW WKLV H[DPSOH FRGH VKRZV KRZ \RX FDQ FDOO EORFN REMHFWV ZLWKLQ EORFN REMHFWV ,Q &KDSWHU \RX ZLOO OHDUQ KRZ WR LQYRNH EORFN REMHFWV XVLQJ *UDQG &HQWUDO 'LVSDWFK V\QFKURQRXVO\ RU DV\QFKURQRXVO\ WR XQOHDVK WKH UHDO SRZHU RI EORFN REMHFWV
Memory Management for Block Objects L26 DSSV UXQ LQ D UHIHUHQFH FRXQWHG HQYLURQPHQW 7KDW PHDQV HYHU\ REMHFW KDV D UHWDLQ FRXQW WR HQVXUH WKH 2EMHFWLYH & UXQWLPH NHHSV LW DV ORQJ DV LW PLJKW EH XVHG DQG JHWV ULG RI LW ZKHQ QR RQH FDQ XVH LW DQ\PRUH <RX FDQ WKLQN RI D UHWDLQ FRXQW DV WKH QXPEHU RI OHDVKHV RQ DQ DQLPDO $V ORQJ DV WKHUH LV DW OHDVW RQH OHDVK WKH DQLPDO ZLOO VWD\ ZKHUH Memory Management for Block Objects | 13
LW LV ,I WKHUH DUH WZR OHDVKHV WKH DQLPDO KDV WR EH XQOHDVKHG WZLFH WR EH UHOHDVHG $V VRRQ DV DOO OHDVKHV DUH UHOHDVHG WKH DQLPDO LV IUHH 6XEVWLWXWH DOO RFFXUUHQFHV RI DQL PDO ZLWK REMHFW LQ WKH SUHFHGLQJ VHQWHQFHV DQG \RX ZLOO XQGHUVWDQG KRZ D UHIHUHQFH FRXQWHG HQYLURQPHQW ZRUNV :KHQ ZH DOORFDWH DQ REMHFW LQ L26 WKH UHWDLQ FRXQW RI WKDW REMHFW EHFRPHV (YHU\ DOORFDWLRQ KDV WR EH SDLUHG ZLWK D UHOHDVH FDOO LQYRNHG RQ WKH REMHFW WR GHFUHPHQW WKH UHOHDVH FRXQW E\ ,I \RX ZDQW WR NHHS WKH REMHFW DURXQG LQ PHPRU\ \RX KDYH WR PDNH VXUH \RX KDYH UHWDLQHG WKDW REMHFW VR WKDW LWV UHWDLQ FRXQW LV LQFUHPHQWHG E\ WKH UXQWLPH )RU PRUH LQIRUPDWLRQ DERXW PHPRU\ PDQDJHPHQW LQ L26 DSSV SOHDVH UHIHU WR L26 3URJUDPPLQJ &RRNERRN 2¦5HLOO\
%ORFN REMHFWV DUH REMHFWV DV ZHOO VR WKH\ DOVR FDQ EH FRSLHG UHWDLQHG DQG UHOHDVHG :KHQ ZULWLQJ DQ L26 DSS \RX FDQ VLPSO\ WUHDW EORFN REMHFWV DV QRUPDO REMHFWV DQG UHWDLQ DQG UHOHDVH WKHP DV \RX ZRXOG ZLWK RWKHU REMHFWV typedef NSString* (^StringTrimmingBlockObject)(NSString *paramString); NSString* (^trimString)(NSString *) = ^(NSString *paramString){ NSString *result = nil; result = [paramString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return result; }; - (void) callTrimString{ StringTrimmingBlockObject trimStringCopy = Block_copy(trimString); NSString *trimmedString = trimStringCopy(@"
O'Reilly
");
NSLog(@"Trimmed string = %@", trimmedString); Block_release(trimStringCopy); }
8VH Block_copy RQ D EORFN REMHFW WR GHFODUH RZQHUVKLS RI WKDW EORFN REMHFW IRU WKH SHULRG RI WLPH \RX ZLVK WR XVH LW :KLOH UHWDLQLQJ RZQHUVKLS RYHU D EORFN REMHFW \RX FDQ EH VXUH WKDW L26 ZLOO QRW GLVSRVH RI WKDW EORFN REMHFW DQG LWV PHPRU\ 2QFH \RX DUH GRQH ZLWK WKDW EORFN REMHFW \RX PXVW UHOHDVH RZQHUVKLS XVLQJ Block_release ,I \RX DUH XVLQJ EORFN REMHFWV LQ \RXU 0DF 26 ; DSSV \RX VKRXOG IROORZ WKH VDPH UXOHV ZKHWKHU \RX DUH ZULWLQJ \RXU DSS LQ D JDUEDJH FROOHFWHG RU D UHIHUHQFH FRXQWLQJ
14 | Chapter 1: Introducing Block Objects
HQYLURQPHQW +HUH LV WKH VDPH H[DPSOH FRGH IURP L26 ZULWWHQ IRU 0DF 26 ; <RX FDQ FRPSLOH LW ZLWK DQG ZLWKRXW JDUEDJH FROOHFWLRQ HQDEOHG IRU \RXU SURMHFW typedef NSString* (^StringTrimmingBlockObject)(NSString *paramString); NSString* (^trimString)(NSString *) = ^(NSString *paramString){ NSString *result = nil; result = [paramString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return result; }; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { StringTrimmingBlockObject trimmingBlockObject = Block_copy(trimString); NSString *trimmedString = trimmingBlockObject(@"
O'Reilly
");
NSLog(@"Trimmed string = %@", trimmedString); Block_release(trimmingBlockObject); }
,Q L26 \RX FDQ DOVR XVH DXWRUHOHDVH EORFN REMHFWV OLNH VR NSString* (^trimString)(NSString *) = ^(NSString *paramString){ NSString *result = nil; result = [paramString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return result; }; - (id) autoreleaseTrimStringBlockObject{ return [trimString autorelease]; }
<RX FDQ DOVR GHILQH GHFODUHG SURSHUWLHV WKDW KROG D FRS\ RI D EORFN REMHFW +HUH LV WKH K ILOH RI RXU REMHFW WKDW GHFODUHV D SURSHUW\ nonatomic, copy IRU D EORFN REMHFW #import <UIKit/UIKit.h> typedef NSString* (^StringTrimmingBlockObject)(NSString *paramString); @interface GCDAppDelegate : NSObject <UIApplicationDelegate> { @protected StringTrimmingBlockObject trimmingBlock;
Memory Management for Block Objects | 15
} @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, copy) StringTrimmingBlockObject trimmingBlock; @end
7KLV FRGH LV ZULWWHQ LQVLGH WKH DSSOLFDWLRQ GHOHJDWH RI D VLPSOH XQLYHUVDO L26 DSS
1RZ OHW¦V JR DKHDG DQG LPSOHPHQW RXU DSSOLFDWLRQ¦V GHOHJDWH REMHFW #import "GCDAppDelegate.h" @implementation GCDAppDelegate @synthesize window=_window; @synthesize trimmingBlock; NSString* (^trimString)(NSString *) = ^(NSString *paramString){ NSString *result = nil; result = [paramString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; return result; }; - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.trimmingBlock = trimString; NSString *trimmedString = self.trimmingBlock(@"
O'Reilly
NSLog(@"Trimmed string = %@", trimmedString);
");
}
// Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES;
- (void)dealloc{ [trimmingBlock release]; [_window release]; [super dealloc]; } @end
16 | Chapter 1: Introducing Block Objects
:KDW ZH ZDQW WR DFKLHYH LQ WKLV H[DPSOH LV ILUVW WR GHFODUH RZQHUVKLS RYHU WKH trim String EORFN REMHFW LQ RXU DSSOLFDWLRQ GHOHJDWH DQG WKHQ WR XVH WKDW EORFN REMHFW WR WULP D VLQJOH VWULQJ RII LWV ZKLWHVSDFHV 7KH trimmingBlock SURSHUW\ LV GHFODUHG DV nonatomic 7KLV PHDQV WKDW WKLV SURSHUW\¦V WKUHDG VDIHQHVV PXVW EH PDQDJHG E\ XV DQG ZH VKRXOG PDNH VXUH WKLV SURSHUW\ ZRQ¦W JHW DFFHVVHG IURP PRUH WKDQ RQH WKUHDG DW D WLPH :H ZRQ¦W UHDOO\ KDYH WR FDUH DERXW WKLV DW WKH PRPHQW DV ZH DUH QRW GRLQJ DQ\WKLQJ IDQF\ ZLWK WKUHDGV ULJKW QRZ 7KLV SURSHUW\ LV DOVR GHILQHG DV copy ZKLFK WHOOV WKH UXQWLPH WR FDOO WKH copy PHWKRG RQ DQ\ REMHFW LQFOXGLQJ EORFN REMHFWV ZKHQ ZH DVVLJQ WKRVH REMHFWV WR WKLV SURSHUW\ DV RSSRVHG WR UHWDLQLQJ WKRVH REMHFWV E\ FDOOLQJ WKH retain PHWKRG RQ WKHP
$V ZH VDZ EHIRUH WKH trimString EORFN REMHFW DFFHSWV D VWULQJ DV LWV SDUDPHWHU WULPV WKLV VWULQJ DQG UHWXUQV LW WR WKH FDOOHU ,QVLGH WKH application:didFinishLaunch ingWithOptions: LQVWDQFH PHWKRG RI RXU DSSOLFDWLRQ GHOHJDWH ZH DUH VLPSO\ XVLQJ GRW QRWDWLRQ WR DVVLJQ WKH trimString EORFN REMHFW WR WKH trimmingBlock GHFODUHG SURSHUW\ 7KLV PHDQV WKDW WKH UXQWLPH ZLOO LPPHGLDWHO\ FDOO WKH Block_copy RQ WKH trimString EORFN REMHFW DQG DVVLJQ WKH UHVXOWLQJ YDOXH WR WKH trimmingBlock GHFODUHG SURSHUW\ )URP WKLV SRLQW RQ XQWLO ZH UHOHDVH WKH EORFN REMHFW ZH KDYH D FRS\ RI LW LQ WKH trimmingBlock GHFODUHG SURSHUW\ 1RZ ZH FDQ XVH WKH trimmingBlock GHFODUHG SURSHUW\ WR LQYRNH WKH trimString EORFN REMHFW DV VKRZQ LQ WKH IROORZLQJ FRGH NSString *trimmedString = self.trimmingBlock(@"
O'Reilly
");
2QFH ZH DUH GRQH LQ WKH dealloc LQVWDQFH PHWKRG RI RXU REMHFW ZH ZLOO UHOHDVH WKH trimmingBlock GHFODUHG SURSHUW\ E\ FDOOLQJ LWV release PHWKRG :LWK PRUH LQVLJKW LQWR EORFN REMHFWV DQG KRZ WKH\ PDQDJH WKHLU YDULDEOHV DQG PHPRU\ LW LV ILQDOO\ WLPH WR PRYH WR &KDSWHU WR OHDUQ DERXW WKH ZRQGHU WKDW LV FDOOHG *UDQG &HQWUDO 'LVSDWFK :H ZLOO EH XVLQJ EORFN REMHFWV ZLWK *&' D ORW VR PDNH VXUH \RX KDYH UHDOO\ XQGHUVWRRG WKH PDWHULDO LQ WKLV FKDSWHU EHIRUH PRYLQJ RQ WR WKH QH[W
Memory Management for Block Objects | 17
CHAPTER 2
Programming Grand Central Dispatch
*UDQG &HQWUDO 'LVSDWFK RU *&' IRU VKRUW LV D ORZ OHYHO & $3, WKDW ZRUNV ZLWK EORFN REMHFWV 7KH UHDO XVH IRU *&' LV WR GLVSDWFK WDVNV WR PXOWLSOH FRUHV ZLWKRXW PDNLQJ \RX WKH SURJUDPPHU ZRUU\ DERXW ZKLFK FRUH LV H[HFXWLQJ ZKLFK WDVN 2Q 0DF 26 ; PXOWLFRUH GHYLFHV LQFOXGLQJ ODSWRSV KDYH EHHQ DYDLODEOH WR XVHUV IRU TXLWH VRPH WLPH :LWK WKH LQWURGXFWLRQ RI PXOWLFRUH GHYLFHV VXFK DV WKH L3DG SURJUDPPHUV FDQ ZULWH DPD]LQJ PXOWLFRUH DZDUH PXOWLWKUHDGHG DSSV IRU L26 6HH WKH SUHIDFH IRU PRUH EDFN JURXQG RQ WKH LPSRUWDQFH RI PXOWLFRUHV ,Q &KDSWHU ZH OHDUQHG KRZ WR XVH EORFN REMHFWV ,I \RX KDYH QRW UHDG WKDW FKDSWHU , VWURQJO\ VXJJHVW WKDW \RX GR VWUDLJKW DZD\ DV *&' UHOLHV KHDYLO\ RQ EORFN REMHFWV DQG WKHLU G\QDPLF QDWXUH ,Q WKLV FKDSWHU ZH ZLOO OHDUQ DERXW UHDOO\ IXQ DQG LQWHUHVWLQJ WKLQJV WKDW SURJUDPPHUV FDQ DFKLHYH ZLWK *&' LQ L26 DQG 0DF 26 ;
Short Introduction to Grand Central Dispatch $W WKH KHDUW RI *&' DUH GLVSDWFK TXHXHV 'LVSDWFK TXHXHV DV ZH ZLOO VHH LQ £'LIIHUHQW 7\SHV RI 'LVSDWFK 4XHXHV¤ RQ SDJH DUH SRROV RI WKUHDGV PDQDJHG E\ *&' RQ WKH KRVW RSHUDWLQJ V\VWHP ZKHWKHU LW LV L26 RU 0DF 26 ; <RX ZLOO QRW EH ZRUNLQJ ZLWK WKHVH WKUHDGV GLUHFWO\ <RX ZLOO MXVW ZRUN ZLWK GLVSDWFK TXHXHV GLVSDWFKLQJ WDVNV WR WKHVH TXHXHV DQG DVNLQJ WKH TXHXHV WR LQYRNH \RXU WDVNV *&' RIIHUV VHYHUDO RSWLRQV IRU UXQQLQJ WDVNV V\QFKURQRXVO\ DV\QFKURQRXVO\ DIWHU D FHUWDLQ GHOD\ HWF 7R VWDUW XVLQJ *&' LQ \RXU DSSV \RX GRQ¦W KDYH WR LPSRUW DQ\ VSHFLDO OLEUDU\ LQWR \RXU SURMHFW $SSOH KDV DOUHDG\ LQFRUSRUDWHG *&' LQWR YDULRXV IUDPHZRUNV LQFOXGLQJ &RUH )RXQGDWLRQ DQG &RFRD &RFRD 7RXFK $OO PHWKRGV DQG GDWD W\SHV DYDLODEOH LQ *&' VWDUW ZLWK D GLVSDWFKB NH\ZRUG )RU LQVWDQFH dispatch_async DOORZV \RX WR GLVSDWFK D WDVN RQ D TXHXH IRU DV\QFKURQRXV H[HFXWLRQ ZKHUHDV dispatch_after DOORZV \RX WR UXQ D EORFN RI FRGH DIWHU D JLYHQ GHOD\
19
7UDGLWLRQDOO\ SURJUDPPHUV KDG WR FUHDWH WKHLU RZQ WKUHDGV WR SHUIRUP WDVNV LQ SDUDOOHO )RU LQVWDQFH DQ L26 GHYHORSHU ZRXOG FUHDWH D WKUHDG VLPLODU WR WKLV WR SHUIRUP DQ RSHUDWLRQ WLPHV - (void) doCalculation{ /* Do your calculation here */ } - (void) calculationThreadEntry{ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSUInteger counter = 0; while ([[NSThread currentThread] isCancelled] == NO){ [self doCalculation]; counter++; if (counter >= 1000){ break; } } [pool release]; } - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ /* Start the thread */ [NSThread detachNewThreadSelector:@selector(calculationThreadEntry) toTarget:self withObject:nil]; // Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES; }
7KH SURJUDPPHU KDV WR VWDUW WKH WKUHDG PDQXDOO\ DQG WKHQ FUHDWH WKH UHTXLUHG VWUXFWXUH IRU WKH WKUHDG HQWU\ SRLQW DXWRUHOHDVH SRRO DQG WKUHDG¦V PDLQ ORRS :KHQ ZH ZULWH WKH VDPH FRGH ZLWK *&' ZH UHDOO\ ZRQ¦W KDYH WR GR PXFK
20 | Chapter 2: Programming Grand Central Dispatch
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); size_t numberOfIterations = 1000; dispatch_async(queue, ^(void) { dispatch_apply(numberOfIterations, queue, ^(size_t iteration){ /* Perform the operation here */ }); });
,Q WKLV FKDSWHU \RX ZLOO OHDUQ DOO WKHUH LV WR NQRZ DERXW *&' DQG KRZ WR XVH LW WR ZULWH PRGHUQ PXOWLWKUHDGHG DSSV IRU L26 DQG 0DF 26 ; WKDW ZLOO DFKLHYH EOD]LQJ SHUIRUP DQFH RQ PXOWLFRUH GHYLFHV VXFK DV WKH L3DG
Different Types of Dispatch Queues $V PHQWLRQHG LQ £6KRUW ,QWURGXFWLRQ WR *UDQG &HQWUDO 'LVSDWFK¤ RQ SDJH GLVSDWFK TXHXHV DUH SRROV RI WKUHDGV PDQDJHG E\ *&' :H ZLOO EH ZRUNLQJ ZLWK GLVSDWFK TXHXHV D ORW VR SOHDVH PDNH VXUH WKDW \RX IXOO\ XQGHUVWDQG WKH FRQFHSW EHKLQG WKHP 7KHUH DUH WKUHH W\SHV RI GLVSDWFK TXHXHV 0DLQ 4XHXH 7KLV TXHXH SHUIRUPV DOO LWV WDVNV RQ WKH PDLQ WKUHDG ZKLFK LV ZKHUH &RFRD DQG &RFRD 7RXFK UHTXLUH SURJUDPPHUV WR FDOO DOO 8, UHODWHG PHWKRGV 8VH WKH dispatch_get_main_queue IXQFWLRQ WR UHWULHYH WKH KDQGOH WR WKH PDLQ TXHXH &RQFXUUHQW 4XHXHV 7KHVH DUH TXHXHV WKDW \RX FDQ UHWULHYH IURP *&' LQ RUGHU WR H[HFXWH DV\QFKURQRXV RU V\QFKURQRXV WDVNV 0XOWLSOH FRQFXUUHQW TXHXHV FDQ EH H[HFXWLQJ PXOWLSOH WDVNV LQ SDUDOOHO ZLWKRXW EUHDNLQJ D VZHDW 1R PRUH WKUHDG PDQDJHPHQW \LSSHH 8VH WKH dispatch_get_global_queue IXQFWLRQ WR UHWULHYH WKH KDQGOH WR D FRQFXUUHQW TXHXH 6HULDO 4XHXHV 7KHVH DUH TXHXHV WKDW QR PDWWHU ZKHWKHU \RX VXEPLW V\QFKURQRXV RU DV\QFKUR QRXV WDVNV WR WKHP ZLOO DOZD\V H[HFXWH WKHLU WDVNV LQ D ILUVW LQ ILUVW RXW ),)2
IDVKLRQ PHDQLQJ WKDW WKH\ FDQ RQO\ H[HFXWH RQH EORFN REMHFW DW D WLPH +RZHYHU WKH\ GR QRW UXQ RQ WKH PDLQ WKUHDG DQG WKHUHIRUH DUH SHUIHFW IRU D VHULHV RI WDVNV WKDW KDYH WR EH H[HFXWHG LQ VWULFW RUGHU ZLWKRXW EORFNLQJ WKH PDLQ WKUHDG 8VH WKH dispatch_queue_create IXQFWLRQ WR FUHDWH D VHULDO TXHXH 2QFH \RX DUH GRQH ZLWK WKH TXHXH \RX PXVW UHOHDVH LW XVLQJ WKH dispatch_release IXQFWLRQ $W DQ\ PRPHQW GXULQJ WKH OLIHWLPH RI \RXU DSSOLFDWLRQ \RX FDQ XVH PXOWLSOH GLVSDWFK TXHXHV DW WKH VDPH WLPH <RXU V\VWHP KDV RQO\ RQH PDLQ TXHXH EXW \RX FDQ FUHDWH DV PDQ\ VHULDO GLVSDWFK TXHXHV DV \RX ZDQW ZLWKLQ UHDVRQ RI FRXUVH IRU ZKDWHYHU IXQF WLRQDOLW\ \RX UHTXLUH IRU \RXU DSS <RX FDQ DOVR UHWULHYH PXOWLSOH FRQFXUUHQW TXHXHV DQG GLVSDWFK \RXU WDVNV WR WKHP 7DVNV FDQ EH KDQGHG WR GLVSDWFK TXHXHV LQ WZR IRUPV
Different Types of Dispatch Queues | 21
EORFN REMHFWV RU & IXQFWLRQV DV ZH ZLOO VHH LQ £'LVSDWFKLQJ 7DVNV WR *UDQG &HQWUDO 'LVSDWFK¤ RQ SDJH
Dispatching Tasks to Grand Central Dispatch 7KHUH DUH WZR ZD\V WR VXEPLW WDVNV WR GLVSDWFK TXHXHV Â&#x2021; %ORFN 2EMHFWV VHH &KDSWHU
Â&#x2021; & IXQFWLRQV %ORFN REMHFWV DUH WKH EHVW ZD\ RI XWLOL]LQJ *&' DQG LWV HQRUPRXV SRZHU 6RPH *&' IXQFWLRQV KDYH EHHQ H[WHQGHG WR DOORZ SURJUDPPHUV WR XVH & IXQFWLRQV LQVWHDG RI EORFN REMHFWV +RZHYHU WKH WUXWK LV WKDW RQO\ D OLPLWHG VHW RI *&' IXQFWLRQV DOORZ SURJUDP PHUV WR XVH & IXQFWLRQV VR SOHDVH GR UHDG WKH FKDSWHU DERXW EORFN REMHFWV &KDS WHU EHIRUH SURFHHGLQJ ZLWK WKLV FKDSWHU & IXQFWLRQV WKDW KDYH WR EH VXSSOLHG WR YDULRXV *&' IXQFWLRQV VKRXOG EH RI W\SH dispatch_function_t ZKLFK LV GHILQHG DV IROORZV LQ WKH $SSOH OLEUDULHV typedef void (*dispatch_function_t)(void *);
6R LI ZH ZDQW WR FUHDWH D IXQFWLRQ QDPHG IRU LQVWDQFH myGCDFunction ZH ZRXOG KDYH WR LPSOHPHQW LW LQ WKLV ZD\ void myGCDFunction(void * paraContext){ /* Do the work here */ }
7KH paraContext SDUDPHWHU UHIHUV WR WKH FRQWH[W WKDW *&' DOORZV SUR JUDPPHUV WR SDVV WR WKHLU & IXQFWLRQV ZKHQ WKH\ GLVSDWFK WDVNV WR WKHP :H ZLOO OHDUQ DERXW WKLV VKRUWO\
%ORFN REMHFWV WKDW JHW SDVVHG WR *&' IXQFWLRQV GRQ¦W DOZD\V IROORZ WKH VDPH VWUXFWXUH 6RPH PXVW DFFHSW SDUDPHWHUV DQG VRPH VKRXOGQ¦W EXW QRQH RI WKH EORFN REMHFWV VXE PLWWHG WR *&' UHWXUQ D YDOXH ,Q WKH QH[W WKUHH VHFWLRQV \RX ZLOO OHDUQ KRZ WR VXEPLW WDVNV WR *&' IRU H[HFXWLRQ ZKHWKHU WKH\ DUH LQ WKH IRUP RI EORFN REMHFWV RU & IXQFWLRQV
Performing UI-Related Tasks 8, UHODWHG WDVNV KDYH WR EH SHUIRUPHG RQ WKH PDLQ WKUHDG VR WKH PDLQ TXHXH LV WKH RQO\ FDQGLGDWH IRU 8, WDVN H[HFXWLRQ LQ *&' :H FDQ XVH WKH dispatch_get_main_queue IXQFWLRQ WR JHW WKH KDQGOH WR WKH PDLQ GLVSDWFK TXHXH
22 | Chapter 2: Programming Grand Central Dispatch
7KHUH DUH WZR ZD\V RI GLVSDWFKLQJ WDVNV WR WKH PDLQ TXHXH %RWK DUH DV\QFKURQRXV OHWWLQJ \RXU SURJUDP FRQWLQXH HYHQ ZKHQ WKH WDVN LV QRW \HW H[HFXWHG dispatch_async IXQFWLRQ
([HFXWHV D EORFN REMHFW RQ D GLVSDWFK TXHXH dispatch_async_f IXQFWLRQ ([HFXWHV D & IXQFWLRQ RQ D GLVSDWFK TXHXH 7KH dispatch_sync PHWKRG FDQQRW EH FDOOHG RQ WKH PDLQ TXHXH EHFDXVH LW ZLOO EORFN WKH WKUHDG LQGHILQLWHO\ DQG FDXVH \RXU DSSOLFDWLRQ WR GHDG ORFN $OO WDVNV VXEPLWWHG WR WKH PDLQ TXHXH WKURXJK *&' PXVW EH VXE PLWWHG DV\QFKURQRXVO\
/HW¦V KDYH D ORRN DW XVLQJ WKH dispatch_async IXQFWLRQ ,W DFFHSWV WZR SDUDPHWHUV 'LVSDWFK TXHXH KDQGOH 7KH GLVSDWFK TXHXH RQ ZKLFK WKH WDVN KDV WR EH H[HFXWHG %ORFN REMHFW 7KH EORFN REMHFW WR EH VHQW WR WKH GLVSDWFK TXHXH IRU DV\QFKURQRXV H[HFXWLRQ +HUH LV DQ H[DPSOH 7KLV FRGH ZLOO GLVSOD\ DQ DOHUW LQ L26 WR WKH XVHU XVLQJ WKH PDLQ TXHXH dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^(void) { [[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"GCD", nil) message:NSLocalizedString(@"GCD is amazing!", nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil, nil] autorelease] show]; });
$V \RX¦YH QRWLFHG WKH dispatch_async *&' IXQFWLRQ KDV QR SDUDPHWHUV RU UHWXUQ YDOXH 7KH EORFN REMHFW WKDW LV VXEPLWWHG WR WKLV IXQFWLRQ PXVW JDWKHU LWV RZQ GDWD LQ RUGHU WR FRPSOHWH LWV WDVN ,Q WKH FRGH VQLSSHW WKDW ZH MXVW VDZ WKH DOHUW YLHZ KDV DOO WKH YDOXHV WKDW LW QHHGV WR ILQLVK LWV WDVN +RZHYHU WKLV PLJKW QRW DOZD\V EH WKH FDVH ,Q VXFK LQVWDQFHV \RX PXVW PDNH VXUH WKH EORFN REMHFW VXEPLWWHG WR *&' KDV DFFHVV LQ LWV VFRSH WR DOO WKH YDOXHV WKDW LW UHTXLUHV
5XQQLQJ WKLV DSS LQ L26 6LPXODWRU WKH XVHU ZLOO JHW UHVXOWV VLPLODU WR WKRVH VKRZQ LQ )LJXUH
Performing UI-Related Tasks | 23
)LJXUH $Q DOHUW GLVSOD\HG XVLQJ DV\QFKURQRXV *&' FDOOV
7KLV PLJKW QRW EH WKDW LPSUHVVLYH ,Q IDFW LW LV QRW LPSUHVVLYH DW DOO LI \RX WKLQN DERXW LW 6R ZKDW PDNHV WKH PDLQ TXHXH WUXO\ LQWHUHVWLQJ" 7KH DQVZHU LV VLPSOH ZKHQ \RX DUH JHWWLQJ WKH PD[LPXP SHUIRUPDQFH IURP *&' WR GR VRPH KHDY\ FDOFXODWLRQ RQ FRQFXUUHQW RU VHULDO WKUHDGV \RX PLJKW ZDQW WR GLVSOD\ WKH UHVXOWV WR \RXU XVHU RU PRYH D FRPSRQHQW RQ WKH VFUHHQ )RU WKDW \RX PXVW XVH WKH PDLQ TXHXH EHFDXVH LW LV 8, UHODWHG ZRUN 7KH IXQFWLRQV VKRZQ LQ WKLV VHFWLRQ DUH WKH RQO\ ZD\ WR JHW RXW RI D VHULDO RU D FRQFXUUHQW TXHXH ZKLOH VWLOO XWLOL]LQJ *&' WR XSGDWH \RXU 8, VR \RX FDQ LPDJLQH KRZ LPSRUWDQW LW LV ,QVWHDG RI VXEPLWWLQJ D EORFN REMHFW IRU H[HFXWLRQ RQ WKH PDLQ TXHXH \RX FDQ VXEPLW D & IXQFWLRQ REMHFW 6XEPLW DOO 8, UHODWHG & IXQFWLRQV IRU H[HFXWLRQ LQ *&' WR WKH dispatch_async_f IXQFWLRQ :H FDQ JHW WKH VDPH UHVXOWV DV ZH JRW LQ )LJXUH XVLQJ & IXQFWLRQV LQVWHDG RI EORFN REMHFWV ZLWK D IHZ DGMXVWPHQWV WR RXU FRGH $V PHQWLRQHG EHIRUH ZLWK WKH dispatch_async_f IXQFWLRQ ZH FDQ VXEPLW D SRLQWHU WR DQ DSSOLFDWLRQ GHILQHG FRQWH[W ZKLFK FDQ WKHQ EH XVHG E\ WKH & IXQFWLRQ WKDW JHWV FDOOHG 6R KHUH LV WKH SODQ OHW¦V FUHDWH D VWUXFWXUH WKDW KROGV YDOXHV VXFK DV DQ DOHUW YLHZ¦V WLWOH PHVVDJH DQG FDQFHO EXWWRQ¦V WLWOH :KHQ RXU DSS VWDUWV ZH ZLOO SXW DOO WKH YDOXHV LQ WKLV VWUXFWXUH DQG SDVV LW WR RXU & IXQFWLRQ WR GLVSOD\ +HUH LV KRZ ZH DUH GHILQLQJ RXU VWUXFWXUH 24 | Chapter 2: Programming Grand Central Dispatch
typedef struct{ char *title; char *message; char *cancelButtonTitle; } AlertViewData;
1RZ OHW¦V JR DQG LPSOHPHQW D & IXQFWLRQ WKDW ZH ZLOO ODWHU FDOO ZLWK *&' 7KLV & IXQFWLRQ VKRXOG H[SHFW D SDUDPHWHU RI W\SH void * ZKLFK ZH ZLOO WKHQ W\SHFDVW WR AlertViewData * ,Q RWKHU ZRUGV ZH H[SHFW WKH FDOOHU RI WKLV IXQFWLRQ WR SDVV XV D UHIHUHQFH WR WKH GDWD IRU RXU DOHUW YLHZ HQFDSVXODWHG LQVLGH WKH AlertViewData VWUXFWXUH void displayAlertView(void *paramContext){ AlertViewData *alertData = (AlertViewData *)paramContext; NSString *title = [NSString stringWithUTF8String:alertData->title]; NSString *message = [NSString stringWithUTF8String:alertData->message]; NSString *cancelButtonTitle = [NSString stringWithUTF8String:alertData->cancelButtonTitle]; [[[[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil, nil] autorelease] show]; free(alertData); }
7KH UHDVRQ ZH DUH freeLQJ WKH FRQWH[W SDVVHG WR XV LQ KHUH LQVWHDG RI LQ WKH FDOOHU LV WKDW WKH FDOOHU LV JRLQJ WR H[HFXWH WKLV & IXQFWLRQ DV\QFKUR QRXVO\ DQG FDQQRW NQRZ ZKHQ RXU & IXQFWLRQ ZLOO ILQLVK H[HFXWLQJ 7KHUHIRUH WKH FDOOHU KDV WR malloc HQRXJK VSDFH IRU WKH AlertViewData FRQWH[W DQG RXU displayAlertView & IXQFWLRQ KDV WR IUHH WKDW VSDFH
$QG QRZ OHW¦V FDOO WKH displayAlertView IXQFWLRQ RQ WKH PDLQ TXHXH DQG SDVV WKH FRQ WH[W WKH VWUXFWXUH WKDW KROGV WKH DOHUW YLHZ¦V GDWD WR LW
Performing UI-Related Tasks | 25
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ dispatch_queue_t mainQueue = dispatch_get_main_queue(); AlertViewData *context = (AlertViewData *) malloc(sizeof(AlertViewData)); if (context != NULL){ context->title = "GCD"; context->message = "GCD is amazing."; context->cancelButtonTitle = "OK"; dispatch_async_f(mainQueue, (void *)context, displayAlertView); }
}
// Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES;
,I \RX LQYRNH WKH currentThread FODVV PHWKRG RI WKH NSThread FODVV \RX ZLOO ILQG RXW WKDW WKH EORFN REMHFWV RU WKH & IXQFWLRQV \RX GLVSDWFK WR WKH PDLQ TXHXH DUH LQGHHG UXQQLQJ RQ WKH PDLQ WKUHDG - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^(void) { NSLog(@"Current thread = %@", [NSThread currentThread]); NSLog(@"Main thread = %@", [NSThread mainThread]); }); // Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES; }
7KH RXWSXW RI WKLV FRGH ZRXOG EH VLPLODU WR WKDW VKRZQ KHUH Current thread = <NSThread: 0x4b0e4e0>{name = (null), num = 1} Main thread = <NSThread: 0x4b0e4e0>{name = (null), num = 1}
1RZ WKDW \RX NQRZ KRZ WR SHUIRUP 8, UHODWHG WDVNV XVLQJ *&' LW LV WLPH ZH PRYHG WR RWKHU VXEMHFWV VXFK DV SHUIRUPLQJ WDVNV LQ SDUDOOHO XVLQJ FRQFXUUHQW TXHXHV VHH £3HUIRUPLQJ 1RQ 8, 5HODWHG 7DVNV 6\QFKURQRXVO\¤ RQ SDJH DQG £3HUIRUPLQJ 1RQ 8, 5HODWHG 7DVNV $V\QFKURQRXVO\¤ RQ SDJH DQG PL[LQJ RXU FRGH ZLWK 8, UHODWHG FRGH LI QHHG EH
26 | Chapter 2: Programming Grand Central Dispatch
Performing Non-UI-Related Tasks Synchronously 7KHUH DUH WLPHV ZKHQ \RX ZDQW WR SHUIRUP WDVNV WKDW KDYH QRWKLQJ WR GR ZLWK WKH 8, RU LQWHUDFW ZLWK WKH 8, DV ZHOO DV GRLQJ RWKHU WDVNV WKDW WDNH XS D ORW RI WLPH )RU LQVWDQFH \RX PLJKW ZDQW WR GRZQORDG DQ LPDJH DQG GLVSOD\ LW WR WKH XVHU DIWHU LW LV GRZQORDGHG 7KH GRZQORDGLQJ SURFHVV KDV DEVROXWHO\ QRWKLQJ WR GR ZLWK WKH 8, )RU DQ\ WDVN WKDW GRHVQ¦W LQYROYH WKH 8, \RX FDQ XVH JOREDO FRQFXUUHQW TXHXHV LQ *&' 7KHVH DOORZ HLWKHU V\QFKURQRXV RU DV\QFKURQRXV H[HFXWLRQ %XW V\QFKURQRXV H[HFXWLRQ GRHV QRW PHDQ \RXU SURJUDP ZDLWV IRU WKH FRGH WR ILQLVK EHIRUH FRQWLQXLQJ ,W VLPSO\ PHDQV WKDW WKH FRQFXUUHQW TXHXH ZLOO ZDLW XQWLO \RXU WDVN KDV ILQLVKHG EHIRUH LW FRQWLQXHV WR WKH QH[W EORFN RI FRGH RQ WKH TXHXH :KHQ \RX SXW D EORFN REMHFW RQ D FRQFXUUHQW TXHXH \RXU RZQ SURJUDP DOZD\V FRQWLQXHV ULJKW DZD\ ZLWKRXW ZDLWLQJ IRU WKH TXHXH WR H[HFXWH WKH FRGH 7KLV LV EHFDXVH FRQFXUUHQW TXHXHV DV WKHLU QDPH LPSOLHV UXQ WKHLU FRGH RQ WKUHDGV RWKHU WKDQ WKH PDLQ WKUHDG 7KHUH LV RQH H[FHSWLRQ WR WKLV ZKHQ D WDVN LV VXEPLWWHG WR D FRQFXUUHQW RU D VHULDO TXHXH XVLQJ WKH dispatch_sync IXQFWLRQ L26 ZLOO LI SRVVLEOH UXQ WKH WDVN RQ WKH FXUUHQW WKUHDG ZKLFK PLJKW EH WKH PDLQ WKUHDG GHSHQGLQJ RQ ZKHUH WKH FRGH SDWK LV DW WKH PRPHQW 7KLV LV DQ RSWLPL ]DWLRQ WKDW KDV EHHQ SURJUDPPHG RQ *&' DV ZH VKDOO VRRQ VHH
,I \RX VXEPLW D WDVN WR D FRQFXUUHQW TXHXH V\QFKURQRXVO\ DQG DW WKH VDPH WLPH VXEPLW DQRWKHU V\QFKURQRXV WDVN WR DQRWKHU FRQFXUUHQW TXHXH WKHVH WZR V\QFKURQRXV WDVNV ZLOO UXQ DV\QFKURQRXVO\ LQ UHODWLRQ WR HDFK RWKHU EHFDXVH WKH\ DUH UXQQLQJ WZR GLIIHUHQW FRQFXUUHQW TXHXHV ,W¦V LPSRUWDQW WR XQGHUVWDQG WKLV EHFDXVH VRPHWLPHV DV ZH¦OO VHH \RX ZDQW WR PDNH VXUH WDVN $ ILQLVKHV EHIRUH WDVN % VWDUWV 7R HQVXUH WKDW VXEPLW WKHP V\QFKURQRXVO\ WR WKH VDPH TXHXH <RX FDQ SHUIRUP V\QFKURQRXV WDVNV RQ D GLVSDWFK TXHXH XVLQJ WKH dispatch_sync IXQF WLRQ $OO \RX KDYH WR GR LV WR SURYLGH LW ZLWK WKH KDQGOH RI WKH TXHXH WKDW KDV WR UXQ WKH WDVN DQG D EORFN RI FRGH WR H[HFXWH RQ WKDW TXHXH /HW¦V ORRN DW DQ H[DPSOH ,W SULQWV WKH LQWHJHUV WR WZLFH RQH FRPSOHWH VHTXHQFH DIWHU WKH RWKHU ZLWKRXW EORFNLQJ WKH PDLQ WKUHDG :H FDQ FUHDWH D EORFN REMHFW WKDW GRHV WKH FRXQWLQJ IRU XV DQG V\QFKURQRXVO\ FDOO WKH VDPH EORFN REMHFW WZLFH void (^printFrom1To1000)(void) = ^{ NSUInteger counter = 0; for (counter = 1; counter <= 1000; counter++){ NSLog(@"Counter = %lu - Thread = %@", (unsigned long)counter, [NSThread currentThread]); } };
Performing Non-UI-Related Tasks Synchronously | 27
1RZ OHW¦V JR DQG LQYRNH WKLV EORFN REMHFW XVLQJ *&' dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_sync(concurrentQueue, printFrom1To1000); dispatch_sync(concurrentQueue, printFrom1To1000);
,I \RX UXQ WKLV FRGH \RX PLJKW QRWLFH WKH FRXQWLQJ WDNLQJ SODFH RQ WKH PDLQ WKUHDG HYHQ WKRXJK \RX¦YH DVNHG D FRQFXUUHQW TXHXH WR H[HFXWH WKH WDVN ,W WXUQV RXW WKLV LV DQ RSWLPL]DWLRQ E\ *&' 7KH dispatch_sync IXQFWLRQ ZLOO XVH WKH FXUUHQW WKUHDG¢WKH WKUHDG \RX¦UH XVLQJ ZKHQ \RX GLVSDWFK WKH WDVN¢ZKHQHYHU SRVVLEOH DV D SDUW RI DQ RSWLPL]DWLRQ WKDW KDV EHHQ SURJUDPPHG LQWR *&' +HUH LV ZKDW $SSOH VD\V DERXW LW $V DQ RSWLPL]DWLRQ WKLV IXQFWLRQ LQYRNHV WKH EORFN RQ WKH FXUUHQW WKUHDG ZKHQ SRVVLEOH ¢*UDQG &HQWUDO 'LVSDWFK *&' 5HIHUHQFH
7R H[HFXWH D & IXQFWLRQ LQVWHDG RI D EORFN REMHFW V\QFKURQRXVO\ RQ D GLVSDWFK TXHXH XVH WKH dispatch_sync_f IXQFWLRQ /HW¦V VLPSO\ WUDQVODWH WKH FRGH ZH¦YH ZULWWHQ IRU WKH printFrom1To1000 EORFN REMHFW WR LWV HTXLYDOHQW & IXQFWLRQ OLNH VR void printFrom1To1000(void *paramContext){ NSUInteger counter = 0; for (counter = 1; counter <= 1000; counter++){ NSLog(@"Counter = %lu - Thread = %@", (unsigned long)counter, [NSThread currentThread]); } }
$QG QRZ ZH FDQ XVH WKH dispatch_sync_f IXQFWLRQ WR H[HFXWH WKH printFrom1To1000 IXQFWLRQ RQ D FRQFXUUHQW TXHXH DV GHPRQVWUDWHG KHUH dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_sync_f(concurrentQueue, NULL, printFrom1To1000); dispatch_sync_f(concurrentQueue, NULL, printFrom1To1000);
7KH ILUVW SDUDPHWHU RI WKH dispatch_get_global_queue IXQFWLRQ VSHFLILHV WKH SULRULW\ RI WKH FRQFXUUHQW TXHXH WKDW *&' KDV WR UHWULHYH IRU WKH SURJUDPPHU 7KH KLJKHU WKH SULRULW\ WKH PRUH &38 WLPHVOLFHV ZLOO EH SURYLGHG WR WKH FRGH JHWWLQJ H[HFXWHG RQ WKDW
28 | Chapter 2: Programming Grand Central Dispatch
TXHXH <RX FDQ XVH DQ\ RI WKHVH YDOXHV IRU WKH ILUVW SDUDPHWHU WR WKH dispatch_get_global_queue IXQFWLRQ DISPATCH_QUEUE_PRIORITY_LOW
)HZHU WLPHVOLFHV ZLOO EH DSSOLHG WR \RXU WDVN WKDQ QRUPDO WDVNV DISPATCH_QUEUE_PRIORITY_DEFAULT
7KH GHIDXOW V\VWHP SULRULW\ IRU FRGH H[HFXWLRQ ZLOO EH DSSOLHG WR \RXU WDVN DISPATCH_QUEUE_PRIORITY_HIGH
0RUH WLPHVOLFHV ZLOO EH DSSOLHG WR \RXU WDVN WKDQ QRUPDO WDVNV 7KH VHFRQG SDUDPHWHU RI WKH dispatch_get_global_queue IXQFWLRQ LV UH VHUYHG DQG \RX VKRXOG DOZD\V SDVV WKH YDOXH WR LW
,Q WKLV VHFWLRQ \RX VDZ KRZ \RX FDQ GLVSDWFK WDVNV WR FRQFXUUHQW TXHXHV IRU V\QFKUR QRXV H[HFXWLRQ 7KH QH[W VHFWLRQ VKRZV DV\QFKURQRXV H[HFXWLRQ RQ FRQFXUUHQW TXHXHV ZKLOH £&RQVWUXFWLQJ <RXU 2ZQ 'LVSDWFK 4XHXHV¤ RQ SDJH ZLOO VKRZ KRZ WR H[HFXWH WDVNV V\QFKURQRXVO\ DQG DV\QFKURQRXVO\ RQ VHULDO TXHXHV WKDW \RX FUHDWH IRU \RXU DSSOLFDWLRQV
Performing Non-UI-Related Tasks Asynchronously 7KLV LV ZKHUH *&' FDQ VKRZ LWV WUXH SRZHU H[HFXWLQJ EORFNV RI FRGH DV\QFKURQRXVO\ RQ WKH PDLQ VHULDO RU FRQFXUUHQW TXHXHV , SURPLVH WKDW E\ WKH HQG RI WKLV VHFWLRQ \RX ZLOO EH FRPSOHWHO\ FRQYLQFHG *&' LV WKH IXWXUH RI PXOWLWKUHDG DSSOLFDWLRQV FRP SOHWHO\ UHSODFLQJ WKUHDGV LQ PRGHUQ DSSV ,Q RUGHU WR H[HFXWH DV\QFKURQRXV WDVNV RQ D GLVSDWFK TXHXH \RX PXVW XVH RQH RI WKHVH IXQFWLRQV dispatch_async
6XEPLWV D EORFN REMHFW WR D GLVSDWFK TXHXH ERWK VSHFLILHG E\ SDUDPHWHUV IRU DV\QFKURQRXV H[HFXWLRQ dispatch_async_f
6XEPLWV D & IXQFWLRQ WR D GLVSDWFK TXHXH DORQJ ZLWK D FRQWH[W UHIHUHQFH DOO WKUHH VSHFLILHG E\ SDUDPHWHUV IRU DV\QFKURQRXV H[HFXWLRQ /HW¦V KDYH D ORRN DW D UHDO H[DPSOH :H¦OO ZULWH DQ L26 DSS WKDW LV DEOH WR GRZQORDG DQ LPDJH IURP D 85/ RQ WKH ,QWHUQHW $IWHU WKH GRZQORDG LV ILQLVKHG WKH DSS VKRXOG GLVSOD\ WKH LPDJH WR WKH XVHU +HUH LV WKH SODQ DQG KRZ ZH ZLOO XVH ZKDW ZH¦YH OHDUQHG VR IDU DERXW *&' LQ RUGHU WR DFFRPSOLVK LW
Performing Non-UI-Related Tasks Asynchronously | 29
:H DUH JRLQJ WR ODXQFK D EORFN REMHFW DV\QFKURQRXVO\ RQ D FRQFXUUHQW TXHXH 2QFH LQ WKLV EORFN ZH ZLOO ODXQFK DQRWKHU EORFN REMHFW V\QFKURQRXVO\ XVLQJ WKH dispatch_sync IXQFWLRQ WR GRZQORDG WKH LPDJH IURP D 85/ 6\QFKURQRXVO\ GRZQ ORDGLQJ D 85/ IURP DQ DV\QFKURQRXV FRGH EORFN KROGV XS MXVW WKH TXHXH UXQQLQJ WKH V\QFKURQRXV IXQFWLRQ QRW WKH PDLQ WKUHDG 7KH ZKROH RSHUDWLRQ VWLOO LV DV\Q FKURQRXV ZKHQ ZH ORRN DW LW IURP WKH PDLQ WKUHDG¦V SHUVSHFWLYH $OO ZH FDUH DERXW LV WKDW ZH DUH QRW EORFNLQJ WKH PDLQ WKUHDG ZKLOH GRZQORDGLQJ RXU LPDJH 5LJKW DIWHU WKH LPDJH LV GRZQORDGHG ZH ZLOO V\QFKURQRXVO\ H[HFXWH D EORFN REMHFW RQ WKH PDLQ TXHXH VHH £3HUIRUPLQJ 8, 5HODWHG 7DVNV¤ RQ SDJH LQ RUGHU WR GLVSOD\ WKH LPDJH WR WKH XVHU RQ WKH 8, 7KH VNHOHWRQ IRU RXU SODQ LV DV VLPSOH DV WKLV dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(concurrentQueue, ^{ __block UIImage *image = nil; dispatch_sync(concurrentQueue, ^{ /* Download the image here */ }); dispatch_sync(dispatch_get_main_queue(), ^{ /* Show the image to the user here on the main queue*/ }); });
7KH VHFRQG dispatch_sync FDOO ZKLFK GLVSOD\V WKH LPDJH ZLOO EH H[HFXWHG RQ WKH TXHXH DIWHU WKH ILUVW V\QFKURQRXV FDOO ZKLFK GRZQORDGV RXU LPDJH 7KDW¦V H[DFWO\ ZKDW ZH ZDQW EHFDXVH ZH KDYH WR ZDLW IRU WKH LPDJH WR EH IXOO\ GRZQORDGHG EHIRUH ZH FDQ GLVSOD\ LW WR WKH XVHU 6R DIWHU WKH LPDJH LV GRZQORDGHG ZH H[HFXWH WKH VHFRQG EORFN REMHFW EXW WKLV WLPH RQ WKH PDLQ TXHXH /HW¦V GRZQORDG WKH LPDJH DQG GLVSOD\ LW WR WKH XVHU QRZ :H ZLOO GR WKLV LQ WKH view DidAppear: LQVWDQFH PHWKRG RI D YLHZ FRQWUROOHU GLVSOD\HG LQ DQ L3KRQH DSS - (void) viewDidAppear:(BOOL)paramAnimated{ dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(concurrentQueue, ^{ __block UIImage *image = nil; dispatch_sync(concurrentQueue, ^{ /* Download the image here */ /* iPad's image from Apple's website. Wrap it into two
30 | Chapter 2: Programming Grand Central Dispatch
lines as the URL is too long to fit into one line */ NSString *urlAsString = @"http://images.apple.com/mobileme/features"\ "/images/ipad_findyouripad_20100518.jpg"; NSURL *url = [NSURL URLWithString:urlAsString]; NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; NSError *downloadError = nil; NSData *imageData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&downloadError]; if (downloadError == nil && imageData != nil){ image = [UIImage imageWithData:imageData]; /* We have the image. We can use it now */ } else if (downloadError != nil){ NSLog(@"Error happened = %@", downloadError); } else { NSLog(@"No data could get downloaded from the URL."); } }); dispatch_sync(dispatch_get_main_queue(), ^{ /* Show the image to the user here on the main queue*/ if (image != nil){ /* Create the image view here */ UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds]; /* Set the image */ [imageView setImage:image]; /* Make sure the image is not scaled incorrectly */ [imageView setContentMode:UIViewContentModeScaleAspectFit]; /* Add the image to this view controller's view */ [self.view addSubview:imageView]; /* Release the image view */ [imageView release]; } else { NSLog(@"Image isn't downloaded. Nothing to display."); } });
Performing Non-UI-Related Tasks Asynchronously | 31
}); }
$V \RX FDQ VHH LQ )LJXUH ZH KDYH VXFFHVVIXOO\ GRZQORDGHG RXU LPDJH DQG DOVR FUHDWHG DQ LPDJH YLHZ WR GLVSOD\ WKH LPDJH WR WKH XVHU RQ WKH 8,
)LJXUH 'RZQORDGLQJ DQG GLVSOD\LQJ LPDJHV WR XVHUV XVLQJ *&'
/HW¦V PRYH RQ WR DQRWKHU H[DPSOH /HW¦V VD\ WKDW ZH KDYH DQ DUUD\ RI UDQGRP QXPEHUV WKDW KDYH EHHQ VWRUHG LQ D ILOH RQ GLVN DQG ZH ZDQW WR ORDG WKLV DUUD\ LQWR PHPRU\ VRUW WKH QXPEHUV LQ DQ DVFHQGLQJ IDVKLRQ ZLWK WKH VPDOOHVW QXPEHU DSSHDULQJ ILUVW LQ WKH OLVW DQG WKHQ GLVSOD\ WKH OLVW WR WKH XVHU 7KH FRQWURO XVHG IRU WKH GLVSOD\ GHSHQGV RQ ZKHWKHU \RX DUH FRGLQJ WKLV IRU L26 LGHDOO\ \RX¦G XVH DQ LQVWDQFH RI UITableView RU 0DF 26 ; NSTableView ZRXOG EH D JRRG FDQGLGDWH 6LQFH ZH GRQ¦W KDYH DQ DUUD\ ZK\ GRQ¦W ZH FUHDWH WKH DUUD\ ILUVW WKHQ ORDG LW DQG ILQDOO\ GLVSOD\ LW" +HUH DUH WZR PHWKRGV WKDW ZLOO KHOS XV ILQG WKH ORFDWLRQ ZKHUH ZH ZDQW WR VDYH WKH DUUD\ RI UDQGRP QXPEHUV RQ GLVN RQ WKH GHYLFH - (NSString *) fileLocation{ /* Get the document folder(s) */ NSArray *folders = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
32 | Chapter 2: Programming Grand Central Dispatch
NSUserDomainMask, YES); /* Did we find anything? */ if ([folders count] == 0){ return nil; } /* Get the first folder */ NSString *documentsFolder = [folders objectAtIndex:0]; /* Append the file name to the end of the documents path */ return [documentsFolder stringByAppendingPathComponent:@"list.txt"]; } - (BOOL) hasFileAlreadyBeenCreated{ BOOL result = NO; NSFileManager *fileManager = [[NSFileManager alloc] init]; if ([fileManager fileExistsAtPath:[self fileLocation]] == YES){ result = YES; } [fileManager release]; return result; }
1RZ WKH LPSRUWDQW SDUW ZH ZDQW WR VDYH DQ DUUD\ RI UDQGRP QXPEHUV WR GLVN LI DQG RQO\ LI ZH KDYH QRW FUHDWHG WKLV DUUD\ EHIRUH RQ GLVN ,I ZH KDYH ZH ZLOO ORDG WKH DUUD\ IURP GLVN LPPHGLDWHO\ ,I ZH KDYH QRW FUHDWHG WKLV DUUD\ EHIRUH RQ GLVN ZH ZLOO ILUVW FUHDWH LW DQG WKHQ PRYH RQ WR ORDGLQJ LW IURP GLVN $W WKH HQG LI WKH DUUD\ ZDV VXFFHVVIXOO\ UHDG IURP GLVN ZH ZLOO VRUW WKH DUUD\ LQ DQ DVFHQGLQJ IDVKLRQ DQG ILQDOO\ GLVSOD\ WKH UHVXOWV WR WKH XVHU RQ WKH 8, , ZLOO OHDYH GLVSOD\LQJ WKH UHVXOWV WR WKH XVHU XS WR \RX dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); /* If we have not already saved an array of 10,000 random numbers to the disk before, generate these numbers now and then save them to the disk in an array */ dispatch_async(concurrentQueue, ^{ NSUInteger numberOfValuesRequired = 10000; if ([self hasFileAlreadyBeenCreated] == NO){ dispatch_sync(concurrentQueue, ^{ NSMutableArray *arrayOfRandomNumbers = [[NSMutableArray alloc] initWithCapacity:numberOfValuesRequired];
Performing Non-UI-Related Tasks Asynchronously | 33
NSUInteger counter = 0; for (counter = 0; counter < numberOfValuesRequired; counter++){ unsigned int randomNumber = arc4random() % ((unsigned int)RAND_MAX + 1); [arrayOfRandomNumbers addObject: [NSNumber numberWithUnsignedInt:randomNumber]]; } /* Now let's write the array to disk */ [arrayOfRandomNumbers writeToFile:[self fileLocation] atomically:YES]; [arrayOfRandomNumbers release]; }); } __block NSMutableArray *randomNumbers = nil; /* Read the numbers from disk and sort them in an ascending fashion */ dispatch_sync(concurrentQueue, ^{ /* If the file has now been created, we have to read it */ if ([self hasFileAlreadyBeenCreated] == YES){ randomNumbers = [[NSMutableArray alloc] initWithContentsOfFile:[self fileLocation]]; /* Now sort the numbers */ [randomNumbers sortUsingComparator: ^NSComparisonResult(id obj1, id obj2) { NSNumber *number1 = (NSNumber *)obj1; NSNumber *number2 = (NSNumber *)obj2; return [number1 compare:number2]; }]; } }); dispatch_async(dispatch_get_main_queue(), ^{ if ([randomNumbers count] > 0){ /* Refresh the UI here using the numbers in the randomNumbers array */ } [randomNumbers release]; }); });
34 | Chapter 2: Programming Grand Central Dispatch
7KHUH LV D ORW PRUH WR *&' WKDQ V\QFKURQRXV DQG DV\QFKURQRXV EORFN RU IXQFWLRQ H[HFXWLRQ ,Q £5XQQLQJ D *URXS RI 7DVNV 7RJHWKHU¤ RQ SDJH \RX ZLOO OHDUQ KRZ WR JURXS EORFN REMHFWV WRJHWKHU DQG SUHSDUH WKHP IRU H[HFXWLRQ RQ D GLVSDWFK TXHXH , DOVR VXJJHVW WKDW \RX KDYH D ORRN DW £3HUIRUPLQJ 7DVNV $IWHU D 'HOD\¤ RQ SDJH DQG £3HUIRUPLQJ D 7DVN DW 0RVW 2QFH¤ RQ SDJH WR OHDUQ DERXW RWKHU IXQFWLRQDOLWLHV WKDW *&' LV FDSDEOH RI SURYLGLQJ WR SURJUDPPHUV
Performing Tasks After a Delay :LWK &RUH )RXQGDWLRQ \RX FDQ LQYRNH D VHOHFWRU LQ DQ REMHFW DIWHU D JLYHQ SHULRG RI WLPH XVLQJ WKH performSelector:withObject:afterDelay: PHWKRG RI WKH NSObject FODVV +HUH LV DQ H[DPSOH - (void) printString:(NSString *)paramString{ NSLog(@"%@", paramString); } - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ @selector(performSelector:withObject:afterDelay:) [self performSelector:@selector(printString:) withObject:@"Grand Central Dispatch" afterDelay:3.0];
}
// Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES;
,Q WKLV H[DPSOH ZH DUH DVNLQJ WKH UXQWLPH WR FDOO WKH printString: PHWKRG DIWHU VHFRQGV RI GHOD\ :H FDQ GR WKH VDPH WKLQJ LQ *&' XVLQJ WKH dispatch_after DQG dispatch_after_f IXQFWLRQV HDFK RI ZKLFK LV GHVFULEHG KHUH dispatch_after
'LVSDWFKHV D EORFN REMHFW WR D GLVSDWFK TXHXH DIWHU D JLYHQ SHULRG RI WLPH VSHFLILHG LQ QDQRVHFRQGV 7KHVH DUH WKH SDUDPHWHUV WKDW WKLV IXQFWLRQ UHTXLUHV 'HOD\ LQ QDQRVHFRQGV 7KH QXPEHU RI QDQRVHFRQGV *&' KDV WR ZDLW RQ D JLYHQ GLVSDWFK TXHXH VSHFLILHG E\ WKH VHFRQG SDUDPHWHU EHIRUH LW H[HFXWHV WKH JLYHQ EORFN REMHFW VSHFLILHG E\ WKH WKLUG SDUDPHWHU 'LVSDWFK TXHXH 7KH GLVSDWFK TXHXH RQ ZKLFK WKH EORFN REMHFW VSHFLILHG E\ WKH WKLUG SDUDP HWHU KDV WR EH H[HFXWHG DIWHU WKH JLYHQ GHOD\ VSHFLILHG E\ WKH ILUVW SDUDPHWHU
Performing Tasks After a Delay | 35
%ORFN REMHFW 7KH EORFN REMHFW WR EH LQYRNHG DIWHU WKH VSHFLILHG QXPEHU RI QDQRVHFRQGV RQ WKH JLYHQ GLVSDWFK TXHXH 7KLV EORFN REMHFW VKRXOG KDYH QR UHWXUQ YDOXH DQG VKRXOG DFFHSW QR SDUDPHWHUV VHH £&RQVWUXFWLQJ %ORFN 2EMHFWV DQG 7KHLU 6\Q WD[¤ RQ SDJH dispatch_after_f
'LVSDWFKHV D & IXQFWLRQ WR *&' IRU H[HFXWLRQ DIWHU D JLYHQ SHULRG RI WLPH VSHFLILHG LQ QDQRVHFRQGV 7KLV IXQFWLRQ DFFHSWV IRXU SDUDPHWHUV 'HOD\ LQ QDQRVHFRQGV 7KH QXPEHU RI QDQRVHFRQGV *&' KDV WR ZDLW RQ D JLYHQ GLVSDWFK TXHXH VSHFLILHG E\ WKH VHFRQG SDUDPHWHU EHIRUH LW H[HFXWHV WKH JLYHQ IXQFWLRQ VSHFLILHG E\ WKH IRXUWK SDUDPHWHU 'LVSDWFK TXHXH 7KH GLVSDWFK TXHXH RQ ZKLFK WKH & IXQFWLRQ VSHFLILHG E\ WKH IRXUWK SDUDP HWHU KDV WR EH H[HFXWHG DIWHU WKH JLYHQ GHOD\ VSHFLILHG E\ WKH ILUVW SDUDPHWHU &RQWH[W 7KH PHPRU\ DGGUHVV RI D YDOXH LQ WKH KHDS WR EH SDVVHG WR WKH & IXQFWLRQ IRU DQ H[DPSOH VHH £3HUIRUPLQJ 8, 5HODWHG 7DVNV¤ RQ SDJH & IXQFWLRQ 7KH DGGUHVV RI WKH & IXQFWLRQ WKDW KDV WR EH H[HFXWHG DIWHU D FHUWDLQ SHULRG RI WLPH VSHFLILHG E\ WKH ILUVW SDUDPHWHU RQ WKH JLYHQ GLVSDWFK TXHXH VSHFLILHG E\ WKH VHFRQG SDUDPHWHU $OWKRXJK WKH GHOD\V DUH LQ QDQRVHFRQGV LW LV XS WR L26 WR GHFLGH WKH JUDQXODULW\ RI GLVSDWFK GHOD\ DQG WKLV GHOD\ PLJKW QRW EH DV SUHFLVH DV ZKDW \RX KRSH ZKHQ \RX VSHFLI\ D YDOXH LQ QDQRVHFRQGV
/HW¦V KDYH D ORRN DW DQ H[DPSOH IRU dispatch_after ILUVW double delayInSeconds = 2.0; dispatch_time_t delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_after(delayInNanoSeconds, concurrentQueue, ^(void){ /* Perform your operations here */ });
$V \RX FDQ VHH WKH QDQRVHFRQGV GHOD\ SDUDPHWHU IRU ERWK WKH dispatch_after DQG dispatch_after_f IXQFWLRQV KDV WR EH RI W\SH dispatch_time_t ZKLFK LV DQ DEVWUDFW UHSUHVHQWDWLRQ RI DEVROXWH WLPH 7R JHW WKH YDOXH IRU WKLV SDUDPHWHU \RX FDQ XVH WKH
36 | Chapter 2: Programming Grand Central Dispatch
dispatch_time IXQFWLRQ DV GHPRQVWUDWHG LQ WKLV VDPSOH FRGH +HUH DUH WKH SDUDPHWHUV WKDW \RX FDQ SDVV WR WKH dispatch_time IXQFWLRQ
%DVH WLPH ,I WKLV YDOXH ZDV GHQRWHG ZLWK % DQG WKH GHOWD SDUDPHWHU ZDV GHQRWHG ZLWK ' WKH UHVXOWLQJ WLPH IURP WKLV IXQFWLRQ ZRXOG EH HTXDO WR % ' <RX FDQ VHW WKLV SDUDP HWHU¦V YDOXH WR DISPATCH_TIME_NOW WR GHQRWH QRZ DV WKH EDVH WLPH DQG WKHQ VSHFLI\ WKH GHOWD IURP QRZ XVLQJ WKH GHOWD SDUDPHWHU 'HOWD WR DGG WR EDVH WLPH 7KLV SDUDPHWHU LV WKH QDQRVHFRQGV WKDW ZLOO JHW DGGHG WR WKH EDVH WLPH SDUDPHWHU WR FUHDWH WKH UHVXOW RI WKLV IXQFWLRQ )RU H[DPSOH WR GHQRWH D WLPH VHFRQGV IURP QRZ \RX FRXOG ZULWH \RXU FRGH OLNH VR dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC);
2U WR GHQRWH KDOI D VHFRQG IURP QRZ dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (1.0 / 2.0f) * NSEC_PER_SEC);
1RZ OHW¦V KDYH D ORRN DW KRZ ZH FDQ XVH WKH dispatch_after_f IXQFWLRQ void processSomething(void *paramContext){ /* Do your processing here */ NSLog(@"Processing..."); } - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ double delayInSeconds = 2.0; dispatch_time_t delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_after_f(delayInNanoSeconds, concurrentQueue, NULL, processSomething);
}
// Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES;
Performing Tasks After a Delay | 37
Performing a Task at Most Once $OORFDWLQJ DQG LQLWLDOL]LQJ D VLQJOHWRQ LV RQH RI WKH WDVNV WKDW KDV WR KDSSHQ H[DFWO\ RQFH GXULQJ WKH OLIHWLPH RI DQ DSS , DP VXUH \RX NQRZ RI RWKHU VFHQDULRV ZKHUH \RX KDG WR PDNH VXUH D SLHFH RI FRGH ZDV H[HFXWHG RQO\ RQFH GXULQJ WKH OLIHWLPH RI \RXU DSSOLFDWLRQ *&' OHWV \RX VSHFLI\ DQ LGHQWLILHU IRU D SLHFH RI FRGH ZKHQ \RX DWWHPSW WR H[HFXWH LW ,I *&' GHWHFWV WKDW WKLV LGHQWLILHU KDV EHHQ SDVVHG WR WKH IUDPHZRUN EHIRUH LW ZRQ¦W H[HFXWH WKDW EORFN RI FRGH DJDLQ 7KH IXQFWLRQ WKDW DOORZV \RX WR GR WKLV LV dispatch_once ZKLFK DFFHSWV WZR SDUDPHWHUV 7RNHQ $ WRNHQ RI W\SH dispatch_once_t WKDW KROGV WKH WRNHQ JHQHUDWHG E\ *&' ZKHQ WKH EORFN RI FRGH LV H[HFXWHG IRU WKH ILUVW WLPH ,I \RX ZDQW D SLHFH RI FRGH WR EH H[HFXWHG DW PRVW RQFH \RX PXVW VSHFLI\ WKH VDPH WRNHQ WR WKLV PHWKRG ZKHQHYHU LW LV LQ YRNHG LQ WKH DSS :H ZLOO VHH DQ H[DPSOH RI WKLV VRRQ %ORFN REMHFW 7KH EORFN REMHFW WR JHW H[HFXWHG DW PRVW RQFH 7KLV EORFN REMHFW UHWXUQV QR YDOXHV DQG DFFHSWV QR SDUDPHWHUV dispatch_once DOZD\V H[HFXWHV LWV WDVN RQ WKH FXUUHQW TXHXH EHLQJ XVHG
E\ WKH FRGH WKDW LVVXHV WKH FDOO EH LW D VHULDO TXHXH D FRQFXUUHQW TXHXH RU WKH PDLQ TXHXH
+HUH LV DQ H[DPSOH static dispatch_once_t onceToken; void (^executedOnlyOnce)(void) = ^{ static NSUInteger numberOfEntries = 0; numberOfEntries++; NSLog(@"Executed %lu time(s)", (unsigned long)numberOfEntries); }; - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_once(&onceToken, ^{ dispatch_async(concurrentQueue, executedOnlyOnce); });
38 | Chapter 2: Programming Grand Central Dispatch
dispatch_once(&onceToken, ^{ dispatch_async(concurrentQueue, executedOnlyOnce); }); // Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES; }
$V \RX FDQ VHH DOWKRXJK ZH DUH DWWHPSWLQJ WR LQYRNH WKH executedOnlyOnce EORFN REMHFW WZLFH XVLQJ WKH dispatch_once IXQFWLRQ LQ UHDOLW\ *&' LV RQO\ H[HFXWLQJ WKLV EORFN REMHFW RQFH VLQFH WKH LGHQWLILHU SDVVHG WR WKH dispatch_once IXQFWLRQ LV WKH VDPH ERWK WLPHV $SSOH LQ LWV &RFRD )XQGDPHQWDOV *XLGH VKRZV SURJUDPPHUV KRZ WR FUHDWH D VLQJOH WRQ +RZHYHU ZH FDQ FKDQJH WKLV PRGHO WR PDNH XVH RI *&' DQG WKH dispatch_once IXQFWLRQ LQ RUGHU WR LQLWLDOL]H D VKDUHG LQVWDQFH RI DQ REMHFW OLNH VR #import "MySingleton.h" @implementation MySingleton static MySingleton *sharedMySingleton = NULL; + (MySingleton *) sharedInstance{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (sharedMySingleton == NULL){ sharedMySingleton = [[super allocWithZone:NULL] init]; } }); return sharedMySingleton; } + (id) allocWithZone:(NSZone *)paramZone{ return [[self sharedInstance] retain]; } - (id) copyWithZone:(NSZone *)paramZone{ return self; } - (void) release{ /* Do nothing */ } - (id) autorelease{ return self; } - (NSUInteger) retainCount{
Performing a Task at Most Once | 39
}
return NSUIntegerMax; - (id) retain{ return self; } @end
Running a Group of Tasks Together *&' OHWV XV FUHDWH JURXSV ZKLFK DOORZ \RX WR SODFH \RXU WDVNV LQ RQH SODFH UXQ DOO RI WKHP DQG JHW D QRWLILFDWLRQ DW WKH HQG IURP *&' 7KLV KDV PDQ\ YDOXDEOH DSSOLFDWLRQV )RU LQVWDQFH VXSSRVH \RX KDYH D 8, EDVHG DSS DQG ZDQW WR UHORDG WKH FRPSRQHQWV RQ \RXU 8, <RX KDYH D WDEOH YLHZ D VFUROO YLHZ DQG DQ LPDJH YLHZ <RX ZDQW WR UHORDG WKH FRQWHQWV RI WKHVH FRPSRQHQWV XVLQJ WKHVH PHWKRGV - (void) reloadTableView{ /* Reload the table view here */ NSLog(@"%s", __FUNCTION__); } - (void) reloadScrollView{ /* Do the work here */ NSLog(@"%s", __FUNCTION__); } - (void) reloadImageView{ /* Reload the image view here */ NSLog(@"%s", __FUNCTION__); }
$W WKH PRPHQW WKHVH PHWKRGV DUH HPSW\ EXW ODWHU \RX FDQ SXW WKH UHOHYDQW 8, FRGH LQ WKHP 1RZ ZH ZDQW WR FDOO WKHVH WKUHH PHWKRGV RQH DIWHU WKH RWKHU DQG ZH ZDQW WR NQRZ ZKHQ *&' KDV ILQLVKHG FDOOLQJ WKHVH PHWKRGV VR WKDW ZH FDQ GLVSOD\ D PHVVDJH WR WKH XVHU )RU WKLV ZH VKRXOG EH XVLQJ D JURXS <RX VKRXOG NQRZ DERXW IRXU IXQFWLRQV ZKHQ ZRUNLQJ ZLWK JURXSV LQ *&' dispatch_group_create
&UHDWHV D JURXS KDQGOH 2QFH \RX DUH GRQH ZLWK WKLV JURXS KDQGOH \RX VKRXOG GLVSRVH RI LW XVLQJ WKH dispatch_release IXQFWLRQ dispatch_group_async
6XEPLWV D EORFN RI FRGH IRU H[HFXWLRQ RQ D JURXS <RX PXVW VSHFLI\ WKH GLVSDWFK TXHXH RQ ZKLFK WKH EORFN RI FRGH KDV WR EH H[HFXWHG DV ZHOO DV WKH JURXS WR ZKLFK WKLV EORFN RI FRGH EHORQJV dispatch_group_notify
$OORZV \RX WR VXEPLW D EORFN REMHFW WKDW VKRXOG EH H[HFXWHG RQFH DOO WDVNV DGGHG WR WKH JURXS IRU H[HFXWLRQ KDYH ILQLVKHG WKHLU ZRUN 7KLV IXQFWLRQ DOVR DOORZV \RX WR VSHFLI\ WKH GLVSDWFK TXHXH RQ ZKLFK WKDW EORFN REMHFW KDV WR EH H[HFXWHG 40 | Chapter 2: Programming Grand Central Dispatch
dispatch_release
8VH WKLV IXQFWLRQ WR GLVSRVH RI DQ\ GLVSDWFK JURXSV WKDW \RX FUHDWH XVLQJ WKH dispatch_group_create IXQFWLRQ /HW¦V KDYH D ORRN DW DQ H[DPSOH $V H[SODLQHG LQ RXU H[DPSOH ZH ZDQW WR LQYRNH WKH reloadTableView reloadScrollView DQG reloadImageView PHWKRGV RQH DIWHU WKH RWKHU DQG WKHQ GLVSOD\ D PHVVDJH WR WKH XVHU RQFH ZH DUH GRQH :H FDQ XWLOL]H *&'¦V SRZHUIXO JURXSLQJ IDFLOLWLHV LQ RUGHU WR DFFRPSOLVK WKLV dispatch_group_t taskGroup = dispatch_queue_t mainQueue =
dispatch_group_create(); dispatch_get_main_queue();
/* Reload the table view on the main queue */ dispatch_group_async(taskGroup, mainQueue, ^{ [self reloadTableView]; }); /* Reload the scroll view on the main queue */ dispatch_group_async(taskGroup, mainQueue, ^{ [self reloadScrollView]; }); /* Reload the image view on the main queue */ dispatch_group_async(taskGroup, mainQueue, ^{ [self reloadImageView]; }); /* At the end when we are done, dispatch the following block */ dispatch_group_notify(taskGroup, mainQueue, ^{ /* Do some processing here */ [[[[UIAlertView alloc] initWithTitle:@"Finished" message:@"All tasks are finished" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] autorelease] show]; }); /* We are done with the group */ dispatch_release(taskGroup);
,Q DGGLWLRQ WR dispatch_group_async \RX FDQ DOVR GLVSDWFK DV\QFKURQRXV & IXQFWLRQV WR D GLVSDWFK JURXS XVLQJ WKH dispatch_group_async_f IXQFWLRQ GCDAppDelegate LV VLPSO\ WKH QDPH RI WKH FODVV IURP ZKLFK WKLV H[DPSOH
LV WDNHQ :H KDYH WR XVH WKLV FODVV QDPH LQ RUGHU WR W\SHFDVW D FRQWH[W REMHFW VR WKDW WKH FRPSLOHU ZLOO XQGHUVWDQG RXU FRPPDQGV
/LNH VR
Running a Group of Tasks Together | 41
- (void) reloadTableView{ /* Reload the table view here */ NSLog(@"%s", __FUNCTION__); } - (void) reloadScrollView{ /* Do the work here */ NSLog(@"%s", __FUNCTION__); } - (void) reloadImageView{ /* Reload the image view here */ NSLog(@"%s", __FUNCTION__); } void reloadAllComponents(void *context){ GCDAppDelegate *self = (GCDAppDelegate *)context; [self reloadTableView]; [self reloadScrollView]; [self reloadImageView]; } - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ dispatch_group_t taskGroup = dispatch_queue_t mainQueue =
dispatch_group_create(); dispatch_get_main_queue();
dispatch_group_async_f(taskGroup, mainQueue, (void *)self, reloadAllComponents); /* At the end when we are done, dispatch the following block */ dispatch_group_notify(taskGroup, mainQueue, ^{ /* Do some processing here */ [[[[UIAlertView alloc] initWithTitle:@"Finished" message:@"All tasks are finished" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] autorelease] show]; }); /* We are done with the group */ dispatch_release(taskGroup); // Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES; }
42 | Chapter 2: Programming Grand Central Dispatch
6LQFH WKH dispatch_group_async_f IXQFWLRQ DFFHSWV D & IXQFWLRQ DV WKH EORFN RI FRGH WR EH H[HFXWHG WKH & IXQFWLRQ PXVW KDYH D UHIHUHQFH WR self WR EH DEOH WR LQYRNH LQVWDQFH PHWKRGV RI WKH FXUUHQW REMHFW LQ ZKLFK WKH & IXQFWLRQ LV LPSOHPHQWHG 7KDW LV WKH UHDVRQ EHKLQG SDVVLQJ self DV WKH FRQWH[W SRLQWHU LQ WKH dispatch_group_async_f IXQFWLRQ )RU PRUH LQIRUPDWLRQ DERXW FRQWH[WV DQG & IXQFWLRQV SOHDVH UHIHU WR £3HUIRUPLQJ 8, 5HODWHG 7DVNV¤ RQ SDJH
2QFH DOO WKH JLYHQ WDVNV DUH ILQLVKHG WKH XVHU ZLOO VHH D UHVXOW VLPLODU WR WKDW VKRZQ LQ )LJXUH
)LJXUH 0DQDJLQJ D JURXS RI WDVNV ZLWK *&'
Constructing Your Own Dispatch Queues :LWK *&' \RX FDQ FUHDWH \RXU RZQ VHULDO GLVSDWFK TXHXHV VHH £'LIIHUHQW 7\SHV RI 'LVSDWFK 4XHXHV¤ RQ SDJH IRU VHULDO TXHXHV 6HULDO GLVSDWFK TXHXHV UXQ WKHLU WDVNV LQ D ILUVW LQ ILUVW RXW ),)2 IDVKLRQ 7KH DV\QFKURQRXV WDVNV RQ VHULDO TXHXHV ZLOO QRW EH SHUIRUPHG RQ WKH PDLQ WKUHDG KRZHYHU PDNLQJ VHULDO TXHXHV KLJKO\ GHVLUDEOH IRU FRQFXUUHQW ),)2 WDVNV Constructing Your Own Dispatch Queues | 43
$OO V\QFKURQRXV WDVNV VXEPLWWHG WR D VHULDO TXHXH ZLOO EH H[HFXWHG RQ WKH FXUUHQW WKUHDG EHLQJ XVHG E\ WKH FRGH WKDW LV VXEPLWWLQJ WKH WDVN ZKHQHYHU SRVVLEOH %XW DV\QFKURQRXV WDVNV VXEPLWWHG WR D VHULDO TXHXH ZLOO DOZD\V EH H[HFXWHG RQ D WKUHDG RWKHU WKDQ WKH PDLQ WKUHDG :H¦OO XVH WKH dispatch_queue_create IXQFWLRQ WR FUHDWH VHULDO TXHXHV 7KH ILUVW SDUDP HWHU LQ WKLV IXQFWLRQ LV D & VWULQJ char * WKDW ZLOO XQLTXHO\ LGHQWLI\ WKDW VHULDO TXHXH LQ WKH V\VWHP 7KH UHDVRQ , DP HPSKDVL]LQJ V\VWHP LV EHFDXVH WKLV LGHQWLILHU LV D V\VWHP ZLGH LGHQWLILHU PHDQLQJ WKDW LI \RXU DSS FUHDWHV D QHZ VHULDO TXHXH ZLWK WKH LGHQWLILHU RI serialQueue1 DQG VRPHERG\ HOVH¦V DSS GRHV WKH VDPH WKH UHVXOWV RI FUHDWLQJ D QHZ VHULDO TXHXH ZLWK WKH VDPH QDPH DUH XQGHILQHG E\ *&' %HFDXVH RI WKLV $SSOH VWURQJO\ UHFRPPHQGV WKDW \RX XVH D UHYHUVH '16 IRUPDW IRU LGHQWLILHUV 5HYHUVH '16 LGHQWLILHUV DUH XVXDOO\ FRQVWUXFWHG LQ WKLV ZD\ FRP COMPANY PRODUCT IDENTIFIER )RU LQVWDQFH , FRXOG FUHDWH WZR VHULDO TXHXHV DQG DVVLJQ WKHVH QDPHV WR WKHP com.pixolity.GCD.serialQueue1 com.pixolity.GCD.serialQueue2
$IWHU \RX¦YH FUHDWHG \RXU VHULDO TXHXH \RX FDQ VWDUW GLVSDWFKLQJ WDVNV WR LW XVLQJ WKH YDULRXV *&' IXQFWLRQV \RX¦YH OHDUQHG LQ WKLV ERRN 2QFH \RX DUH GRQH ZLWK WKH VHULDO GLVSDWFK TXHXH WKDW \RX¦YH MXVW FUHDWHG \RX PXVW GLVSRVH RI LW XVLQJ WKH dispatch_release IXQFWLRQ :RXOG \RX OLNH WR VHH DQ H[DPSOH" , WKRXJKW VR dispatch_queue_t firstSerialQueue = dispatch_queue_create("com.pixolity.GCD.serialQueue1", 0); dispatch_async(firstSerialQueue, ^{ NSUInteger counter = 0; for (counter = 0; counter < 5; counter++){ NSLog(@"First iteration, counter = %lu", (unsigned long)counter); } }); dispatch_async(firstSerialQueue, ^{ NSUInteger counter = 0; for (counter = 0; counter < 5; counter++){ NSLog(@"Second iteration, counter = %lu", (unsigned long)counter); } }); dispatch_async(firstSerialQueue, ^{ NSUInteger counter = 0; for (counter = 0; counter < 5; counter++){ NSLog(@"Third iteration, counter = %lu", (unsigned long)counter); }
44 | Chapter 2: Programming Grand Central Dispatch
}); dispatch_release(firstSerialQueue);
,I \RX UXQ WKLV FRGH DQG KDYH D ORRN DW WKH RXWSXW SULQWHG WR WKH FRQVROH ZLQGRZ \RX ZLOO VHH UHVXOWV VLPLODU WR WKHVH First iteration, counter = 0 First iteration, counter = 1 First iteration, counter = 2 First iteration, counter = 3 First iteration, counter = 4 Second iteration, counter = 0 Second iteration, counter = 1 Second iteration, counter = 2 Second iteration, counter = 3 Second iteration, counter = 4 Third iteration, counter = 0 Third iteration, counter = 1 Third iteration, counter = 2 Third iteration, counter = 3 Third iteration, counter = 4
,WÂŚV REYLRXV WKDW DOWKRXJK ZH GLVSDWFKHG RXU EORFN REMHFWV DV\QFKURQRXVO\ WR WKH VHULDO TXHXH WKH TXHXH KDV H[HFXWHG WKHLU FRGH LQ D ),)2 IDVKLRQ :H FDQ PRGLI\ WKH VDPH VDPSOH FRGH WR PDNH XVH RI dispatch_async_f IXQFWLRQ LQVWHDG RI WKH dispatch_async IXQFWLRQ OLNH VR void firstIteration(void *paramContext){ NSUInteger counter = 0; for (counter = 0; counter < 5; counter++){ NSLog(@"First iteration, counter = %lu", (unsigned long)counter); } } void secondIteration(void *paramContext){ NSUInteger counter = 0; for (counter = 0; counter < 5; counter++){ NSLog(@"Second iteration, counter = %lu", (unsigned long)counter); } } void thirdIteration(void *paramContext){ NSUInteger counter = 0; for (counter = 0; counter < 5; counter++){ NSLog(@"Third iteration, counter = %lu", (unsigned long)counter); } }
Constructing Your Own Dispatch Queues | 45
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ dispatch_queue_t firstSerialQueue = dispatch_queue_create("com.pixolity.GCD.serialQueue1", 0); dispatch_async_f(firstSerialQueue, NULL, firstIteration); dispatch_async_f(firstSerialQueue, NULL, secondIteration); dispatch_async_f(firstSerialQueue, NULL, thirdIteration); dispatch_release(firstSerialQueue); // Override point for customization after application launch. [self.window makeKeyAndVisible]; return YES; }
46 | Chapter 2: Programming Grand Central Dispatch