【问题标题】:Loading a XIB file to a UIView Swift将 XIB 文件加载到 UIView Swift
【发布时间】:2016-06-10 03:22:29
【问题描述】:

我正在尝试将我的 XIB 文件加载到 UIView 中,但我遇到了一些问题。我有所需的覆盖功能,但它们似乎正在崩溃。说这个错误,警告:

无法加载任何 Objective-C 类信息。这会 显着降低可用类型信息的质量。

我想知道是否有人可以告诉我如何将XIB 文件正确加载到UIView

import UIKit

class Widget: UIView {

    let view = UIView()

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

        //call function

        loadNib()

    }

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

        loadNib()

        //fatalError("init(coder:) has not been implemented")
    }

    func loadNib() {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: "nib", bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
        view.frame = bounds
        view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        self.addSubview(view);  
    }
}

【问题讨论】:

  • 你的 XIB 文件真的命名为“nil”吗?
  • 似乎工作正常...哪条线路崩溃了?
  • 这能回答你的问题吗? Load a UIView from nib in Swift

标签: ios swift xcode uiview xib


【解决方案1】:

//**只要使用这个类作为视图的超类**

import UIKit

class ViewWithXib: UIView {

func initUI() {}

private func xibSetup() {
    let view = loadViewFromNib()
    view.frame = bounds
    view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
    addSubview(view)
    initUI()
}

private func loadViewFromNib() -> UIView {
    let thisName = String(describing: type(of: self))
    let view = Bundle(for: self.classForCoder).loadNibNamed(thisName, owner: self, options: nil)?.first as! UIView
    return view
}


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

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

}

// 用法

class HeaderView: ViewWithXib {
}


let header = HeaderView() // No need to load the view from nib, It will work

【讨论】:

    【解决方案2】:

    Swift 5.x

    let loadMusicView = Bundle.main.loadNibNamed("MusicView", owner: nil, options: nil)![0] as? MusicView
    loadMusicView?.frame = controlsMainView.bounds
    loadMusicView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    controlsMainView.addSubview(loadMusicView!)
    
    //if you have variables in your .xib file access those variables like this
    loadMusicView.yourVariableName = .....
    

    【讨论】:

      【解决方案3】:

      我在我们的一个项目中使用它,可能对你有用

      import UIKit
      
      class RegisterPageView: UIView {
          
              class func instanceFromNib() -> RegisterPageView {
                  return UINib(nibName: "RegisterPageView", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as! RegisterPageView
              }
      }
       
      

      【讨论】:

      • 它不适用于 thisView.alpha = 0 , thisView.superview
      【解决方案4】:

      改进的DevAndArtist UIView 扩展

      public extension UIView
      {
          static func loadFromXib<T>(withOwner: Any? = nil, options: [UINib.OptionsKey : Any]? = nil) -> T where T: UIView
          {
              let bundle = Bundle(for: self)
              let nib = UINib(nibName: "\(self)", bundle: bundle)
      
              guard let view = nib.instantiate(withOwner: withOwner, options: options).first as? T else {
                  fatalError("Could not load view from nib file.")
              }
              return view
          }
      }
      

      用法

      let view = CustomView.loadFromXib()
      let view = CustomView.loadFromXib(withOwner: self)
      let view = CustomView.loadFromXib(withOwner: self, options: [UINibExternalObjects: objects])
      

      External Objects discussion

      【讨论】:

        【解决方案5】:

        我想分享这段需要我努力使其具有弹性的代码。

        import Foundation
        
        protocol Nib {
        
            func registerNib()
        
        }
        
        extension Nib where Self : UIView {
        
            func registerNib() {
                guard let nibName = type(of: self).description().components(separatedBy: ".").last else { return }
                // ** Check if resource is used in Interface Builder first to avoid crash during compile
                #if !TARGET_INTERFACE_BUILDER
                let bundle = Bundle(for: type(of: self))
                guard let _ = bundle.path(forResource: nibName, ofType: "nib")
                    else { fatalError("can't find \(nibName) xib resource in current bundle") }
                #endif
                guard let view = Bundle(for: type(of: self)).loadNibNamed(nibName, owner: self, options: nil)?.first as? UIView
                    else { return }
                // ** Another way to write it but do not work if xib is bundled with framework
                //guard let view = UINib(nibName: nibName, bundle: nil).instantiate(withOwner: self, options: nil).first as? UIView
                //    else { return }
                view.frame = bounds
                addSubview(view)
            }
        
        }
        

        您可以使用它来创建一个名为类名的 xib 资源文件(又名 CustomView.xib)

        import UIKit
        
        class CustomView: UIView, Nib {
        
            override init(frame: CGRect) {
                super.init(frame: frame)
                postInit()
            }
        
            required init?(coder aDecoder: NSCoder) {
                super.init(coder: aDecoder)
                postInit()
            }
        
            func postInit() {
                registerNib()
            }
        
        }
        

        不要忘记将xib资源文件的所有者类设置为CustomView,并将自定义类类字段留空。

        【讨论】:

          【解决方案6】:

          斯威夫特 4.x

          我终于做到了 这不在 customView 本身中。我把代码放在 ViewController 加载 customView 的地方。

          import UIKit
          
          class StartMenuViewController: UIViewController {
          
              @IBOutlet weak var customView: CustomView!
          
              override func viewDidLoad() {
                  super.viewDidLoad()
          
                  let myView = Bundle.main.loadNibNamed("CustomView", owner: self, options: nil)![0] as! UIView
                  customView .addSubview(myView)
              }
          

          【讨论】:

            【解决方案7】:

            这是我的方法(用 Swift 3.1 编写):

            protocol XibDesignable : class {}
            
            extension XibDesignable where Self : UIView {
            
                static func instantiateFromXib() -> Self {
            
                    let dynamicMetatype = Self.self
                    let bundle = Bundle(for: dynamicMetatype)
                    let nib = UINib(nibName: "\(dynamicMetatype)", bundle: bundle)
            
                    guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else {
            
                        fatalError("Could not load view from nib file.")
                    }
                    return view
                }
            }
            
            extension UIView : XibDesignable {}
            

            现在我可以像MyCustomView.instantiateFromXib() 那样从 Xib(假设有一个)创建任何 UIView 子类。请记住将您的 Xib 文件完全命名为您的 UIView 子类,并正确设置该 Xib 文件中主视图的类型。


            一旦SE-0068 实现,就可以删除协议并将函数直接移动到UIView 扩展中。


            请注意:原始帖子使用带有嵌套视图的常用模式。恕我直言,这是一种不好的模式,它不利用资源,只会创建不必要的视图层次结构。

            【讨论】:

            • 我喜欢这种方法。在我的例子中,.xib 文件只包含当前类的一个视图并且guard let view = nib.instantiate(withOwner: nil, options: nil).last 崩溃了,因为.last 返回了 nil。出于某种原因,guard let view = nib.instantiate(withOwner: nil, options: nil)[0] 虽然效果很好。只需将.last 更改为[0]
            • 我的示例中没有.last。此外,如果数组确实包含某些内容,.first 不能为零。如果数组为空,[0] 也会崩溃。
            • @DevAndArtist 我已经使用了您的代码,但遇到了内存泄漏问题。
            【解决方案8】:
              func configureNib() -> UIView {
                let bundle = Bundle(for: type(of: self))
                let nib = UINib(nibName: "CustomUIView", bundle: bundle)
                let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
                return view
            }
            

            并使用本教程使用 xib 进行自定义视图... https://developerfly.com/custom-view-use-xib-swift/

            【讨论】:

              【解决方案9】:

              Swift 4.x

              let myView = Bundle.main.loadNibNamed("yourXibView", owner: nil, options: nil)![0] as! UIView
              

              【讨论】:

                【解决方案10】:

                在我的项目中,我实现了以下(非常类似于彼得的解决方案)

                import UIKit
                
                // MARK: - Protocol Declaration
                
                public protocol InterfaceBuilderInstantiable
                {
                    /// The UINib that contains the view
                    ///
                    /// Defaults to the swift class name if not implemented
                    static var associatedNib : UINib { get }
                }
                
                // MARK: - Default Implementation
                
                extension InterfaceBuilderInstantiable
                {
                    /// Creates a new instance from the associated Xib
                    ///
                    /// - Returns: A new instance of this object loaded from xib
                    static func instantiateFromInterfaceBuilder() -> Self
                    {
                        return associatedNib.instantiate(withOwner:nil, options: nil)[0] as! Self
                    }
                
                    static var associatedNib : UINib
                    {
                        let name = String(describing: self)
                        return UINib(nibName: name, bundle: Bundle.main)
                    }
                }
                

                要使用,您只需实现协议:

                class MyView: UIView, InterfaceBuilderInstantiable
                {
                    // The rest
                

                如果您的 nib 与您的类 (MyView.xib) 同名,则您已设置:协议的默认实现会查找与主包中的类同名的 nib。

                当然,如果您的 nib 在另一个包中或具有不同的名称,您可以覆盖 associatedNib 并返回您自己的 nib。

                【讨论】:

                • 我用过你的方法,但是会导致App内存泄漏。
                【解决方案11】:

                对于 swift 3

                class YourClass:  UIView {
                    class func instanceFromNib() -> YourClass {
                        return UINib(nibName: "YourClassNibName", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! YourClass
                    }
                }
                

                【讨论】:

                • 你能再填一些空白吗?它去哪里了,它在哪里被调用?我一直在纠结这个问题的时间比我愿意承认的要长,而且我发现的所有东西要么是过时的 Swift 要么是 Objective-C。似乎这是一个简单的练习,但我太笨了,无法弄清楚。
                【解决方案12】:

                使用 Swift 3.0

                let viewFromNib: UIView? = Bundle.main.loadNibNamed("NibName", 
                    owner: nil, 
                    options: nil)?.first
                

                【讨论】:

                  【解决方案13】:
                  let xibView = NSBundle.mainBundle().loadNibNamed("NameXibView", owner: nil, options: nil)[0] as! UIView
                  

                  【讨论】:

                    【解决方案14】:

                    通常我使用以下方式加载自定义UIView拥有的xib文件:

                    NSBundle.mainBundle().loadNibNamed(nibName, owner: self, options: nil)[0];
                    

                    【讨论】:

                      猜你喜欢
                      • 2016-02-29
                      • 1970-01-01
                      • 2011-10-11
                      • 1970-01-01
                      • 2016-10-31
                      • 2011-12-10
                      • 2015-04-08
                      • 2018-10-07
                      • 1970-01-01
                      相关资源
                      最近更新 更多