Загрузите xib-файл из Interfacebuilder и, как правило, из кода - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть хорошая реализация XibLoadedView, которая позволяет загружать подклассы UIView из xibfile в раскадровки.Однако я хочу иметь возможность повторно использовать эти xibfiles и загружать их из кода.Кажется, он не работает.

@IBDesignable
class XibLoadedView: UIView {
    var loadedView: UIView?

    required init(fileName: String) {
        super.init(frame: .zero)
        xibSetup(fileName: fileName)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        xibSetup()
    }

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

    func xibSetup(fileName: String? = nil) {
        guard let loadedView = viewLoadedFromNib(named: fileName ?? xibName) else {
            return
        }

        loadedView.frame = bounds
        loadedView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        setupView()
        addSubview(loadedView)
        self.loadedView = loadedView
        self.backgroundColor = .clear
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setupView()
    }

    internal func setupView() {
        // To be overridden
    }

    internal var xibName: String? {
        // To be overridden if xib filename is other than subclass name
        return nil
    }
}

с расширением UIView:

func viewLoadedFromNib<View: UIView>(named nibName: String? = nil) -> View? {
    let nibName = nibName ?? String(describing: type(of: self))
    let bundle = Bundle(for: type(of: self))
    let nib = UINib(nibName: nibName, bundle: bundle)
    let views = nib.instantiate(withOwner: self, options: nil)
    let view = views.first as? View
    return view
}

Теперь я хочу создать конкретный подкласс XibLoadedView из кода.В моем случае из UITableViewCell:

class ViewWrappedTableViewCell: UITableViewCell {

    var rootView: UIView!
    var cellModel: CellModel!

    func setup<View: XibLoadedView>(from cellModel: CellModel, type: View.Type) {
        self.cellModel = cellModel
        let view = View(fileName: cellModel.xibName)
        contentView.addSubview(view)
        view.addConstraints(matchingParent: contentView)
        if let tableViewWidth = tableView()?.frame.width {
            view.addWidthConstraint(width: tableViewWidth)
        }

        contentView.backgroundColor = .clear

        if let view = view as? CellModelSetupable {
            view.setup(from: cellModel)
        }
        self.rootView = view
        contentView.layoutIfNeeded()
    }

CellModel хранит тип создаваемого экземпляра (подкласс XibLoadedView):

class CellModel {
    // ...
    var viewType: XibLoadedView.Type

Кажется, проблема похожа на эту: https://stackoverflow.com/a/26284281/511299

Если я не добавлю требуемый init, ни один из inits в XibLoadedView не вызывается.Однако добавление required init(fileName: String) приводит к сбою на nib.instantiate(withOwner: self, options: nil) с ошибкой:

[<GoodMorning.XibLoadedView 0x7fe5fd1297d0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key bottomSeparatorView.'

, что является выходом в правильном xibfile.Но он считает себя i XibLoadedView, а не правильным общим подклассом XibLoadedView.

Есть мысли?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...