【问题标题】:Determine if `UIView` is loaded from XIB or instantiated from code确定 `UIView` 是从 XIB 加载还是从代码实例化
【发布时间】:2017-04-03 13:48:13
【问题描述】:

我使用以下代码强制UIView 的子类从名称为实际类名的 XIB 文件中加载:

class NibView : UIView {
    override func awakeAfter(using aDecoder: NSCoder) -> Any? {
        guard isRawView() else { return self }
        for view in self.subviews {
            view.removeFromSuperview()
        }

        let view = instanceFromNib()
        return view
    }

    func isRawView() -> Bool {
        // What here?
    }
}

isRawView() 方法的目的是确定这个视图是从代码创建的,还是从相应的 XIB 文件加载的。 到目前为止我使用的实现是:

func isRawView() -> Bool {
    // A subview created by code (as opposed to  being deserialized from a nib)
    // has 2 subviews, both implementing the `UILayerSupport` protocol
    return
        self.subviews.count == 2 &&
        self.subviews.flatMap(
            { $0.conforms(to: UILayoutSupport.self) ? $0 : nil }).count == 2
}

它使用一种技巧来确定视图是否是从代码创建的,因为在这种情况下它正好包含 2 个子视图,都实现了UILayoutSupport 协议。

NibView 子类从代码中实例化时,这很有效。但是如果视图是作为情节提要中视图控制器的一部分创建的,则它不起作用(并且可能同样适用于视图控制器和从 XIB 文件加载的视图)。

长篇大论来解释我的问题的原因:有没有办法让UIView 知道它是否是从 XIB 文件加载的,并且可能是该文件的名称? 或者,否则,实现isRawView() 方法的另一种方法应该是:

  • 如果视图已从关联的 XIB 文件(其名称是类名)反序列化,则返回 false
  • 否则返回true

【问题讨论】:

    标签: ios swift uiview


    【解决方案1】:

    利用提供的init 函数。

    示例代码:

    override init(frame: CGRect) {
        super.init(frame: frame)
        print("From code")
    }
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        print("From nib")
    }
    

    我可以这样打印出类名:

    print(NSStringFromClass(type(of: self)).components(separatedBy: ".").last ?? "Couldn't get it")
    

    你应该能够使用它,也许稍作调整,就可以得到你需要的东西。

    【讨论】:

    • 这可以帮助我区分代码和xib,但我认为它并不能告诉我使用了哪个xib。
    • @Antonio;我用一些可以打印类名的代码更新了我的答案。
    • 这是 xib 文件名,而不是我要查找的类名。 super.init(coder: aDecoder) 内部调用awakeAfter(using:),在该方法中我需要确定当前视图是否已从名称为类名的 xib 文件中加载。
    • 您的 xib 没有“链接”到它的自定义类吗?因为你可以有一个属性,即你在代码中设置的nibName,然后你可以检查view.nibName?
    • 我可以,但我仍然需要确定何时可以设置它。如果awakeAfter(using:) 没有返回self,则意味着它创建并返回了一个新视图。为了设置该属性,我需要在新实例上调用 awakeAfter(using:) 之前执行此操作,但这会由 init?(coder:) 初始化程序自动调用,而这恰好为时已晚。
    猜你喜欢
    • 1970-01-01
    • 2015-04-08
    • 2018-02-15
    • 2017-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-03
    • 1970-01-01
    相关资源
    最近更新 更多