Je suis ici pour comprendre pourquoi la solution que j'avais implémentée ne fonctionnera pas. En gros, j'ai une classe appelée MyClass et dans cette classe j'aimerais avoir un dictionnaire statique créé à partir d'un fichier plist. Comme ceci:
class MyClass {
static func myDic() -> [String: String] {
return NSDictionary(contentsOfFile: Bundle(for: self).path(forResource: "PlayerRolesWithColors", ofType: "plist")!) as! [String: String]
}
}
Si je le fais, le compilateur se plaindra que:
Cannot convert value of type '(MyClass) -> () -> (MyClass)' to expected argument type 'AnyClass' (aka 'AnyObject.Type')
Mais si je change myDic code > var et créez une méthode statique retournant ce dic, tout va bien:
class MyClass {
static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(for: self).path(forResource: "filename", ofType: "plist")!) as! [String: String]
}
Deux questions ici:
'(MaClasse) -> () -> (MaClasse)' Merci.
3 Réponses :
Vous pouvez faire
class MyClass {
static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(identifier: "comThisBundle")!.path(forResource: "filename", ofType: "plist")!) as! [String: String]
}
Comme vous ne pouvez pas accéder à self dans une variable statique, ou utiliser l'identifiant du bundle
class MyClass {
static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(for:MyClass.self).path(forResource: "filename", ofType: "plist")!) as! [String: String]
}
Vous pouvez simplement utiliser le nom de la classe au lieu de self .
Vous ne devriez pas non plus utiliser NSDictionary puis effectuer un cast dans un Dictionary . Utilisez plutôt PropertyListDecoder .
class MyClass {
static let myDic = try! PropertyListDecoder().decode([String:String].self, from: try! Data(contentsOf: Bundle(for: MyClass.self).url(forResource: "filename", withExtension: "plist")))
}
Ce qui est malheureusement une très mauvaise solution (même si d'autres solutions sont actuellement impossibles). J'attends toujours github.com/apple / swift-evolution / blob / master / propositions /… à mettre en œuvre.
@Sulthan oui, pour les méthodes génériques, cette solution de contournement n'est pas appropriée et cette proposition serait formidable d'avoir implémenté
@ DávidPásztor Merci de m'avoir indiqué le PropertyListDecoder que je ne connaissais pas.
Examinons un exemple plus simple (fonctionnel) gardant votre problème principal le même:
class ClassName {
static func check() {
print("static function check")
print(type(of: self)) //ClassName.Type
//same as
print(type(of: ClassName.self)) //ClassName.Type
//test
print(type(of: self) == type(of: ClassName.self)) //true
}
func check() {
print("normal function check")
print(type(of: self)) //ClassName
//test
print(type(of: self) == type(of: ClassName.self)) //false
}
}
ClassName.check()
ClassName().check()
Tout d'abord, notons que Bundle (for: AnyClass) prend un type d'objet.
Variables au niveau supérieur, accédez à self en tant que ClassName qui est un type d'instance, qu'il soit déclaré comme let code> / var / paresseux / calculé, statique ou non.
Donc:
static func getBundle() -> Bundle {
return Bundle(for: self)
}
est identique à:
static var bundle = Bundle(for: ClassName.self)
Les deux ne sont pas valides et génèrent l'erreur suivante:
Impossible de convertir la valeur de type 'ClassName' en type d'argument attendu 'AnyClass' (alias 'AnyObject.Type')
Bien sûr, c'est parce que nous transmettons un type d'instance au lieu du type d'objet attendu.
static var bundle = Bundle(for: ClassName())
Comme pour une fonction statique, c'est un peu différent.
Le métatype sur lequel vous appelez la méthode statique est disponible dans la méthode en tant que
self(il est simplement passé en tant que paramètre implicite).
Dans mon exemple, nous avons:
static var bundle = Bundle(for: self)
Lorsque vous appelez ClassName.getBundle () , ClassName. Le type est transmis implicitement à la fonction.
Désormais dans la fonction statique, self est de type ClassName.Type qui est un type Object et peut être appliqué directement dans Bundle (for :) , ou des fonctions similaires qui acceptent un type Object comme paramètre.
Ainsi, les fonctions statiques accèdent à self en tant que ClassName.Type qui est identique à ClassName.self , simplement pas apparent car il est passé implicitement.
Vous pouvez confirmer ce comportement de self dans une fonction static , et en outre, observez même comment self se comporte dans une fonction normale dans l'exemple suivant:
class ClassName {
static var bundle = Bundle(for: ClassName.self)
static func getBundle() -> Bundle {
return Bundle(for: self)
}
}
Nous montre également que les fonctions normales accèdent à self comme ClassName qui est un type d'instance, similaire aux variables.
Bundle (for :) prend un type d'objet self en tant que ClassName qui est un type d'instance self en tant que ClassName qui est un type d'instance self en tant que ClassName.Type qui est un type Object, car il est passé implicitement à la fonction
Notez qu'il y a une grande différence entre les fonctions static et les fonctions class .
@Sulthan Bien sûr, il doit y en avoir (et nous n'avons pas parlé de fonctions class ) mais ... dans le contexte de sa question, cela n'aurait toujours pas d'importance si c'était un statique func ou class func comme type (of: self) dans les deux cas serait toujours ClassName.Type .
Pas dans une sous-classe mais vous avez raison, c'est probablement hors de portée de cette question.
Bonnes questions, qui valent la peine d'être répondues :)