2013-10-14 34 views
9

Pracuję nad aplikacją iOS 5+ z najnowszym SDK.EXC_BAD_ACCESS na niestandardowym UIView z niestandardowym XIB

Utworzyłem niestandardowe UIView (TopMenuView) z niestandardowym XIB. W programie Interface Builder zmieniłem, na tej klasie XIB, UIView na TopMenuView. Nie ustawiłem żadnego File's Owner.

Na TopMenuView.m mam:

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super initWithCoder:aDecoder]; 

    if (self) 
    { 
     NSLog(@"init with coder: %d", counter); 
     counter++; 
     // Add custom XIB 
     NSArray *topMenuView = [[NSBundle mainBundle] loadNibNamed:@"TopMenuView" 
                  owner:nil 
                  options:nil]; 
     UIView *nv = [topMenuView objectAtIndex:0]; 

     [self addSubview:nv]; 
    } 

    return self; 
} 

za pomocą interfejsu Builder Dodałem UIView do UIViewController i zmienił tę UIView klasę TopMenuView.

Ale kiedy uruchomić aplikację, i ten komunikat zalogować 4251 razy: 2013-10-13 20:49:34.078 MyProject[470:c07] init with coder: 0

A potem dostaję EXC_BAD_ACCESS tutaj:

NSArray *topMenuView = [[NSBundle mainBundle] loadNibNamed:@"TopMenuView" 
                  owner:nil 
                  options:nil]; 
+0

dodajesz nv jako widok podrzędny, ale gdzie jest główny widok? nie deklarujesz żadnego widoku właścicielowi pliku. musisz dołączyć jeden widok do właściciela pliku. – KDeogharkar

Odpowiedz

3

ten jak to zrobiłem:

//Add Custom View to my main view of viewcontroller 
self.customNavView = [[CustomNavigationView alloc] init]; 
self.customNavView = [[[NSBundle mainBundle] loadNibNamed:@"CustomNavigationView" owner:self options:nil] objectAtIndex:0]; 
[self.customNavView setFrame:CGRectMake(0, 20, 320, 54)]; 
[self.view addSubview:self.customNavView];  

Tutaj CustomNavigationView jest podklasą UIView z klasami właściciela plików jako UIView i niestandardową klasą UIView jako CustomNavigationView.

To działa dla mnie.

+0

Działa świetnie! Możesz usunąć przesłonięcie initWithCoder – Jesse

1

Twój - (id)initWithCoder:(NSCoder *)aDecoder nazywa ilekroć TopMenuView jest tworzony ładując twój xib.

Zatem jesteś rekurencyjnie nazywając swoją initWithCoder:


Komentarz wszystkim metoda - (id)initWithCoder:(NSCoder *)aDecoder

i gdzie chcesz użyć TopMenuView prawdopodobnie w jakimś kontrolerem użyć poniższy kod

NSArray *topMenuView = [[NSBundle mainBundle] loadNibNamed:@"TopMenuView" owner:nil options:nil]; 
UIView *nv = [topMenuView objectAtIndex:0]; 
+0

Tak, wiem o tym. Jak mogę to naprawić? – VansFannel

9

Najprawdopodobniej dostaniesz się w nieskończoną pętlę, ponieważ rekurencyjnie wywołujesz initWithCoder. Jednym z obejść jest sprawdzenie, czy twoja podklasa ma pierwsze subviews.

-(id)initWithCoder:(NSCoder *)aDecoder { 
    self = [super initWithCoder:aDecoder]; 
    if (self) { 
     if (self.subviews.count == 0) { 
      NSArray *topMenuView = [[NSBundle mainBundle] loadNibNamed:@"TopMenuView" owner:nil options:nil]; 
      UIView *nv = [topMenuView objectAtIndex:0]; 
      [self addSubview:self.view]; 
     } 
    } 
    return self; 
} 
0

Otrzymałem ten sam błąd, dopóki nie zmieniłem sposobu wczytywania pliku xib z storyboardu. Zasadniczo chodziło o zrobienie pliku @IBOutlet z widoku głównego pliku xib do kodu. Upewnij się również, że ustawiłeś Właściciel pliku na Xib na twoją klasę niestandardową.

import UIKit 
class ResuableCustomView: UIView { 

    @IBOutlet var view: UIView! 
    @IBOutlet weak var label: UILabel! 

    @IBAction func buttonTap(sender: UIButton) { 
     label.text = "Hi" 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

     NSBundle.mainBundle().loadNibNamed("ReusableCustomView", owner: self, options: nil)[0] as! UIView 
     self.addSubview(view) 
     view.frame = self.bounds 
    } 
} 

Moja pełna odpowiedź na temat konfiguracji tego projektu to here.

30

Powód, dla którego wywołuje initWithCoder tyle razy, jest wynikiem nieprawidłowej konfiguracji klasy w pliku .xib.

Upewnij niestandardową klasę na właściciela pliku jest niestandardowe klasy UIView:

enter image description here

I upewnij się, że klasa na głównym widokiem jest domyślnym UIView:

enter image description here

A teraz to wszystko, czego potrzebujesz w swojej klasie niestandardowej (w Swift):

required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 

    let view = NSBundle.mainBundle().loadNibNamed("TopMenuView", owner: self, options: nil)[0] as! UIView 
    self.addSubview(view) 
    view.frame = self.bounds 
} 
+1

To naprawdę rozwiązuje problem. Czułem, że Xcode powinien dostarczyć lepsze ostrzeżenia dla tego rodzaju konfiguracji "niestandardowej klasy". – RandyTek

+1

@JYeh To jest jedna szczegółowa i precyzyjna odpowiedź. – Singh

+2

Należy również zauważyć, że jeśli twoja niestandardowa klasa pochodzi z innego projektu, na przykład zależność od Cocoapods, musisz również wypełnić pole modułu (tuż pod klasą niestandardową). – judepereira

Powiązane problemy