2009-08-18 8 views
6

Dziś rano wpadłem w awarię w aplikacji na iPhone, nad którą pracuję i podczas naprawiania błędu, jestem ciekawy z powodu składniowej przyczyny problemu.Ustawianie właściwości klasy Objective-C bez korzystania z samodzielnego odwołania

Oto mój kod zredukowany do prostych elementów. Zapełniam elementy w TableView za pomocą NSArray dla przedmiotów. NSArray jest własnością:

@interface FooViewController : UITableViewController { 
    NSArray *stuff; 
} 

@property (nonatomic, retain) NSArray *stuff; 

I w moim pliku wdrażania:

@synthesize stuff; 

- (void)viewDidLoad {  
    NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    self.stuff = arr; 

    [arr release]; 
} 

Teraz, kiedy po raz pierwszy napisał metodę, przypadkowo wypaść poza "ja". i to spowodowało bombę. Chociaż podczas testowania działało na pierwszy rumieniec. Ja próbowałem:

stuff = arr; 
NSLog(@"%d", [stuff count]); 

Ale używając rzeczy w innych metodach zbombardowany. Po rozwiązaniu problemu mogę używać funkcji [liczba rzeczy] w innych miejscach.

Dlaczego więc mogę używać rzeczy w niektórych miejscach, ale w innych muszę użyć self.stuff?

Odpowiedz

4

Byłoby to również działało poprawnie:

- (void)viewDidLoad {  
    stuff = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
} 

Ponieważ tablica została zatrzymana przez Alloc.Ale to zwykle lepiej trzymać się zapisu dot jeśli mają właściwość i użyć metod tworzenia tablicy autorelease, gdzie można uzyskać zachowuje „za darmo” od nieruchomości:

- (void)viewDidLoad {  
    NSArray *arr = [NSArray arrayWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    self.stuff = arr; 

} 

Prawdopodobnie właśnie opuścił ją utrzymać rzeczy proste, ale trzeba także wyzwolić tę tablicę w dealloc:

- (void)dealloc {  
    [stuff release]; stuff = nil; 
} 
+1

Jeśli zamierzasz używać właściwości, powinieneś używać ich wszędzie, tzn. Zawartość dealloc powinna po prostu przeczytać: self.stuff = nil; Powszechnym sposobem uniknięcia błędów jest zadeklarowanie zmiennej instancji jako: NSArray * _stuff; Deklaracja właściwości pozostaje taka sama, ale instrukcja syntezy powinna wyglądać teraz tak: @synthesize stuff = _stuff; Teraz za każdym razem, gdy spróbujesz użyć rzeczy bez własnego użytku, kompilator zgłosi błąd. –

+1

Właściwie Apple zaleca dealloc, aby bezpośrednio udostępniać zmienne klasy, a nie korzystać z właściwości - dzieje się tak dlatego, że jeśli korzystasz z właściwości, możesz uruchamiać powiadomienia KVC lub prawdopodobnie uruchamiasz inne efekty uboczne z nadpisywania syntezowanych metod pobierania/ustawiania. –

+0

Dzięki za cynk. Zastanawiam się, jakie to ma znaczenie, zwłaszcza, że ​​może nie chcieć * uruchamiać KVO? Nie wspominając o tym, że we współczesnym środowisku wykonawczym * będziemy * używać akcesorów z syntezowanymi zmiennymi instancji. Wyobrażam sobie, że Apple upewnia się, że ich kod chroni przed takimi rzeczami. Do tej pory nie napotkaliśmy żadnych problemów z moim kodem, ale teraz będę ostrzeżony, że zostałem ostrzeżony :-) –

3

stuff = ... bezpośrednio odwołuje się do pola wsparcia nieruchomości. Nie zwiększa liczby zatrzymań. W rezultacie zwolnienie obiektu w innym miejscu może spowodować zatrzymanie odliczania do zera i zwolnienie go, gdy nadal będziesz go odwoływał. Ponadto może spowodować wyciek pamięci dla poprzedniej wartości właściwości.
Powodem, dla którego wygląda na to, że czasami działa, jest to, że obiekt prawdopodobnie jeszcze nie został zwolniony przez kogoś innego.

Z drugiej strony, self.stuff = ... wyśle ​​wiadomość do akompaniatora zestawu nieruchomości, który zajmie się licznikiem zatrzymania.

5

Gdy używasz składni (self) i kropki, biorąc pod uwagę sposób zdefiniowania właściwości (nonatomic, retain), NSArray (stuff) zostaje zachowany.

Jeśli nie, nadal wykonuje się przypisanie, ale nie zachowujesz tablicy poza niejawnym zachowaniem poprzez alloc + init - i natychmiast ją zwalniasz.

można obejść poprzez przypisanie „self.stuff = arr” wykonując:

stuff = [arr retain]; 

Ale skoro określona właściwość, to oczywiście chcą być przy użyciu składni kropki i posiadające zachowują wezwał do ciebie.

3

różnica między robi:

stuff=arr; 

i

self.stuff=arr; 

jest to, że w drugim przypadku wywołuje się automatycznie syntetyzowaną metodę setStuff: accessor, która zachowuje tablicę. W opublikowanym przez Ciebie kodzie tablica jest tworzona za pomocą metody alloc/initWithObjects, więc ma ona już wartość zatrzymania 1.

Trzeba tylko zmienić usunąć wywołanie [wydanie arr] w viewDidLoad: method i wszystko będzie dobrze:

- (void)viewDidLoad {  
    NSArray *arr = [[NSArray alloc] initWithObjects:@"", @"Item 1", @"Item 2", 
             @"Lorem", @"Ipsum", nil]; 
    stuff = arr; 
} 

Jak zauważyłeś, możesz również "naprawić" to za pomocą self.stuff. Odradzam robienie tego, ponieważ przesłania to znaczenie kodu i dodaje dodatkową pracę, która w większości przypadków nie jest potrzebna. Ogólnie zalecam, aby nie używać "self". składnia w metodach instancji.

+0

Tak więc, jeśli właściwość @ ma "przypisz" semantyczną, to używanie "ja" przed dostępem jest w porządku? – bobobobo

+0

Ogólnie, tak. Jak wspomniano w innych odpowiedziach, bezpośredni dostęp do nieruchomości nie zwolni obserwatorów KVO (co może, ale nie musi, być zależne). –

Powiązane problemy