Salut là =) Je viens d'être confronté à un problème de conception où je dois (essentiellement) faire ce qui suit:
Je veux injecter un peu de code sur viewWillAppear:
De toute sous-classe UIViewController
conforme à un protocole MyProtocol
. Expliqué dans le code:
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController where Self: MyProtocol //<-----compilation error
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}
Le problème principal ici est que j'ai besoin de 2 choses dans l'extension UIVIewController
:
MyProtocol
et UIViewController
UIViewController
méthode initialize()
afin de pouvoir balancer viewWillAppear:
Ces 2 capacités semblent incompatibles (au Swift 3) car:
extension UIViewController where Self: MyProtocol
)extension MyProtocol where Self: UIViewController
mais nous NE POUVONS PAS remplacer les méthodes d'une classe dans une extension de protocole, ce qui signifie que nous pouvons ' t public override class func initialize()
qui est nécessaire pour le swizzling.Je me demandais donc s'il y avait quelqu'un qui pourrait offrir une solution Swifty à ce problème auquel je fais face? =)
Merci d'avance!!
Eh bien, jusqu'à présent, je n'ai trouvé aucun moyen vraiment satisfaisant de le faire, mais j'ai décidé de publier ce que j'ai fini par faire pour ce problème particulier. En un mot, la solution se présente comme suit (en utilisant l'exemple de code d'origine):
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension UIViewController //------->simple extension on UIViewController directly
{
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//------->only run when self conforms to MyProtocol
if let protocolConformingSelf = self as? MyProtocol {
//invoke APIs from
protocolConformingSelf.protocolFunction() // MyProtocol APIs
let viewLoaded = protocolConformingSelf.isViewLoaded // UIViewController APIs
}
}
}
Désavantages:
UIViewControllers
, même si nous validons uniquement ceux qui sont conformes au protocole MyProtocol
pour exécuter les lignes de code sensibles.J'espère vraiment que cela aidera quelqu'un d'autre face à une situation similaire =)
Vous étiez près de la solution. Juste besoin de faire autrement. Étendre le protocole uniquement si sa partie de UIViewController.
protocol MyProtocol
{
func protocolFunction() {
//do cool stuff...
}
}
extension MyProtocol where Self: UIViewController {
public override class func initialize()
{
//swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)
}
// MARK: - Swizzling
func xxx_viewWillAppear(animated: Bool)
{
self.xxx_viewWillAppear(animated)
//invoke APIs from
self.protocolFunction() // MyProtocol APIs
let viewLoaded = self.isViewLoaded // UIViewController APIs
}
}