web-dev-qa-db-fra.com

Comment supprimer tous les reconnaisseurs de gestes d'une vue UIV dans Swift

J'ai écrit Swift code qui tente de supprimer tous les reconnaisseurs de gestes de toutes les sous-vues d'un type UIView personnalisé donné.

let mySubviews = self.subviews.filter() {
   $0.isKindOfClass(CustomSubview)
}
for subview in mySubviews {
   for recognizer in subview.gestureRecognizers {
      subview.removeGestureRecognizer(recognizer)
   }
}

Mais la ligne for recognizer Produit l'erreur du compilateur:

'[AnyObject]?' does not have a member named 'Generator'

J'ai essayé de changer la boucle for recognizer En for recognizer in enumerate(subview.gestureRecognizers), mais cela produit l'erreur du compilateur:

Type '[AnyObject]?!' Does not conform to protocol 'SequenceType'

Je vois que la méthode gestureRecognizers d'UIView renvoie [AnyObject]??, Et je pense que les valeurs de retour doublement enveloppées me font trébucher. Quelqu'un peut-il m'aider?

MISE À JOUR: Le code de compilation révisé est:

if let recognizers = subview.gestureRecognizers {
   for recognizer in recognizers! {
      subview.removeGestureRecognizer(recognizer as UIGestureRecognizer)
   }
}
48
Brian McCafferty

MISE À JOUR POUR iOS 11

En général, il est (et a toujours été) une mauvaise idée de supprimer all le geste est reconnu dans une vue en parcourant son tableau gestureRecognizers. Vous ne devez supprimer que les reconnaisseurs de mouvements que vous ajoutez à la vue, en gardant une trace de ces reconnaisseurs dans votre propre variable d'instance.

Cela prend une nouvelle importance dans iOS 11 pour les vues impliquées dans le glisser-déposer, car UIKit ajoute ses propres reconnaisseurs de gestes à ces vues pour reconnaître les glissements et les suppressions.

MISE À JOUR

Vous n'avez plus besoin de caster vers UIGestureRecognizer, car UIView.gestureRecognizers a été remplacé par le type [UIGestureRecognizer]? dans iOS 9.0.

De plus, en utilisant l'opérateur de coalescence nulle ??, vous pouvez éviter l'instruction if.

for recognizer in subview.gestureRecognizers ?? [] {
    subview.removeGestureRecognizer(recognizer)
}

Cependant, la façon la plus courte de le faire est la suivante:

subview.gestureRecognizers?.forEach(subview.removeGestureRecognizer)

Nous pouvons également filtrer les sous-vues dans une boucle for comme ceci:

for subview in subviews where subview is CustomSubview {
    for recognizer in subview.gestureRecognizers ?? [] {
        subview.removeGestureRecognizer(recognizer)
    }
}

Ou nous pouvons tout résumer en une seule expression (enveloppée pour plus de clarté):

subviews.lazy.filter { $0 is CustomSubview }
    .flatMap { $0.gestureRecognizers ?? [] }
    .forEach { $0.view?.removeGestureRecognizer($0) }

L'utilisation de .lazy devrait l'empêcher de créer des tableaux temporaires inutiles.

ORIGINAL

C'est une de ces choses ennuyeuses à propos de Swift. Votre boucle for ne fonctionnerait qu'en Objective-C, mais en Swift vous devez déballer explicitement le tableau optionnel:

if let recognizers = subview.gestureRecognizers {
    for recognizer in recognizers {
        subview.removeGestureRecognizer(recognizer as! UIGestureRecognizer)
    }
}

Vous pouvez forcer le déballage (for recognizer in subview.gestureRecognizers!), mais je ne sais pas si gestureRecognizers peut renvoyer nil et vous obtiendrez une erreur d'exécution si c'est le cas et vous le décompressez de force.

97
rob mayoff

Solution la plus simple

yourView.gestureRecognizers?.removeAll()
27
user3144836

Un moyen plus simple de le faire est

for subview in self.subviews as [UIView] {
    if subview.isKindOfClass(CustomSubview) {
        subview.gestureRecognizers?.removeAll(keepCapacity: false)
    }
}
10
Ah Ryun Moon