2012-03-17 17 views
7

Dodaję dwa widoki, które są przechowywane przez właściwości, do mojego widoku. Podczas dodawania subviews do mojego widoku, subViews są pozornie dealokowane po wywołaniu mojej metody setup. Rezultat końcowy jest taki, że widoki nigdy się nie wyświetlają. Teraz, jeśli zmienię moje właściwości na strong, w przeciwieństwie do weak, zachowuję odniesienie do widoków, które teraz są wyświetlane na ekranie. Więc co tu się dzieje? Dlaczego addSubview: i insertSubview: nie zachowują subviews? Zobacz poniższy kod:Dlaczego funkcja addSubview: nie zachowuje widoku?

btw, używam iOS5 z ARC (stąd silne i słabe rzeczy)

#import "NoteView.h" 
@interface NoteView() <UITextViewDelegate> 
@property (weak, nonatomic) HorizontalLineView *horizontalLineView; // custom subclass of UIView that all it does is draw horizontal lines 
@property (weak, nonatomic) UITextView *textView; 
@end 

@implementation NoteView 
@synthesize horizontalLineView = _horizontalLineView; 
@synthesize textView = _textView; 

#define LEFT_MARGIN 20 
- (void)setup 
{ 
    // Create the subviews and set the frames 
    self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame]; 
    CGRect textViewFrame = CGRectMake(LEFT_MARGIN, 0, self.frame.size.width, self.frame.size.height); 
    self.textView = [[UITextView alloc] initWithFrame:textViewFrame]; 


    // some addition setup stuff that I didn't include in this question... 

    // Finally, add the subviews to the view 
    [self addSubview:self.textView]; 
    [self insertSubview:self.horizontalLineView atIndex:0]; 
} 

- (void)awakeFromNib 
{ 
    [super awakeFromNib]; 

    [self setup]; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
     // Initialization code 
     [self setup]; 
    } 
    return self; 
} 
+0

Jak tworzysz instancja NoteView? Widzę kontroli jest osiągnięcie w ustawieniu .. –

+0

Tworzę wystąpienie NoteView, dodając go do kontrolera widoku w storyboard. –

+0

Czy twoja klasa jest określona w Xib jako NoteView –

Odpowiedz

21

Oto linia kodu:

self.horizontalLineView = [[HorizontalLineView alloc] initWithFrame:self.frame]; 

Przypomnijmy, że nieruchomość horizontalLineView jest słaby. Przeanalizujmy, co naprawdę dzieje się w tej linii, z dodatkowym kodem generowanym przez ARC. Po pierwsze, należy wysłać metod alloc i initWithFrame:, wracając silne odniesienie:

id temp = [[HorizontalLineView alloc] initWithFrame:self.frame]; 

W tym momencie obiekt HorizontalLineView ma liczbę zatrzymywania o 1. Następnie, ponieważ użyłeś dot-składni ustawić właściwość horizontalLineView , kompilator generuje kod do wysłania metody setHorizontalLineView: do self, przekazując jako parametr parametr temp. Ponieważ nieruchomość HorizontalLineView deklaruje weak metoda ustawiająca to robi:

objc_storeWeak(&self->_horizontalLineView, temp); 

że zestawy self->_horizontalLineView równa temp i umieszcza na liście &self->_horizontalLineView obiektu słabych referencji. Ale zwiększa wartość zatrzymania obiektu .

Wreszcie, ponieważ zmienna temp nie jest już potrzebna, kompilator generuje to:

[temp release]; 

który obniża HorizontalLineView obiektu zatrzymania licznika do zera, więc dealokuje obiekt. Podczas dealokacji przechodzi do listy słabych referencji i ustawia je na nil. Tak więc self->_horizontalLineView staje się nil.

Sposób, aby rozwiązać ten problem jest, aby temp zmienna jawne, tak, że można przedłużyć jej żywotność, aż po dodaniu obiektu HorizontalLineView jej SuperView, która utrzymuje go:

HorizontalLineView *hlv = [[HorizontalLineView alloc] initWithFrame:self.frame]; 
self.horizontalLineView = hlv; 
// ... 
[self insertSubview:hlv atIndex:0]; 
+2

Wow - masz absolutną rację! Dokładnie tego rodzaju wyjaśnienia miałem nadzieję na temat tego, co dzieje się za sceną. Czy nie wydaje się dziwne, że musisz przejść dodatkowy krok tworzenia wyraźnej zmiennej? W każdym razie, dzięki za pomoc! –

+0

Odkryłem, że wystarczy wprowadzić zmienną temp, nie trzeba jej używać w wywołaniu 'insertSubview'. Więc możesz użyć '[self insertSubview: self.horizontalLineView atIndex: 0];' i to nadal działa. Wydaje mi się to sprzeczne z intuicją. Czy możesz wyjaśnić to zachowanie? –

3

Słaby nie powinny być stosowane, chyba że w przypadkach, gdy rodzic-dziecko zachowują cyklu uformowany (rodzic zachowuje odniesienie do dziecka, dziecko zachowuje odniesienie do rodzica, więc nie jest dealloc'd). Mocny jest równoważny zachowaniu ARC (obecnie nieważny w ARC) i utrzymuje ładny stabilny wskaźnik na obiekcie przez znacznie dłuższy okres czasu niż słabe odniesienie, więc addSubview działa, zamiast dać jakiś błąd.

Dlaczego addSubview: i insertSubview: nie zachowują subviews?

Czy próbowałeś zadzwonić do retain na obiekcie zerowym? Tak, wciąż zero. Twoje słabe odniesienie nie utrzymuje obiektu UIView wystarczająco długo, aby pomyślnie "zadzwonić zachować" na obiekcie.

+0

Dlaczego miałaby się zawiesić? –

+0

Założę, że wysyłanie zostanie zatrzymane na zwolnioną instancję ... – CodaFi

+0

To znaczy, widzę, co mówisz o tym, jak widoki mogą nie być przechowywane wystarczająco długo, aby je zachować, ale metoda instalacji powinna zostać wywołana po widoku (rodzica) utworzony. Kiedy dodam moje subviews do hierarchii widoku, zostaną one zachowane, prawda? Sądzę więc, że nadal jestem zdezorientowany. czego mi brakuje? –

0

Spróbuj użyć zamiast tego:

@property (nonatomic, retain) 
+0

Retain jest nieprawidłowy pod łukiem i prosił o wyjaśnienie. – CodaFi

+0

@CodaFi, własność zatrzymania jest całkowicie ważna w ramach ARC. –

Powiązane problemy