简体   繁体   中英

Determine if `UIView` is loaded from XIB or instantiated from code

I use the following code to force a subclass of UIView to load from a XIB file whose name is the actual class name:

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

The purpose of the isRawView() method is to determine whether this view has been created from code, or it's been loaded from the corresponding XIB file. The implementation I've used so far is:

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
}

which uses a trick to determine if the view is created from code, because in such cases it contains exactly 2 subviews, both implementing the UILayoutSupport protocol.

This works nicely when a NibView subclass is instantiated from code. However it doesn't work if the view is created as part of a view controller in a storyboard (and presumably the same happens for view controllers and views loaded from XIB files).

Long story to explain the reason of my question: is there a way for a UIView to know whether it's been loaded from a XIB file, and possibly the name of that file? Or, otherwise, an alternative way of implementing the isRawView() method, which should:

  • return false if the view has been deserialized from an associated XIB file (whose name is the class name)
  • return true otherwise

Make use of the provided init functions.

Example code:

override init(frame: CGRect) {
    super.init(frame: frame)
    print("From code")
}

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

I can print out the class name like this:

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

You should be able to use that, maybe with some slight adjustments, to get what you need.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM