Создание экземпляра вида из nib выдает ошибку

Я попытался создать подкласс @IBDesignable UIView следующим образом (ссылка). Первый пользовательский вид проходит нормально. Но когда я пытаюсь сделать еще один, у меня возникают ошибки. Сначала я получил failed to update auto layout status: the agent crashed и Failed to render instance of .... Каким-то образом я начал собирать и запускать проект с этими ошибками, но потом я получаю новую ошибку - EXC_BAD_ACCESS ... в строке let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView. Вот весь метод:

func loadViewFromNib() -> UIView {
        
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: "advancedCellView", bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
        
        return view
    }

С первым пользовательским UIView проблем нет. Я использую тот же код..

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

Любые идеи? Спасибо


person Lachtan    schedule 07.01.2016    source источник
comment
Вы написали, что первый пользовательский просмотр проходит нормально. Означает ли это, что вы действительно можете загрузить представление один раз, но затем, если вы попытаетесь загрузить его снова, вы получите сообщение об ошибке?   -  person Aaron Rasmussen    schedule 07.01.2016
comment
Кроме того, в чем причина использования NSBundle:forClass: вместо простого доступа к NSBundle.mainBundle()? Этот nib хранится в другом пакете?   -  person Aaron Rasmussen    schedule 07.01.2016
comment
Это говорит о том, что проблема не в коде, который загружает и создает экземпляр nib, а в самом файле xib. Вы изменили class для своего подкласса представления в построителе интерфейса на xib?   -  person Aaron Rasmussen    schedule 07.01.2016
comment
Под этим я имел в виду, что сначала я создал простой пользовательский подкласс UIView, и он отлично работает. Я могу использовать его без каких-либо ошибок. Затем я создал новый файл xib, в котором я разработал другой компонент, а также создал его подкласс UIView (оба на скриншоте). Я следовал той же процедуре, и это дает мне ошибки, которые я описал в вопросе. Я подумаю над другими вашими предложениями и постараюсь исправить это. Спасибо   -  person Lachtan    schedule 07.01.2016
comment
Было бы легче ответить на этот вопрос, если бы вы предоставили некоторые детали, касающиеся настройки пера, особенно в инспекторах удостоверений и атрибутов для представления верхнего уровня и владельца файла. Кроме того, полная ошибка, которую вы получаете с Failed to render instance of..., может помочь сузить ее.   -  person Josh Heald    schedule 29.02.2016


Ответы (4)


Опубликованный вами метод loadViewFromNib() выглядит нормально, вы правильно получаете пакет и указываете имя пера как строковый литерал, поэтому он должен найти кончик. Как заметил кто-то другой, возможно, что-то не так с вашей настройкой пера. Вот несколько вещей, которые нужно проверить:

  1. Вы должны установить AdvancedCellView в качестве пользовательского класса владельца файла в Identity Inspector.
  2. Убедитесь, что модуль также правильный - обычно вы просто хотите, чтобы он был пустым.
  3. Пользовательский класс для представления не должен быть установлен, просто оставьте его по умолчанию (UIView). Если у вас есть более описательное имя, чем «Вид» на боковой панели, вероятно, оно неправильное.
  4. Убедитесь, что у вас есть только один объект верхнего уровня в пера. Боковая панель должна выглядеть так, без каких-либо других записей, когда у вас свернуто дерево просмотра.

Иерархия пера только с одним представлением верхнего уровня

Н.Б. Этот ответ связан с учебным пособием, с которым связана OP, а не с единственным правильным способом настройки пера.

person Josh Heald    schedule 29.02.2016
comment
Учитывая, что код OP вручную загружает nib и напрямую устанавливает свойство view, неясно, будет ли необходима установка класса владельца файла в nib-файле. В любом случае это не повлияет на поведение во время выполнения, а только на возможность устанавливать соединения в Interface Builder. Однако неправильно говорить, что класс представления не должен быть установлен в nib (если действительно OP хочет, чтобы он был подклассом UIView); это повлияет на поведение во время выполнения, потому что эта информация используется средством разархивирования для определения экземпляра класса. - person jlehr; 29.02.2016
comment
@jlehr правда, не всегда класс не следует устанавливать в наконечнике, но ОП следовал руководству, в котором он загружал представление из наконечника в методах init(frame:) и init(coder:). В этом случае установка пользовательского класса для представления приведет к бесконечному циклу при загрузке пера, если у вас нет другого кода для предотвращения этого. - person Josh Heald; 01.03.2016
comment
Хорошо, я ломаю голову - при каких обстоятельствах подклассу UIView потребуется загружать другой экземпляр своего собственного типа из пера (не говоря уже о том, что загрузка пера обычно является обязанностью контроллера представления, а не представления)? Может быть, я что-то упускаю, но этот урок звучит немного подозрительно. - person jlehr; 01.03.2016
comment
Я тоже сейчас немного в замешательстве. Подход учебника состоит в том, чтобы позволить nib/раскадровке ViewController загрузить nib, установив пользовательский класс в заполнителе UIView в IB. Это означает, что init вызывается в пользовательском классе, где он распаковывает UIView из пользовательского пера и добавляет его в иерархию представлений. Лично я считаю, что это лучший подход, поскольку представление самодостаточно, поэтому оно может загружать себя как во время разработки, так и во время выполнения. - person Josh Heald; 01.03.2016
comment
Представление также может использовать awakeAfterUsingCoder() для возврата замены самому себе, что, как я видел, используется для загрузки представления из пера с пользовательским набором классов. Я никогда не видел, чтобы этот подход работал с IBDesignable, и с ним есть куча других проблем. - person Josh Heald; 01.03.2016

Я просматривал учебник и обнаружил, что если вы создадите подкласс элемента View в своем пользовательском xib, вы получите ошибку. Убедитесь, что вы установили только «Владелец файла» для своего пользовательского класса.

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

person B-Rad    schedule 18.05.2017

Метод instantiateWithOwner(options:) возвращает массив, а не представление, поэтому принудительное приведение к UIView никогда не сработает. Вместо этого попробуйте привести к реальному типу [AnyObject].

Элементы в массиве соответствуют объектам верхнего уровня в файле пера, поэтому интересующее вас представление должно быть одним из элементов массива. Учитывая имя вашего файла пера, по всей вероятности, в массиве будет только один объект верхнего уровня — ячейка, которую вы пытаетесь загрузить. Убедитесь, что в файле пера есть только один объект верхнего уровня и что он действительно является экземпляром подкласса UIView.

Обратите внимание, что ваша реализация потенциально неэффективна. Если вы загружаете более одной ячейки, вам следует кэшировать экземпляр UINib вместо того, чтобы каждый раз создавать новый. Обратите внимание, что классы фреймворка, такие как UITableViewController, имеют встроенные методы для регистрации пера, которые автоматически заботятся об этих деталях, поэтому вам может не понадобиться делать это самостоятельно.

person jlehr    schedule 10.01.2016
comment
Метод instanceiateWithOwner(options:) возвращает массив объектов верхнего уровня, распакованных из пера, как вы говорите. Однако, если эти объекты не имеют настраиваемого набора классов, они будут UIViews, и понижение будет работать нормально. Я действительно не думаю, что это должно быть принудительным опусканием, но это другой вопрос. - person Josh Heald; 29.02.2016
comment
Хех, ты прав -- похоже, я пропустил [0]. Я обновлю свой ответ. - person jlehr; 29.02.2016

Попробуйте сделать это вместо этого. Всегда работает для меня:

let picker = NSBundle.mainBundle().loadNibNamed("advancedCellView", owner: nil, options: nil)
let view = picker[0] as! UIView

return view

дай мне знать, если это работает

person brl214    schedule 07.01.2016
comment
Спасибо за ответ. Он не работает ни в первом пользовательском UIView. Выбрасывает Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x7f9a83413f30> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key captionLabel.' - person Lachtan; 07.01.2016
comment
Это другой вопрос. Вы должны подключить метку в раскадровке к своему пользовательскому классу просмотра. - person brl214; 07.01.2016