EXC_BAD_ACCESS на пользовательском UIView с пользовательским XIB

Я разрабатываю приложение iOS 5+ с последним SDK.

Я создал пользовательский UIView (TopMenuView) с пользовательским XIB. В Interface Builder я изменил этот класс XIB, UIView на TopMenuView. Я не установил File Owner.

В TopMenuView.m у меня есть:

- (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;
}

С помощью Interface Builder я добавил UIView в UIViewController и изменил этот класс UIView на TopMenuView.

Но, когда я запускаю приложение, я получаю это сообщение журнала 4251 раз: 2013-10-13 20:49:34.078 MyProject[470:c07] init with coder: 0

И затем я получаю EXC_BAD_ACCESS здесь:

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

Ответ 1

Вот как я это сделал:

//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];    

Здесь CustomNavigationView является подклассом UIView с классом владельца файлов как UIView и пользовательским классом UIView как CustomNavigationView.

Это работает для меня.

Ответ 2

Причина, по которой он вызывает initWithCoder столько раз, объясняется неправильной настройкой класса в вашем .xib файле.

Убедитесь, что пользовательский класс в файловом владельце - это ваш пользовательский класс UIView:

введите описание изображения здесь

И убедитесь, что класс в корневом представлении является UIView по умолчанию:

введите описание изображения здесь

И теперь это все, что вам нужно в вашем пользовательском классе (в 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
}

Ответ 3

Скорее всего, вы попадаете в бесконечный цикл, потому что вы рекурсивно вызываете initWithCoder. Один из способов - проверить, имеет ли ваш подкласс какие-либо подзаголовки в первую очередь.

-(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;
}

Ответ 4

Ваш - (id)initWithCoder:(NSCoder *)aDecoder вызывается всякий раз, когда TopMenuView создается путем загрузки xib.

Таким образом, вы рекурсивно называете свой initWithCoder:


Комментировать весь ваш метод - (id)initWithCoder:(NSCoder *)aDecoder

и где вы хотите использовать TopMenuView, вероятно, в каком-то контроллере используйте приведенный ниже код

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

Ответ 5

Я получал ту же ошибку, пока не изменил, как я загрузил xib файл из раскадровки. В основном это связано с созданием @IBOutlet из корневого представления файла xib для кода. Также убедитесь, что вы установили File Owner xib в свой собственный класс.

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
    }
}

Мой полный ответ для настройки этого проекта здесь.