webentwicklung-frage-antwort-db.com.de

Schnell die richtige Art, um die Xib-Datei zu laden

Ich habe ein seltsames Problem beim Laden der Xib-Datei in einem Swift-Projekt. Es ist so frustrierend, weil ich bereits weiß, wie es in Obj-C geht. Aber da Swift Swift ist, kannst du es nicht so machen wie du ..: /

Ich habe also IconTextFiled.xib und IconTextField.Swift erstellt. (erweitert UITextField) In xib fülle ich das Feld Class im Idenity-Inspector und im Storyboard mache ich dasselbe für einige TextFields. Also ist es gut zu gehen, nur das Laden von xib zur init-Methode hinzuzufügen? Nein.

In objc würde ich es so machen

- (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;
}

Also dachte ich, wenn ich zu Swift übersetze, wird es gut sein.

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

Aber das geht nicht. Ich weiß nicht warum, aber es wird versucht, viel mehr Objekte und Abstürze zu erstellen

Endlich fand ich eine Erweiterung

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

In ViewController sieht es also so aus

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

Und wieder scheitern. Können Sie mir sagen, wie Sie Xib-Dateien laden und verwenden?

AKTUALISIEREN

Ok folgt nach Daniel Anwser

Mein aktueller 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

Diese beiden Var sind mit diesen Ansichten verbunden

Consoleo-Ausgabe war viel größer und endete mit 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;>

Es sollten nur zwei initWithCoder sein. Es scheint, dass func loadNibNamed initWithCoder aufruft.

14
Błażej

Das funktioniert für mich:

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")
    }
}

Sobald loadNibNamed:owner:options: aufgerufen wird, sind die view- und test-Tasten wie erwartet mit den Ausgängen verbunden. Durch Hinzufügen der Untersicht-Hierarchie des Ansichtselibs der Spitze wird der Inhalt der Spitze sichtbar.

8
Daniel T.

Ich bevorzuge das Laden von der Spitze, indem ich die Funktion loadFromNib() in einer Protokollerweiterung wie folgt implementiere:

(wie hier erklärt: 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{$0 == "."}.map(String.init).last!
    let nib = UINib(nibName: nibName, bundle: nil)
    return nib.instantiateWithOwner(self, options: nil).first as! Self
  }

}
6
Sam

Sie können dies verwenden:

if let customView = Bundle.main.loadNibNamed("MyCustomView", owner: self, options: nil)?.first as? MyCustomView {
        // Set your view here with instantiated customView
}
0
Zaldy