从Interfacebuilder加载xib文件,通常从代码加载

时间:2018-11-27 15:43:52

标签: ios swift generics

我有一个很好的XibLoadedView实现,可以将xibfile中的UIView子类加载到Storyboard中。但是我希望能够重用这些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,则XibLoadedView中的所有init均不会被调用。但是,添加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中的出口。但是它认为自己是XibLoadedView,而不是XibLoadedView的正确泛型子类。

有什么想法吗?

0 个答案:

没有答案