Подтвердить что ты не робот

Как удалить все распознаватели жестов из UIView в Swift

Я написал код Swift, который пытается удалить все распознаватели жестов из всех подзонов данного пользовательского типа UIView.

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

Но строка for recognizer создает ошибку компилятора:

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

Я попытался изменить цикл for recognizer на for recognizer in enumerate(subview.gestureRecognizers), но это вызывает ошибку компилятора:

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

Я вижу, что метод UIView gestureRecognizers возвращает [AnyObject]??, и я думаю, что возвращаемые значения с двойным завершением меня отключают. Кто-нибудь может мне помочь?

UPDATE: Пересмотренный код компиляции:

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

Ответ 1

ОБНОВЛЕНИЕ ДЛЯ iOS 11

В общем, это (и всегда было) плохой идеей для удаления жестов all распознается из представления путем циклизации его массива gestureRecognizers. Вам нужно только удалить распознаватели жестов, чтобы вы добавляли в представление, отслеживая эти распознаватели в своей собственной переменной экземпляра.

Это приобретает новое значение в iOS 11 для представлений, связанных с перетаскиванием, потому что UIKit добавляет свои собственные распознаватели жестов к этим представлениям, чтобы распознавать перетаскивания и капли.

UPDATE

Вам больше не нужно указывать на UIGestureRecognizer, потому что UIView.gestureRecognizers был изменен на тип [UIGestureRecognizer]? в iOS 9.0.

Кроме того, используя оператор nil-coalescing ??, вы можете избежать оператора if.

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

Однако самый короткий способ сделать это:

subview.gestureRecognizers?.forEach(subview.removeGestureRecognizer)

Мы также можем выполнить фильтрацию подзонов в цикле for следующим образом:

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

Или мы можем обернуть все это в одно выражение (завернутое для ясности):

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

Использование .lazy должно препятствовать созданию ненужных временных массивов.

ORIGINAL

Это одна из тех раздражающих вещей, которые произошли в Swift. Ваш цикл for будет работать только в Objective-C, но в Swift вам необходимо явно развернуть дополнительный массив:

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

Вы можете принудительно развернуть его (for recognizer in subview.gestureRecognizers!), но я не уверен, сможет ли gestureRecognizers вернуть nil, и вы получите ошибку времени выполнения, если это произойдет, и вы принудительно развернете его.

Ответ 2

Более простой способ сделать это:

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

Ответ 3

Простейшее решение

yourView.gestureRecognizers?.removeAll()