@property zachowują, przypisują, kopiują, nieatomowe w Objective-C

214

Jako ktoś, kto jest nowy w Celu C, może ktoś dać mi przegląd zachowania, przypisania, kopiowania i wszystkich innych, których mi brakuje, które są zgodne z dyrektywą @property? Co oni robią i dlaczego miałbym chcieć używać jednego nad drugim?

Mark Reid
źródło
1
Apple nazywa je „atrybuty” lub „atrybuty własności”
Nevan King

Odpowiedzi:

273

Artykuł powiązany z MrMage już nie działa. Oto, czego nauczyłem się w moim (bardzo) krótkim czasie kodowania w Objective-C:

nonatomic vs. atomic - domyślnym jest „atomic”. Zawsze używaj „nieatomowych”. Nie wiem dlaczego, ale w książce, którą czytałem, jest „rzadko kiedy jest powód”, by używać „atomu”. (BTW: Przeczytałem książkę BNR „Programowanie na iOS”.)

readwrite vs. readonly - „readwrite” jest ustawieniem domyślnym. Kiedy @synthesize zostanie utworzony zarówno getter, jak i setter. Jeśli użyjesz opcji „tylko do odczytu”, nie zostanie utworzony program ustawiający. Użyj go dla wartości, której nie chcesz nigdy zmieniać po utworzeniu wystąpienia obiektu.

zachowaj vs. kopiuj vs. przypisaj

  • „Przypisz” jest ustawieniem domyślnym. W seterze utworzonym przez @synthesize wartość zostanie po prostu przypisana do atrybutu. Rozumiem, że „atrybut” powinien być używany w przypadku atrybutów niepochodzących ze wskaźnika.
  • „zachowaj” jest potrzebne, gdy atrybut jest wskaźnikiem do obiektu. Setter wygenerowany przez @synthesize zachowa (inaczej dodając liczbę zatrzymań) obiekt. Po zakończeniu musisz zwolnić obiekt.
  • „kopia” jest potrzebna, gdy obiekt jest modyfikowalny. Użyj tego, jeśli potrzebujesz wartości obiektu w tej chwili i nie chcesz, aby ta wartość odzwierciedlała wszelkie zmiany wprowadzone przez innych właścicieli obiektu. Będziesz musiał zwolnić obiekt, gdy skończysz go, ponieważ zachowujesz kopię.
Blamdarot
źródło
@Blamdarot - czy muszę go również wydać z ARC
Dejell
10
@Odelya - Nie. Jeśli zwolnisz podczas korzystania z ARC, uważam, że pojawi się błąd kompilatora.
Blamdarot,
52
„Zawsze używaj substancji nieatomowych” to zła rada. Powinieneś wiedzieć, z czego rezygnujesz, gdy używasz substancji nieatomowych.
Jesse Rusak
7
Zgoda. W szczególności wiele osób nie zdaje sobie sprawy, że wartości nieatomowe nie są automatycznie uwalniane przez program pobierający. nieatomowy jest często odpowiedni, ale programowanie kultu ładunku rzadko.
Catfish_Man
9
Poradzenie, aby pozostawić wartość domyślną, atomicjest tak samo złe, jak doradztwo nonatomic. Żaden wybór nie jest „właściwy”, więc projektanci języków wybrali bezpieczniejsze z tych dwóch rozwiązań. W rzeczywistości nonatomicjest ogólnie lepszym wyborem, ponieważ pomija bardzo drogie zamki gwintowane. Jedynym powodem atomicjest to, że twoja właściwość może być ustawiona z wielu wątków (w takim przypadku jej pominięcie może doprowadzić do nadmiernego zwolnienia lub wycieku).
Adam Kaplan
295

Zanim dowiesz się o atrybutach @property, powinieneś wiedzieć, jakie jest zastosowanie @property.

  • @property oferuje sposób definiowania informacji, które klasa ma hermetyzować. Jeśli zadeklarujesz obiekt / zmienną za pomocą @property , wówczas ten obiekt / zmienna będzie dostępny dla innych klas importujących jego klasę.

  • Jeśli zadeklarujesz obiekt za pomocą @property w pliku nagłówkowym, musisz go zsyntetyzować za pomocą @synthesize w pliku implementacyjnym. Dzięki temu obiekt jest zgodny z KVC . Domyślnie kompilator zsyntetyzuje metody dostępu dla tego obiektu.

  • metodami dostępowymi są: setter i getter.

Przykład: .h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

Teraz kompilator zsyntetyzuje metody dostępu dla nazwy .

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • Lista atrybutów właściwości @

    atomowy, nieatomowy, zachowaj, kopiuj, tylko do odczytu, do odczytu, przypisuj, mocny, getter = metoda, setter = metoda, unsafe_unretained

  • atomowe jest zachowaniem domyślnym. Jeśli obiekt zostanie zadeklarowany jako atomowy, staje się bezpieczny dla wątków. Bezpieczeństwo wątków oznacza, że ​​jednocześnie tylko jeden wątek określonej instancji tej klasy może mieć kontrolę nad tym obiektem.

Jeśli wątek wykonuje metodę gettera, inny wątek nie może wykonać metody ustawiającej dla tego obiektu. To jest wolne.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • nonatomic nie jest bezpieczny dla nici. Możesz użyć atrybutu właściwości nonatomic, aby określić, że zsyntetyzowane akcesoria po prostu ustawiają lub zwracają wartość bezpośrednio, bez żadnych gwarancji, co się stanie, jeśli ta sama wartość będzie dostępna jednocześnie z różnych wątków.

Z tego powodu dostęp do właściwości nieatomowych jest szybszy niż atomowy.

@property (nonatomic)NSString *name;   
  • Zachowanie jest wymagane, gdy atrybut jest wskaźnikiem do obiektu.

Metoda settera zwiększy liczbę zatrzymań obiektu, dzięki czemu zajmie on pamięć w puli autorelease.

@property (retain)NSString *name;
  • kopiuj Jeśli używasz kopiowania, nie możesz użyć zachowaj. Korzystanie z kopii instancji klasy będzie zawierało własną kopię.

Nawet jeśli zmienny ciąg zostanie ustawiony, a następnie zmieniony, instancja przechwytuje dowolną wartość, jaką ma w momencie jego ustawienia. Żadne metody ustawiające i pobierające nie będą syntezowane.

@property (copy) NSString *name;

teraz,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

imię pozostanie niezmienione.

  • readonly Jeśli nie chcesz zezwalać na zmianę właściwości metodą setter, możesz zadeklarować właściwość tylko do odczytu.

Kompilator wygeneruje getter, ale nie ustawiający.

@property (readonly) NSString *name;
  • readwrite to zachowanie domyślne. Nie musisz jawnie określać atrybutu readwrite.

Jest to przeciwieństwo tylko do odczytu.

@property (readwrite) NSString *name;
  • Przypisanie wygeneruje obiekt ustawiający, który przypisuje wartość bezpośrednio do zmiennej instancji, zamiast kopiować ją lub zachowywać. Jest to najlepsze w przypadku prymitywnych typów, takich jak NSInteger i CGFloat, lub obiektów, których bezpośrednio nie posiadasz, takich jak delegaci.

Pamiętaj, że zachowaj i przypisz są zasadniczo wymienne, gdy jest włączone odśmiecanie.

@property (assign) NSInteger year;
  • strong jest zamiennikiem retain.

Pochodzi z ARC.

@property (nonatomic, strong) AVPlayer *player; 
  • getter = metoda Jeśli chcesz użyć innej nazwy dla metody gettera, możesz określić niestandardową nazwę poprzez dodanie atrybutów do właściwości.

W przypadku właściwości boolowskich (właściwości, które mają wartość TAK lub NIE) zwyczajowo metoda gettera zaczyna się od słowa „jest”

@property (getter=isFinished) BOOL finished;
  • setter = method Jeśli chcesz użyć innej nazwy dla metody setter, możesz określić niestandardową nazwę poprzez dodanie atrybutów do właściwości.

Metoda powinna kończyć się dwukropkiem.

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained Istnieje kilka klas w Cocoa i Cocoa Touch, które nie obsługują jeszcze słabych referencji, co oznacza, że ​​nie można zadeklarować słabej właściwości lub słabej zmiennej lokalnej, aby je śledzić. Do tych klas należą NSTextView, NSFont i NSColorSpace itp. Jeśli potrzebujesz użyć słabego odwołania do jednej z tych klas, musisz użyć niebezpiecznego odwołania.

Niebezpieczne odwołanie jest podobne do słabego odniesienia, ponieważ nie utrzymuje przy życiu powiązanego obiektu, ale nie zostanie ustawione na zero, jeśli obiekt docelowy zostanie zwolniony.

@property (unsafe_unretained) NSObject *unsafeProperty;

Jeśli musisz podać wiele atrybutów, po prostu dołącz je jako listę oddzieloną przecinkami, na przykład:

@property (readonly, getter=isFinished) BOOL finished;
Liza
źródło
Dodatkowo słaby oznacza, że ​​nie ma licznika odwołań do odwołania do obiektu, ale że jest on w ogóle odwoływany lub w ogóle nie ma odniesienia. Coś w rodzaju „tak, coś do mnie odnosiło się” vs. „istnieje 9 odniesień do mnie” (co jest silne).
Alex Zavatone,
6
Zignoruj ​​wiersz w odpowiedzi na temat wyrzucania elementów bezużytecznych, ponieważ jest ono przestarzałe w systemie Mac OS X i nie istnieje w dokumentacji systemu iOS dla Apple .
Basil Bourque
4
„Uwaga: atomowość właściwości nie jest synonimem bezpieczeństwa wątku obiektu.” - from developer.apple.com/library/mac/documentation/Cocoa/Conceptual/...
jk7
1
„Jeśli zadeklarujesz obiekt za pomocą @propertypliku nagłówka, musisz go zsyntetyzować za pomocą @synthesizepliku implementacji.” Nie zawsze. Na przykład: „Domyślnie readwritewłaściwość będzie wspierana przez zmienną instancji, która ponownie zostanie automatycznie zsyntetyzowana przez kompilator”. Od dok .
Franklin Yu,
4
@liza To doskonała odpowiedź. Dlaczego nie jest to akceptowana odpowiedź. Przedstawia o wiele bardziej zrozumiałe wyjaśnienie niż obecnie akceptowana odpowiedź. Czasami nie rozumiem StackOverflow?
Charles Robertson,
149

Po przeczytaniu wielu artykułów postanowiłem zebrać wszystkie informacje o atrybutach razem:

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

Poniżej znajduje się link do szczegółowego artykułu, w którym można znaleźć te atrybuty.

Ogromne podziękowania dla wszystkich ludzi, którzy udzielają tutaj najlepszych odpowiedzi !!

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

Oto przykładowy opis z artykułu

  1. atomowy -Atomowy oznacza, że ​​tylko jeden wątek uzyskuje dostęp do zmiennej (typ statyczny). -Atomika jest bezpieczna dla wątków. -Ale jego wydajność jest niska -Akatomiczne jest zachowanie domyślne -Akcesoria akcesoryjne w środowisku bez odśmiecania (tj. przy użyciu zachowania / zwolnienia / automatycznego uwalniania) użyją blokady, aby upewnić się, że inny wątek nie zakłóci prawidłowego ustawienia / pobierania wartości. -nie jest tak naprawdę słowem kluczowym.

Przykład:

@property (retain) NSString *name;

@synthesize name;
  1. nonatomic -Nonatomic środki dostępu wielokrotnego gwint zmienny (dynamiczny) typu. -Nieatomowy jest niebezpieczny dla nici. -Ale jest szybki w działaniu -Nieatomowy NIE jest zachowaniem domyślnym, musimy dodać nieatomowe słowo kluczowe w atrybucie właściwości. - może powodować nieoczekiwane zachowanie, gdy dwa różne procesy (wątki) uzyskują dostęp do tej samej zmiennej w tym samym czasie.

Przykład:

@property (nonatomic, retain) NSString *name;

@synthesize name;

Wyjaśnić:

Załóżmy, że istnieje właściwość ciągu atomowego o nazwie „nazwa”, a jeśli wywołasz [self setName: @ „A”] z wątku A, wywołaj [self setName: @ „B”] z wątku B i wywołaj [self name] z wątek C, wtedy wszystkie operacje na innym wątku będą wykonywane szeregowo, co oznacza, że ​​jeśli jeden wątek wykonuje setter lub getter, wówczas inne wątki będą czekać. To sprawia, że ​​właściwość „nazwa” odczytuje / zapisuje bezpiecznie, ale jeśli inny wątek D wywoła [uwolnienie nazwy] jednocześnie, wówczas ta operacja może spowodować awarię, ponieważ nie jest tu zaangażowane wywołanie setter / getter. Co oznacza, że ​​obiekt jest bezpieczny do odczytu / zapisu (ATOMIC), ale nie jest bezpieczny dla wątków, ponieważ inne wątki mogą jednocześnie wysyłać do obiektu wiadomości dowolnego typu. Deweloper powinien zapewnić bezpieczeństwo wątków dla takich obiektów.

Jeśli właściwość „name” była nieatomowa, wówczas wszystkie wątki w powyższym przykładzie - A, B, C i D wykonają się jednocześnie, dając dowolny nieprzewidywalny wynik. W przypadku atomu, jeden z A, B lub C wykona się jako pierwszy, ale D może nadal wykonać równolegle.

  1. strong (iOS4 = zachowaj) - mówi „trzymaj to w kupie, dopóki nie wskażę na to więcej” - innymi słowy „Jestem właścicielem, nie możesz cofnąć przydziału, zanim celujesz dobrze tym samym co zachowaj” - Używasz silnego tylko wtedy, gdy musisz zatrzymać obiekt. - Domyślnie wszystkie zmienne instancji i zmienne lokalne są silnymi wskaźnikami. -Zazwyczaj używamy silnego dla UIViewControllers (rodziców przedmiotu UI) -mocny jest używany z ARC i zasadniczo pomaga, 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;
  1. słaby (iOS4 = unsafe_unretained) - mówi „zachowaj to tak długo, jak długo ktoś wskazuje na to mocno” - to samo co przypisanie, brak zachowania lub zwolnienia - „Słaby” odnośnik to odnośnik, którego nie zachowujesz. -Na ogół 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. -Weak jest zasadniczo przypisaną, nie posiadającą własnoś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ć. Jak 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).

  1. retain = strong -it jest zachowywany, stara wartość jest zwalniana i przypisywana -retain określa, że ​​nowa wartość powinna zostać wysłana -retain przy przypisaniu, a stara wartość wysłana -release -retain jest taka sama jak mocna. -apple mówi, że jeśli napiszesz zachowaj, automatycznie przekonwertuje się / będzie działać jak tylko silny. -metody takie jak „przydzielić” obejmują domyślnie „zachowaj”

Przykład:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. przypisanie-przypisanie jest ustawieniem domyślnym i po prostu wykonuje przypisanie zmiennej -przypisanie jest atrybutem właściwości, który informuje kompilator, jak zsyntetyzować implementację ustawiacza właściwości. Użyłbym przypisania dla pierwotnych właściwości C i słabych dla słabych odniesień do obiektów Celu-C.

Przykład:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. unsafe_unretained

    -unsafe_unretained to kwalifikator własności, który mówi ARC, jak wstawiać wywołania zatrzymania / zwolnienia -unsafe_unretained to wersja ARC przypisania.

Przykład:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. kopiowanie-kopiowanie jest wymagane, gdy obiekt jest modyfikowalny. -copy określa, że ​​nowa wartość powinna zostać wysłana -copy po przypisaniu, a stara wartość wysłana -release. -copy jest jak retain zwraca obiekt, który musisz jawnie zwolnić (np. w dealloc) w środowiskach nie śmieciowych. -Jeśli używasz kopiowania, nadal musisz zwolnić to w dealloc. -Użyj tego, jeśli potrzebujesz wartości obiektu taką, jaka jest w tej chwili, i nie chcesz, aby ta wartość odzwierciedlała wszelkie zmiany wprowadzone przez innych właścicieli obiektu. Będziesz musiał zwolnić obiekt, gdy skończysz go, ponieważ zachowujesz kopię.

Przykład:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;
swiftBoy
źródło
2
Myślę, że po łuku retain nie jest już używany.
mert
1
na pełnej liście brakuje 2 pozycji opcji: setter i getter, które są jedynymi opcjami wymagającymi argumentu.
Scott Chu,
silna lub zachowaj jest domyślna tylko dla typu obiektu. Nie można go używać do typów pierwotnych.
Saleh Enam Shohag,
9

Dostęp do właściwości atomowych może mieć tylko jeden wątek na raz. Jest bezpieczny dla wątków . Domyślnie jest to atom. Należy pamiętać, że nie ma słowa kluczowego atomic

Nonatomic oznacza, że ​​wiele wątków może uzyskać dostęp do elementu. Jest to wątek niebezpieczny

Dlatego należy zachować ostrożność podczas korzystania z atomu. Ponieważ wpływa to na wydajność twojego kodu

Kannan Prasad
źródło
3
„Uwaga: atomowość właściwości nie jest synonimem bezpieczeństwa wątku obiektu.” from developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7