7

Mam metodę klasy, która używa dispatch_once do utworzenia statycznego obiektu. Wewnątrz bloku dispatch_once używam [self class] i zastanawiałem się, czy muszę użyć słabego odniesienia do self, aby uniknąć cyklu zatrzymania?Metoda klasy self, jeśli jest używana w bloku

+ (NSArray *)accountNames{ 
    static NSArray *names = nil; 
    static dispatch_once_t predicate; 
    dispatch_once(&predicate, ^{ 
     names = [[[self class] accounts] allKeys]; 
     names = [names sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; 
    }); 
    return names; 
} 

Jeśli używam słabe odniesienie do self otrzymuję ostrzeżenie:

+ (NSArray *)accountNames{ 
    static NSArray *names = nil; 
    static dispatch_once_t predicate; 
    __weak TUAccount *wself = self; 
    dispatch_once(&predicate, ^{ 
     names = [[[wself class] accounts] allKeys]; 
     names = [names sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; 
    }); 
    return names; 
} 

niezgodne typy wskaźnik inicjowanie 'TUAccount * __ słaby' z wyrazem typu 'const klasy'

Ponieważ dostaję ostrzeżenie, nie sądzę, żebym musiał użyć słabego odniesienia do self w tym przypadku, ale chciałem zobaczyć, co wy myśleliście.

Odpowiedz

11

Nie ma powodu, aby martwić się o cykl zatrzymywania tutaj, ponieważ nie ma sensu zatrzymywanie lub uwalnianie obiektu klasy - zachowanie i zwolnienie po prostu nie przynosi efektu.

Twoja próba podejmowania słaby odniesienia jest niewłaściwy, ponieważ biorą obiektu klasy self i próbuje rzucić go do przykład z TUAccount. Te dwie rzeczy są zupełnie inne.

Ponadto, można uprościć:

names = [[[self class] accounts] allKeys]; 

Ponieważ samo to już klasa [klasa siebie] == siebie, więc to zrobić w zamian:

names = [[self accounts] allKeys]; 
+0

Dzięki, nie jestem pewien, dlaczego, ale przy użyciu 'self' dla niektórych metod klasy nie działa, dlatego używam' [self class] 'do wywoływania wszystkich metod klasy. – keegan3d

+3

Jakieś metody klasy w szczególności - twoje lub te w frameworkach Apple'a? A co masz na myśli mówiąc "nie działa"? Prawdopodobnie jest jakiś powód. –

+0

OK zależy od miejsca wywołania metody. Na przykład dla metody klasy 'accounts', która jest moją własną metodą klasy. Mogę nazywać to przez "[self accounts]" z innych metod klasy, ale muszę używać '[[self class] kont]' w metodach instancji. Więc masz rację w powyższym przykładowym kodzie, może to być po prostu "[self accounts"]. – keegan3d

0

zostały sprawdzone jeszcze raz iOS SDK Dokumenty i tuż obok:

Cel C Przedmioty

W ręcznie referencyjnych liczone środowiska lokalne zmienne stosowane w bloku są zatrzymywane, gdy blok jest kopiowane. Użycie zmiennych instancji w bloku spowoduje zatrzymanie samego obiektu. Jeśli chcesz zastąpić to zachowanie dla konkretnej zmiennej obiektowej, możesz oznaczyć ją modyfikatorem typu __block.

Jeśli używasz ARC, zmienne obiektów są zachowywane i automatycznie zwalniane, gdy blok jest kopiowany, a następnie zwalniany.

  • Uwaga: W środowisku ze zbieraniem śmieci, jeśli zastosuje się zmienne __weak i __block do zmiennej, blok nie zapewni, że zostanie zachowany przy życiu.

Jeśli używasz blok w realizacji metody, zasady zarządzania pamięcią zmiennych instancji obiektu są bardziej subtelne:

  • Jeśli masz dostęp do zmiennej instancji przez odniesienie, self jest zachowana;
  • Jeśli uzyskasz dostęp do zmiennej instancji według wartości, zmienna zostanie zachowana.

Poniższe przykłady ilustrują dwa różne sytuacje:

dispatch_async(queue, ^{ 
    // instanceVariable is used by reference, self is retained 
    doSomethingWithObject(instanceVariable); 
}); 


id localVariable = instanceVariable; 
dispatch_async(queue, ^{ 
    // localVariable is used by value, localVariable is retained (not self) 
    doSomethingWithObject(localVariable); 
}); 

Wniosek: zakładać, że nie ma problemu z wykorzystaniem self w bloku. Zostanie zachowany, a po egzekucji zwolniony.

Co więcej, nie przechowujesz bloku w pamięci i nie używasz go bezpośrednio. Jest więc kopiowany na stos, wykonany i wypychany z niego. Nie widzę żadnych cykli zatrzymania.

Mam nadzieję, że mam rację!

+0

dzięki za info, że jest naprawdę pomocny! – keegan3d

+0

'id' jest wskaźnikiem, więc w drugiej sytuacji czy' localVariable' nadal odnosi się do tego samego obiektu co 'instanceVariable'? – Elliot

+0

@ Elliot Jeśli ustawisz nową wartość na "instanceVariable", wówczas "localVariable" nie zostanie zaktualizowane. Jeśli zmienna 'instanceVariable' jest zmienna i zostanie zmieniona, to' localVariable' odwoła się do tej samej wartości. – Nekto

Powiązane problemy