web-dev-qa-db-fra.com

Manière rapide de charger le fichier xib

J'ai un problème étrange avec le chargement du fichier xib dans le projet Swift. C'est tellement frustrant parce que je sais déjà comment le faire dans Obj-C. Mais comme Swift est Swift, vous ne pouvez pas le faire comme vous l'avez fait ..: /

J'ai donc créé IconTextFiled.xib et IconTextField.Swift. (étend UITextField) Dans xib, je remplis le champ Class dans l'inspecteur Idenity et dans le storyboard, je fais de même pour certains textFields. Nous sommes donc prêts à aller simplement ajouter le chargement de xib à la méthode init? Non.

En objc je le ferais comme ça

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

Alors j'ai pensé que si je traduisais en Swift, ce serait bien.

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

Mais ça ne marche pas. Je ne sais pas pourquoi mais il essaye de créer beaucoup plus d'objet et de crash

Enfin j'ai trouvé l'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
    }
}

Donc, dans ViewController, cela ressemble à

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

Et encore échouer. Pourriez-vous me dire comment vous chargez et utilisez les fichiers xib?

METTRE À JOUR

Ok après la réponse de Daniel

Mon code actuel

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

Ces deux var sont connectés à ces vues

La sortie de la console, était beaucoup plus grande et se terminait par 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;>

Ce ne devrait être que deux initWithCoder. Il semble que func loadNibNamed appelle initWithCoder

14
Błażej

Cela fonctionne pour moi:

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

Une fois que loadNibNamed:owner:options: est appelé, les boutons view et test sont connectés aux prises comme prévu. L'ajout de la hiérarchie de sous-vues du self de la nib rend le contenu de la nib visible.

8
Daniel T.

Je préfère charger depuis nib en implémentant la fonction loadFromNib() dans une extension de protocole comme suit:

(comme expliqué ici: 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

Vous pouvez utiliser ceci:

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