В 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 }