Cel ARC: mocne vs utrzymanie i słabe vs przypisanie

367

Istnieją dwa nowe atrybuty zarządzania pamięcią dla właściwości wprowadzonych przez ARC strongi weak.

Poza tym copy, co jest oczywiście czymś zupełnie innym, czy są jakieś różnice między strongvs retaina weakvs assign?

Z mojego zrozumienia, jedyną różnicą jest to, że weakprzypisze nilwskaźnik do wskaźnika, podczas gdy assignnie, co oznacza, że ​​program zawiesi się, gdy wyślę komunikat do wskaźnika po jego zwolnieniu. Ale jeśli użyję weak, tak się nigdy nie stanie, ponieważ wiadomość wysłana do nilnic nie zrobi.

Nie wiem o różnicach między strongi retain.

Czy jest jakiś powód, dla którego powinno się używać assigni retainw nowych projektach, lub są tego rodzaju są przestarzałe?

Jakub Arnold
źródło
12
Istnieją trzy nowe atrybuty zarządzania pamięcią o właściwościach wprowadzonych przez ARC strong, weaki unsafe_unretained.
NJones
5
@NJones Istnieją dwa atrybutów obiektu ( weaka strong) i 4 zmienne kwalifikatory żywotność ( __strong, __weak, __unsafe_unretained, __autoreleasing). Zobacz uwagi ARC poniżej.
Snowcrash,
1
@SnowCrash Była wersja Xcode, prawdopodobnie wersja dla programistów, w której użycie assignpodczas kompilacji z ARC było błędem. Istnieje wiele usuniętych odpowiedzi na ten temat. Wygląda na to, że zostało zmienione przed ostatecznym wydaniem. unsafe_unretainedjest preferowanym atrybutem dla wielu z nas wczesnych użytkowników. Aby dowieść, że unsafe_unretainedjest to prawidłowy atrybut, zapoznaj się z „Programowaniem z celem C” firmy Apple w sekcji „Hermetyzowanie danych” pod podtytułem „Używaj niebezpiecznych bezpiecznych odwołań dla niektórych klas”. Co mówi: „W przypadku właściwości oznacza to użycie atrybutu unsafe_unretained:”
NJones

Odpowiedzi:

230

Od informacji o przejściu do wersji ARC (przykład w sekcji dotyczącej atrybutów właściwości).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

Tak strongsamo jak retainw deklaracji majątkowej.

W przypadku projektów ARC strongzamiast tego retainużyłbym assigndla pierwotnych właściwości C i weaksłabych odniesień do obiektów Objective-C.

JeremyP
źródło
11
W rzeczywistości w ARC jest to błąd kompilacji, który można zastosować assigndla obiektu. Trzeba użyć jednej weaklub unsafe_unretained(co jest niebezpieczne, oczywiście), jeśli nie chcesz, aby zachować właściwości.
cobbal
5
assignkompiluje mi się dobrze w projektach ARC z celem wdrożenia 4.0.
Pascal
8
@Pascal: słabe odniesienia nie są dozwolone w obiektach docelowych wdrażania, w których system operacyjny nie ma wersji 5.0 lub wyższej. Tak więc w przypadku starszych projektów nadal możesz używać przypisania, ale jeśli przejdziesz do nowszych wersji, musisz przełączyć się na słabe
Mattia
1
Wygląda na to, Xcode 4 (z ARC) generuje NSManagedObject podklasy pomocą retainVs. strong. Przypuszczam, że to w większości nieszkodliwe, ale wyobrażam sobie, że powinno to być strongdla spójności ... a może to nie ma znaczenia. stackoverflow.com/questions/7796476/…
Joe D'Andrea
3
@JeremyP Tak, twoja odpowiedź jest natychmiastowa. Reagowałem na @Mattia. Wskazałem, że assignw niektórych przypadkach jest to nadal aktualne.
Steven Oxley,
606

Po przeczytaniu tylu artykułów Posty Stackoverflow i aplikacje demonstracyjne, aby sprawdzić atrybuty właściwości zmiennych, postanowiłem zebrać wszystkie informacje o atrybutach razem:

  1. atomic // default
  2. nieatomowy
  3. strong = zachowaj // default
  4. słaby
  5. zachować
  6. przypisać // domyślnie
  7. unsafe_unretained
  8. Kopiuj
  9. tylko czytać
  10. readwrite // default

Poniżej znajduje się szczegółowy link do artykułu, w którym można znaleźć wyżej wymienione wszystkie atrybuty, które na pewno Ci pomogą. Ogromne podziękowania dla wszystkich ludzi, którzy udzielają tutaj najlepszych odpowiedzi !!

Zmienne atrybuty właściwości lub modyfikatory w iOS

1. silny (iOS4 = zachowaj)

  • mówi „trzymaj to w kupie, dopóki nie wskażę więcej”
  • innymi słowy „Jestem właścicielem, nie możesz cofnąć przydziału, zanim celujesz dobrze, zachowując”
  • Używasz silnego tylko wtedy, gdy musisz zatrzymać obiekt.
  • Domyślnie wszystkie zmienne instancji i zmienne lokalne są silnymi wskaźnikami.
  • Zwykle używamy silnych dla UIViewControllers (rodziców elementu interfejsu użytkownika)
  • strong jest używany z ARC i zasadniczo pomaga ci, nie martwiąc się o liczbę zatrzymań obiektu. ARC automatycznie zwalnia go, gdy skończysz. Użycie słowa kluczowego strong oznacza, że ​​jesteś właścicielem obiektu.

Przykład:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2. słaby -

  • mówi „zachowaj to tak długo, jak długo ktoś inny na to mocno wskazuje”
  • to samo co przypisanie, brak zachowania lub zwolnienia
  • „Słaba” referencja to referencja, której nie zachowujecie.
  • Zwykle używamy słaby dla IBOutlets (Childs UIViewController). Działa to, ponieważ obiekt potomny musi istnieć tylko tak długo, jak obiekt macierzysty.
  • słabe odwołanie to odwołanie, które nie chroni obiektu, do którego istnieje odwołanie, przed zbieraniem przez moduł odśmiecający.
  • Słaby jest w istocie przypisany, nieokreśloną właściwością. Z wyjątkiem momentu zwolnienia obiektu słaby wskaźnik jest automatycznie ustawiany na zero

Przykład:

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Mocne i słabe wyjaśnienia, dzięki BJ Homer :

Wyobraź sobie, że naszym przedmiotem jest pies i że pies chce uciec (zostać zwolniony).

Silne wskazówki są jak smycz dla psa. Dopóki masz przymocowaną do psa smycz, pies nie ucieknie. Jeśli pięć osób przywiąże smycz do jednego psa (pięć silnych wskaźników do jednego obiektu), pies nie ucieknie, dopóki wszystkie pięć smyczy nie zostanie odłączonych.

Z drugiej strony, słabe wskaźniki są jak małe dzieci wskazujące na psa i mówiące: „Patrz! Pies!” Tak długo, jak pies jest nadal na smyczy, małe dzieci nadal mogą go widzieć i nadal będą go wskazywać. Gdy tylko wszystkie smycze zostaną odpięte, pies ucieka bez względu na to, ile małych dzieci na niego wskazuje.

Gdy ostatni silny wskaźnik (smycz) nie będzie już wskazywał na obiekt, obiekt zostanie zwolniony, a wszystkie słabe wskaźniki zostaną wyzerowane.

Kiedy używamy słabego?

Jedynym czasem, w którym chciałbyś użyć słabego, jest to, że chcesz uniknąć zatrzymywania cykli (np. Rodzic zachowuje dziecko, a dziecko zachowuje rodzica, więc żadne z nich nie zostanie nigdy zwolnione).

3. pozostań = silny

  • jest zachowywany, stara wartość jest zwalniana i przypisywane jest zachowanie określa, że ​​nowa wartość powinna zostać wysłana
  • zachowaj przy przypisaniu, a stara wartość zostanie wysłana -release
  • Zachowaj jest taki sam jak silny.
  • Apple mówi, że jeśli napiszesz, zachowaj to automatycznie przekonwertuje / będzie działać jak tylko silny.
  • metody takie jak „przydziel” obejmują domyślnie „zachowaj”

Przykład:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4. przypisać

  • Przypisanie jest ustawieniem domyślnym i po prostu wykonuje przypisanie zmiennej
  • assign jest atrybutem właściwości, który informuje kompilator, jak zsyntetyzować implementację metody ustawiającej właściwość
  • Chciałbym użyć przypisania dla pierwotnych właściwości C i słabego dla słabych odniesień do obiektów Objective-C.

Przykład:

@property (nonatomic, assign) NSString *address;

@synthesize address;
swiftBoy
źródło
5
2. „słabe odwołanie to odwołanie, które nie chroni obiektu, do którego istnieje odwołanie, przed zbieraniem przez moduł odśmiecający” - w celu c nie ma czegoś takiego jak moduł odśmiecający;
Bucherland,
1
a tą hierarchią zarządza automatycznie iOS. Przeczytaj o koncepcji MVC. Mam na myśli, że podczas prezentacji ViewContorller iOS ładuje swoją hierarchię widoków na ekranie (tworząc brakujące widoki). Kiedy prezentowany jest inny ViewController, ta pierwsza hierarchia widoków jest zwalniana. Ale jeśli masz „silny” w ViewController, wtedy tego widoku nie można cofnąć przydziału, gdy jest poza ekranem. Co może mieć duży wpływ na pamięć urządzenia i powodować spowolnienie działania aplikacji. (Oczywiście, urządzenie ma dużo pamięci i na pewno dobrze by było w aplikacji 5-10, ale w ogromnej aplikacji masz kłopoty)
bucherland
1
Kiedy używamy słabego? 1. W przypadku obiektów interfejsu użytkownika, 2. delegatów, 3. bloków (slaveSelf powinien być używany zamiast self, aby uniknąć cykli pamięci (jak wspomniano powyżej)
bucherland
1
Jest jedna pomyłka w tej wspaniałej odpowiedzi - silna - „ARC automatycznie wypuszcza ją dla ciebie, kiedy skończysz”, to nie jest właściwe. ARC automatycznie uwalnia słabe obiekty, gdy nie ma do nich wskaźników. Mocny - jest synonimem do zachowania, więc obiekt jest zachowany i naszym obowiązkiem jest uczynienie go zerowym
Ashwin G
1
@RDC, co to defaultznaczy? Jeśli korzystam @property (nonatomic) NSString *stringto jest strong? Czy assign? Ponieważ oba są domyślne.
Iulian Onofrei
40

nieatomowy / atomowy

  • nonatomowy jest znacznie szybszy niż atomowy
  • zawsze używaj nonatomic, chyba że masz bardzo specyficzne wymagania dla atomu, co powinno być rzadkie (atom nie gwarantuje bezpieczeństwa wątku - tylko blokuje dostęp do właściwości, gdy jest jednocześnie ustawiany przez inny wątek)

silny / słaby / przypisać

  • użyj silnego, aby zachować obiekty - chociaż słowo kluczowe zachowaj jest synonimem, najlepiej zamiast tego użyć silnego
  • użyj słabego, jeśli chcesz tylko wskaźnik do obiektu bez zachowania go - przydatne w celu uniknięcia cykli przechowywania (tj. delegatów) - automatycznie wyzeruje wskaźnik po zwolnieniu obiektu
  • użyj przypisania do prymitywów - dokładnie tak jak słaby, ale nie zwalnia obiektu po zwolnieniu (domyślnie ustawione)

(Opcjonalny)

Kopiuj

  • użyj go do stworzenia płytkiej kopii obiektu
  • dobrą praktyką, aby zawsze ustawiać właściwości niezmienne na kopiowanie - ponieważ wersje zmienne można przenosić na właściwości niezmienne, kopiowanie zapewni, że zawsze będziesz mieć do czynienia z obiektem niezmiennym
  • jeśli zostanie przekazany niezmienny obiekt, zachowa go - jeśli zostanie przekazany obiekt zmienny, skopiuje go

tylko czytać

  • użyj go, aby wyłączyć ustawienie właściwości (zapobiega kompilacji kodu w przypadku wykroczenia)
  • możesz zmienić zawartość dostarczaną przez moduł pobierający, zmieniając zmienną bezpośrednio za pomocą zmiennej instancji lub w samej metodzie metody pobierającej
Vadoff
źródło
@ Sakthimuthiah ma rację, musisz poprawić swoją odpowiedź.
Adela Toderici,
@ Sakthimuthiah jest niepoprawny (i każdy, kto to mówi). Atomic NIE sprawia, że ​​wątek jest bezpieczny, choć można go łatwo pomylić ze względu na jego zachowanie. Proszę przeczytać: stackoverflow.com/questions/12347236/...
Chris J
39

O ile wiem strongi retainsą synonimami, więc robią dokładnie to samo.

Wtedy weakjest prawie jak assign, ale automatycznie ustawia się na zero po tym, jak obiekt, na który wskazuje, jest zwolniony.

Oznacza to, że możesz je po prostu wymienić.

Jednakże , istnieje jeden szczególny przypadek z jaką się spotkałem, gdzie miałem do użytku assign, zamiast weak. Powiedzmy, że mamy dwie właściwości delegateAssigni delegateWeak. W obu jest przechowywany nasz delegat, który jest naszym właścicielem, mając jedyne silne odniesienie. Delegat dokonuje dezalokacji, więc -deallocwywoływana jest również nasza metoda.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

Delegat jest już w trakcie procesu zwolnienia, ale nadal nie jest całkowicie zwolniony. Problem polega na tym, że weakodniesienia do niego zostały już unieważnione! Właściwość delegateWeakzawiera zero, ale delegateAssignzawiera prawidłowy obiekt (wszystkie właściwości zostały już zwolnione i unieważnione, ale nadal są prawidłowe).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

Jest to dość szczególny przypadek, ale pokazuje nam, jak działają te weakzmienne i kiedy są one zerowane.

Tricertops
źródło
20

Dokument Clanga na temat automatycznego liczenia referencyjnego Objective-C (ARC) wyjaśnia jasno kwalifikatory własności i modyfikatory:

Istnieją cztery kwalifikatory własności:

  • __ autoreleasing
  • __ silny
  • __ * unsafe_unretained *
  • __ słaby

Typ jest nontrivially własność wykwalifikowanych jeśli jest kwalifikowane __ autoreleasing , __ silnego lub __ słaby .

Następnie istnieje sześć modyfikatorów własności deklarowanej własności:

  • przypisanie implikuje __ * unsafe_unretained * własność.
  • kopiowanie oznacza __ silną własność, a także zwykłe zachowanie semantyki kopiowania na seterze.
  • zachowaj oznacza __ silną własność.
  • silny oznacza __ silną własność.
  • * unsafe_unretained * oznacza __ * unsafe_unretained * własność.
  • słaby oznacza __ słabą własność.

Z wyjątkiem słabych , modyfikatory te są dostępne w trybach innych niż ARC.

Jeśli chodzi o semantykę, kwalifikatory własności mają różne znaczenie w pięciu zarządzanych operacjach : Czytanie, Przydział, Inicjalizacja, Zniszczenie i Przenoszenie, w których przez większość czasu zależy nam tylko na różnicy w działaniu Przypisanie.

Przypisanie następuje podczas oceny operatora przypisania. Semantyka różni się w zależności od kwalifikacji:

  • W przypadku __ silnych obiektów najpierw zachowywana jest nowa pointee; po drugie, wartość jest ładowana prymitywną semantyką; po trzecie, nowy pointee jest przechowywany w wartości z prymitywną semantyką; i wreszcie, stary pointee zostaje zwolniony. Nie jest to wykonywane atomowo; należy zastosować zewnętrzną synchronizację, aby było to bezpieczne w obliczu jednoczesnych obciążeń i magazynów.
  • W przypadku __ słabych obiektów wartość jest aktualizowana, aby wskazywała nowy punkt, chyba że nowy punkt jest obiektem podlegającym obecnie dealokacji, w którym to przypadku wartość jest aktualizowana do wskaźnika zerowego. Musi to zostać wykonane atomowo w odniesieniu do innych przypisań do obiektu, odczytów z obiektu i ostatecznego wydania nowego pointee.
  • W przypadku obiektów __ * unsafe_unretained * nowy pointee jest przechowywany w wartości za pomocą prymitywnej semantyki.
  • W przypadku __ obiektów autoreleasingu nowy pointee zostaje zachowany, automatycznie wydany i zapisany w wartości za pomocą prymitywnej semantyki.

Inna różnica w czytaniu, inicjowaniu, niszczeniu i przenoszeniu znajduje się w rozdziale 4.2 Semantyka w dokumencie .

Mingming
źródło
6

Aby zrozumieć silną i słabą referencję, rozważ poniższy przykład, załóżmy, że mamy metodę o nazwie displayLocalVariable.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

W powyższej metodzie zakres zmiennej myName jest ograniczony do metody displayLocalVariable, po zakończeniu metody zmienna myName, która zawiera ciąg „ABC”, zostanie zwolniona z pamięci.

Co jeśli chcemy zachować wartość zmiennej myName przez cały cykl życia kontrolera widoku. W tym celu możemy utworzyć właściwość o nazwie nazwa użytkownika, która będzie miała silne odwołanie do zmiennej myName (patrz self.username = myName;poniższy kod), jak poniżej,

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Teraz w powyższym kodzie widać, że mojaNazwa została przypisana do self.username, a self.username ma silne odniesienie (jak zadeklarowaliśmy w interfejsie za pomocą @property) do myName (pośrednio ma silne odniesienie do łańcucha „ABC”). Dlatego ciąg myName nie zostanie zwolniony z pamięci, dopóki self.username nie będzie żył.

  • Słabe referencje

Zastanówmy się teraz nad przypisaniem myName do dummyName, które jest słabym odniesieniem, self.dummyName = myName; W przeciwieństwie do silnego odwołania Słaby będzie przechowywać myName tylko do momentu, gdy będzie silne odniesienie do myName. Zobacz poniższy kod, aby zrozumieć Słabe referencje,

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

W powyższym kodzie jest Słabe odniesienie do myName (tzn. Self.dummyName ma Słabe odniesienie do myName), ale nie ma silnego odwołania do myName, dlatego self.dummyName nie będzie w stanie utrzymać wartości myName.

Teraz ponownie rozważ poniższy kod,

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

W powyższym kodzie self.username ma silne odwołanie do myName, stąd self.dummyName będzie miało teraz wartość myName nawet po zakończeniu metody, ponieważ myName ma z nim związane silne odwołanie.

Teraz za każdym razem, gdy odwołujemy się do zmiennej, jej liczba zatrzymań jest zwiększana o jeden, a zmienna nie zostanie cofnięta przy zatrzymaniu, osiąga wartość 0.

Mam nadzieję że to pomoże.

Mahadev Mandale
źródło
2

Silny:

  • Właściwość nie ulegnie zniszczeniu, ale dopiero po ustawieniu właściwości na zero obiekt zostanie zniszczony
  • Domyślnie wszystkie zmienne instancji i zmienne lokalne są silnymi wskaźnikami.
  • Używasz silnego tylko wtedy, gdy musisz zatrzymać obiekt.
  • Zwykle używamy silnych dla UIViewControllers (rodziców elementu interfejsu użytkownika)
  • IOS 4 (bez ARC) Możemy użyć opcji Zachowaj słowo kluczowe
  • IOS 5 (ARC) Możemy użyć silnego słowa kluczowego

Przykład: @property (silny, nieatomowy) ViewController * viewController;

@synthesize viewController;

Słaby

Domyślnie automatycznie dostaje się i ustawia na zero

  • Zwykle używamy słaby dla IBOutlets (dzieci UIViewController) i delegować
  • to samo co przypisanie, brak zachowania lub zwolnienia

Przykład: @property (słaby, nieatomowy) IBOutlet UIButton * myButton;

@synthesize myButton;

Nikunj Patel
źródło
1

Różnice między silnymi i zachowującymi:

  • W iOS4 strong jest równe zachowaniu
  • Oznacza to, że jesteś właścicielem obiektu i trzymasz go na stosie, dopóki go nie wskażesz
  • Jeśli napiszesz, zachowaj to automatycznie działa tak samo, jak silne

Różnice między słabym a przypisaniem:

  • „Słabe” odniesienie to odniesienie, którego nie zachowuje się i utrzymuje się je tak długo, jak długo ktoś inny wskazuje je mocno
  • Kiedy obiekt zostaje „zwolniony”, słaby wskaźnik jest automatycznie ustawiany na zero
  • Atrybut właściwości „przypisać” informuje kompilator, jak zsyntetyzować implementację metody ustawiającej właściwość
Chen Rui
źródło