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