Avatar
coells
Redaktor
Avatar
coells:

Programujete v Objective-C a používáte bloky?
Přijdou vám jednoduché nebo složité?

Pro zájemce se dávám kousek kódu s vysvětlením, které se do budoucna může hodit, abyste si ušetřili námahu a vyhnuli se chybám. A pokud něčemu z toho nerozumíte, doporučil bych vyhýbat se podobným akrobaciím.

Mám aplikaci, která běží nad Cocos2D a potřeboval jsem napsat metodu, která za jednu sekundu vyvolá na instanci zadaný selector.

- (void)delayedBlockOn:(CCNode *)node receiver:(id)receiver selector:(SEL)selector
{
    CCAction *__block action = [CCActionSequence actionWithArray:@[
              [CCActionDelay actionWithDuration:1.0],
              [CCActionCallBlock actionWithBlock:
               ^{
                   objc_msgSend(receiver, selector);
                   _completed = YES;
                   [action.target stopAction:action];
               }],
              ]];
    [node runAction:action];
}

Napsat to nebylo až tak těžké.
Problém nastal ve chvíli, kdy se mi změnilo pořadí uvolňovaných objektů.
Začal jsem tedy zjišťovat, co můj kód vlastně dělá - a to už bylo horší.

Z hlediska programátora:

  • vytvoří se pole CCAction, které nechá sekvenčně běžet jednotlivé akce
  • první akce vyvolá delay
  • druhá akce zavolá selector, uloží příznak o dokončení a vyjme akci ze scheduleru
  • na závěr se akce zaregistruje do scheduleru na zadaný CCNode

Z hlediska ARC (a teď ta zajímavá část):

  • proměnná action je označená jako __block, bude alokována na heapu místo stacku
  • to je nutné, abych měl v bloku pozdní přístup k instanci, v opačném případě by se vyvolala kopie neinicializované proměnné - což by byl problém
  • instance action získá retain v bloku (ačkoliv dokumentace tvrdí opak a bloggeři každý tvrdí něco jiného)
  • funkce objc_msgSend() vyvolá selector, aniž by se ARC rozčiloval nad nejasnou sémantikou návratové hodnoty (btw, pokud metoda vrací instanci, bude to mem-leakovat), je lepší vracet void
  • instance receiver i selector získají retain v bloku
  • _completed je instanční proměnná, takže self získá retain!
  • ve chvíli, kdy dojde k uvolnění samotného bloku, vyvolá se release na receiver, selector, self i action

Jestliže máte instanci objektu, která má strong referenci na CCNode, je tohle skvělý způsob, jak skončit u memory-leaku přes retain cyklus!

Editováno 18.5.2014 23:10
 
Odpovědět 18.5.2014 23:10
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 1 zpráv z 1.