Powiedzmy, że mam klasę o nazwie SomeClass
o nazwie string
właściwości:
@interface SomeClass : NSObject
{
NSString* name;
}
@property (nonatomic, retain) NSString* name;
@end
Rozumiem, że nazwa może być przypisana, NSMutableString
w którym to przypadku może to prowadzić do błędnego zachowania.
- Czy w przypadku ciągów zawsze dobrym pomysłem jest użycie
copy
atrybutu zamiastretain
? - Czy właściwość „skopiowana” jest w jakikolwiek sposób mniej wydajna niż właściwość „zachowana”?
objective-c
cocoa
cocoa-touch
PlagueHammer
źródło
źródło
name
zostać wydanedealloc
czy nie?Odpowiedzi:
W przypadku atrybutów, których typem jest niezmienna klasa wartości zgodna z
NSCopying
protokołem, prawie zawsze należy określićcopy
w@property
deklaracji. Określanieretain
jest czymś, czego prawie nigdy nie chcesz w takiej sytuacji.Oto dlaczego chcesz to zrobić:
Bieżąca wartość
Person.name
właściwości będzie różna w zależności od tego, czy właściwość jest zadeklarowana,retain
czycopy
- będzie,@"Debajit"
jeśli właściwość zostanie oznaczonaretain
, ale@"Chris"
jeśli właściwość zostanie oznaczonacopy
.Ponieważ w prawie wszystkich przypadkach chcesz zapobiec mutowaniu atrybutów obiektu za jego plecami, powinieneś zaznaczyć właściwości je reprezentujące
copy
. (A jeśli sam piszesz seter zamiast go używać@synthesize
, powinieneś pamiętać, aby go używaćcopy
zamiastretain
niego.)źródło
NSMutableString
, z wyjątkiem przejściowego typu „ kreatora ciągów” (z którego natychmiast biorę niezmienną kopię). Wolałbym, aby były to typy dyskretne - ale pozwolę, że fakt, że kopia może zachować, jeśli oryginalny ciąg nie jest modyfikowalny, łagodzi większość moich obaw.Kopia powinna być używana do NSString. Jeśli jest to Zmienne, to zostanie skopiowane. Jeśli nie, to zostaje po prostu zachowane. Dokładnie semantyka, którą chcesz w aplikacji (pozwól typowi robić to, co najlepsze).
źródło
NSString
własności zadeklarowanej jakocopy
iretain
tak dostanie (jeśli oczywiście jest niezmienna). Innym przykładem, o którym mogę myśleć, jestNSNumber
.Tak - generalnie zawsze używaj atrybutu kopiowania.
Wynika to z faktu, że do Twojej właściwości NSString można przekazać instancję NSString lub instancję NSMutableString , a zatem nie możemy tak naprawdę ustalić, czy przekazywana wartość jest obiektem niezmiennym czy zmiennym.
Jeśli właściwość jest przekazywana do instancji NSString , odpowiedź brzmi „ Nie ” - kopiowanie nie jest mniej wydajne niż zachowanie.
(To nie jest mniej wydajne, ponieważ NSString jest wystarczająco inteligentny, aby w rzeczywistości nie wykonywać kopii.)
Jeśli właściwość zostanie przekazana do instancji NSMutableString, odpowiedź brzmi „ Tak ” - kopiowanie jest mniej wydajne niż zachowanie.
(Jest to mniej wydajne, ponieważ musi nastąpić faktyczny przydział pamięci i kopiowanie, ale jest to prawdopodobnie pożądana rzecz).
Mówiąc ogólnie, „skopiowana” właściwość może być mniej wydajna - jednak dzięki zastosowaniu
NSCopying
protokołu możliwe jest zaimplementowanie klasy, która jest „równie wydajna” do kopiowania, jak do zachowania. Instancje NSString są tego przykładem.Należy zawsze używać,
copy
gdy nie chcesz, aby stan wewnętrzny właściwości zmieniał się bez ostrzeżenia. Nawet w przypadku niezmiennych obiektów - poprawnie zapisane niezmienne obiekty będą skutecznie radziły sobie z kopiowaniem (zob. Następna sekcja dotycząca niezmienności iNSCopying
).retain
Obiekty mogą mieć przyczyny związane z wydajnością , ale wiąże się to z narzutem związanym z konserwacją - musisz zarządzać możliwością zmiany stanu wewnętrznego poza kodem. Jak mówią - optymalizuj ostatni.Nie - użyj
copy
. Jeśli twoja klasa jest naprawdę niezmienna, najlepiej jest zaimplementowaćNSCopying
protokół, aby twoja klasa powróciła sama, gdycopy
jest używana. Jeśli to zrobisz:copy
.copy
Adnotacja sprawia własny kod bardziej linkujących - wcopy
adnotacja wskazuje, że naprawdę nie trzeba się martwić o stan tego obiektu zmieniającym się gdzie indziej.źródło
Staram się przestrzegać tej prostej zasady:
Czy chcę zachować wartość obiektu w momencie, w którym przypisuję go do mojej właściwości? Użyj kopii .
Czy chcę trzymać obiekt i nie obchodzi mnie, jakie są jego wewnętrzne wartości w przyszłości? Użyj silnego (zachowaj).
Dla zilustrowania: Czy chcę zachować imię „Lisa Miller” ( kopia ), czy też chcę zachować osobę Lisa Miller ( silna )? Jej imię może później zmienić się na „Lisa Smith”, ale nadal będzie tą samą osobą.
źródło
W tym przykładzie można skopiować i zachować kopię w następujący sposób:
jeśli właściwość jest typu kopiuj, to
zostanie utworzona nowa kopia dla
[Person name]
ciągu, który będzie zawierał treśćsomeName
ciągu. Teraz każda operacja nasomeName
łańcuchu nie będzie miała wpływu na[Person name]
.[Person name]
asomeName
łańcuchy będą miały różne adresy pamięci.Ale w przypadku zatrzymania
oba
[Person name]
będą przechowywać ten sam adres pamięci co ciąg somename, tylko liczba zatrzymań ciągu somename zostanie zwiększona o 1.Tak więc każda zmiana w łańcuchu nazwy będzie odzwierciedlona w
[Person name]
łańcuchu.źródło
Z pewnością umieszczenie „kopiowania” w deklaracji właściwości jest bardzo trudne w obliczu używania środowiska obiektowego, w którym obiekty na stercie są przekazywane przez referencję - jedną z korzyści, jakie tu otrzymujesz, jest to, że przy zmianie obiektu wszystkie odwołania do tego obiektu zobacz najnowsze zmiany. Wiele języków podaje „ref” lub podobne słowa kluczowe, aby umożliwić typom wartości (tj. Strukturom na stosie) czerpanie korzyści z tego samego zachowania. Osobiście korzystałbym z kopii oszczędnie, a jeśli czułem, że wartość właściwości powinna być chroniona przed zmianami dokonanymi w obiekcie, do którego została przypisana, mógłbym wywołać metodę kopiowania tego obiektu podczas przypisania, np .:
Oczywiście, projektując obiekt zawierający tę właściwość, tylko Ty będziesz wiedział, czy projekt korzysta ze wzorca, w którym zadania są kopiowane - Cocoawithlove.com ma następujące zdanie:
„Powinieneś użyć akcesorium kopiującego, gdy parametr ustawiający może być zmienny, ale nie możesz zmienić stanu wewnętrznego właściwości bez ostrzeżenia ” - więc ocena, czy możesz znieść zmianę wartości, należy do ciebie. Wyobraź sobie ten scenariusz:
W takim przypadku, bez użycia kopii, nasz obiekt kontaktu automatycznie przyjmuje nową wartość; gdybyśmy go jednak użyli, musielibyśmy ręcznie upewnić się, że zmiany zostały wykryte i zsynchronizowane. W takim przypadku zachowanie semantyki może być pożądane; w innym egzemplarz może być bardziej odpowiedni.
źródło
źródło
Powinieneś używać kopii cały czas, aby zadeklarować właściwość NSString
Należy przeczytać je, aby uzyskać więcej informacji na temat tego, czy zwraca łańcuch niezmienny (w przypadku przekazania łańcucha zmiennego), czy zwraca zachowany ciąg (w przypadku przekazania łańcucha niezmiennego)
Odwołanie do protokołu NSCopying
Obiekty wartości
źródło
Ponieważ nazwa jest (niezmienna)
NSString
, kopiowanie lub zachowanie nie ma znaczenia, jeśli ustawisz innąNSString
na nazwę. Innymi słowy, kopia zachowuje się tak, jak zachowaj, zwiększając liczbę referencji o jeden. Myślę, że jest to automatyczna optymalizacja klas niezmiennych, ponieważ są one niezmienne i nie trzeba ich klonować. Ale gdyNSMutalbeString
mstr
zostanie ustawiona nazwa a, treśćmstr
zostanie skopiowana ze względu na poprawność.źródło
Jeśli ciąg jest bardzo duży, kopiowanie wpłynie na wydajność, a dwie kopie dużego ciągu zajmą więcej pamięci.
źródło