ios Swift加载xib文件的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26539849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:18:46  来源:igfitidea点击:

Swift proper way to load xib file

iosswiftinterface-builderxib

提问by B?a?ej

I have some strange problem with loading xib file in swift project. It's so frustrating because I already know how to do it in Obj-C. But since swift is swift so you can't do it like you did.. :/

我在 swift 项目中加载 xib 文件时遇到了一些奇怪的问题。这太令人沮丧了,因为我已经知道如何在 Obj-C 中做到这一点。但是由于 swift 很快,所以你不能像以前那样做..:/

So I have create IconTextFiled.xib and IconTextField.swift. (extends UITextField) In xib I fill field Class in Idenity inspector and in storyboard I do the same for some textFields. So we good to go just add loading from xib to init method? No.

所以我创建了 IconTextFiled.xib 和 IconTextField.swift。(扩展 UITextField)在 xib 中,我在 Idenity 检查器和故事板中填充字段类,我对某些文本字段执行相同的操作。所以我们很高兴将加载从 xib 添加到 init 方法?不。

In objc I would do it like this

在 objc 我会这样做

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"IconTextField" owner:self options:nil];
        self = [nib objectAtIndex:0];
    }
    return self;
}

So I thought if I translate to swift it will be good.

所以我想如果我翻译成 swift 会很好。

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    let nib:NSArray = NSBundle.mainBundle().loadNibNamed("IconTextField", owner: self, options: nil)
    self = nib.objectAtIndex(0)
}

But that doeasn't work. I don't know why but it try to create much more object and crash

但这行不通。我不知道为什么,但它试图创建更多的对象并崩溃

Finally I found extension

最后我找到了扩展

extension IconTextField {
    class func loadFromNibNamed(nibNamed: String, bundle : NSBundle? = nil) -> IconTextField? {
        return UINib(
            nibName: nibNamed,
            bundle: bundle
            ).instantiateWithOwner(nil, options: nil)[0] as? IconTextField
    }
}

So in ViewController it looks like

所以在 ViewController 中它看起来像

@IBOutlet var password: IconTextField!
override func viewDidLoad() {
    super.viewDidLoad()
    password = IconTextField.loadFromNibNamed("IconTextField")
}

And again fail. Could you tell me how you load and use xib files?

又失败了。你能告诉我你是如何加载和使用 xib 文件的吗?

UPDATE

更新

Ok following after Daniel anwser

好的,在 Daniel anwser 之后

My current code

我当前的代码

class IconTextField: UITextField {
    @IBOutlet var icon: UIImageView!
    @IBOutlet weak var view: UIView!

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        NSLog("initWithCoder \(self)")
        NSBundle.mainBundle().loadNibNamed("IconTextField", owner: self, options: nil)
        self.addSubview(view)
    }   
}

enter image description here

在此处输入图片说明

Those two var are connected to those views

这两个 var 连接到这些视图

Consoleo output, was a lot bigger and end with EXC_BAD_ACCESS

Consoleo 输出,要大得多,并以 EXC_BAD_ACCESS

2014-10-24 10:09:09.984 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7be7bfb0;>
2014-10-24 10:09:09.984 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7be7ddf0;>
2014-10-24 10:09:09.985 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7be7fa20;>
2014-10-24 10:09:09.985 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7be814f0;>
2014-10-24 10:09:09.986 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7be830c0;>
2014-10-24 10:09:10.083 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7d183270;>
2014-10-24 10:09:10.084 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7d187cd0;>
2014-10-24 10:09:10.084 testproject[20337:3757479] initWithCoder <stensgroup.IconTextField: 0x7d189960;>

It should be only two initWithCoder. It seams that func loadNibNamed is calling initWithCoder

应该只有两个initWithCoder。它接缝 func loadNibNamed 正在调用initWithCoder

采纳答案by Daniel T.

This works for me:

这对我有用:

class IconTextField: UITextField {
    @IBOutlet weak var view: UIView!
    @IBOutlet weak var test: UIButton!

    required init(coder: NSCoder) {
        super.init(coder: coder)
        NSBundle.mainBundle().loadNibNamed("IconTextField", owner: self, options: nil)
        self.addSubview(view)
        assert(test != nil, "the button is conected just like it's supposed to be")
    }
}

Once loadNibNamed:owner:options:is called the viewand testbutton are connected to the outlets as expected. Adding the nib's view self's subview hierarchy makes the nib's contents visible.

一旦loadNibNamed:owner:options:被调用viewtest按钮就会按预期连接到插座。添加笔尖的视图自身的子视图层次结构使笔尖的内容可见。

回答by Sam

I prefer to load from nib, by implementing loadFromNib()function in a protocol extension as follows:

我更喜欢从nib加载,通过loadFromNib()在协议扩展中实现如下功能:

(as explained here: https://stackoverflow.com/a/33424509/845027)

(如此处所述:https: //stackoverflow.com/a/33424509/845027

import UIKit

protocol UIViewLoading {}
extension UIView : UIViewLoading {}

extension UIViewLoading where Self : UIView {

  // note that this method returns an instance of type `Self`, rather than UIView
  static func loadFromNib() -> Self {
    let nibName = "\(self)".characters.split{
if let customView = Bundle.main.loadNibNamed("MyCustomView", owner: self, options: nil)?.first as? MyCustomView {
        // Set your view here with instantiated customView
}
== "."}.map(String.init).last! let nib = UINib(nibName: nibName, bundle: nil) return nib.instantiateWithOwner(self, options: nil).first as! Self } }

回答by Zaldy

You can use this:

你可以使用这个:

##代码##