В Swift3 объединение отвечает # на и звонит одним махом?

Например,

superview?.subviews.filter{
    $0 != self &&
    $0.responds(to: #selector(setter: Blueable.blue))
  }.map{
    ($0 as! Blueable).blue = false
  }

Есть ли такая концепция, как..

x.blue??? = false

'???' что означает "если он отвечает на синий, назовите синий"...

Примечание - я полностью ценю, что мог написать расширение, callIfResponds:toили конкретное расширение, blueIfBlueable,

Мне интересно, есть ли здесь какая-то местная стремительность, о которой я не знаю. Кажется, это довольно базовая концепция.


Сноска:

в последующем жарком обсуждении упоминается использование протокола. Просто для удобства любого читателя, вот один из подходов к использованию протокола:

protocol Blueable:class {
    var blue:Bool { get set }
}

extension Blueable where Self:UIView {
    func unblueAllSiblings() { // make this the only blued item
        superview?.subviews.filter{$0 != self}
            .flatMap{$0 as? Blueable}
            .forEach{$0.blue = false}
    }
}

// explanation: anything "blueable" must have a blue on/off concept.
// you get 'unblueAllSiblings' for free, which you can call from
// any blueable item to unblue all siblings (likely, if that one just became blue)

Чтобы использовать это, например...

@IBDesignable
class UILabelStarred: UILabel, Blueable {

    var blueStar: UIView? = nil
    let height:CGFloat = 40
    let shinyness:CGFloat = 0.72
    let shader:Shader = Shaders.Glossy
    let s:TimeInterval = 0.35

    @IBInspectable var blue:Bool = false {
        didSet {
            if (blue == true) { unblueAllSiblings() }
            blueize()
        }
    }

    func blueize() {

        if (blueStar == nil) {
            blueStar = UIView()
            self.addSubview(blueStar!)
            ... draw, say, a blue star here
            }
        if (blue) {
            UIView.animate(withDuration: s) {
                self. blueStar!.backgroundColor = corporateBlue03
                self.textColor = corporateBlue03
            }
        }
        else {
            UIView.animate(withDuration: s) {
                self. blueStar!.backgroundColor = UIColor.white
                self.textColor = sfBlack5
            }
        }
    }
}

Просто возвращаясь к первоначальному вопросу, все в порядке. Но вы не можете "подобрать" существующее свойство (простой пример isHidden) в существующих классах.

Более того, пока мы обсуждаем это, обратите внимание, что в этом примере расширения протокола вы, к сожалению, НЕ можете автоматически иметь протокол или расширение, как бы, вызывать unblueAllSiblings "изнутри" протокола или расширения именно по этой причине: почему ты не можешь сделать это

4 ответа

Решение

Каким-то образом я думаю, что вы хотите, это:

superview?.subviews.filter {
   $0 != self // filter out self
}.flatMap {
  $0 as? Blueable
}.forEach {
  $0.blue = false
}

Почему вы должны проверять, соответствует ли класс установщику, когда вы можете проверить тип?

Проверка селекторов не должна использоваться в чистом Swift. Он понадобится вам в основном для взаимодействия с API-интерфейсами Obj-C - динамическими методами, дополнительными методами в протоколах или неофициальными протоколами.

Как уже говорили другие, лучший способ добиться этого - условное приведение типов, а не использование responds(to:), Тем не менее, не забывайте, просто используя for in цикл - они довольно мощные, что позволяет использовать сопоставление с образцом и where пункты, позволяющие перебирать заданное подмножество элементов.

for case let blueable as Blueable in superview?.subviews ?? [] where blueable !== self {
    blueable.blue = false
}
  • case let blueable as Blueable использует шаблон приведения типов, чтобы соответствовать только элементам, которые Blueableи связать их с blueable если успешно

  • where blueable !== self исключает self от совпадения.

Почему бы не проверить соответствие типу напрямую? Что-то вроде:

superview?.subviews.forEach {
    guard $0 !== self else { return }
    ($0 as? Blueable)?.blue = false
}

Вы можете добавить это расширение

extension UIView {
    var siblings: [UIView] { return self.superview?.subviews.filter { $0 != self } ?? [] }
}

Теперь выберите решение, которое вы предпочитаете из следующих

Решение 1

siblings.flatMap { $0 as? Blueable }.forEach { $0.blue = false  }

Решение 2

siblings.forEach { ($0 as? Blueable)?.blue = false }
Другие вопросы по тегам