2

例如,

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

有没有类似..的概念

x.blue??? = false

“???” 意思是“如果它对蓝色有反应,就叫蓝色”......

注意 - 我非常感谢我可以编写一个扩展名callIfResponds:to,或一个特定的扩展名,blueIfBlueable

我想知道这里是否有一些本地的 swiftyness,我不知道。这似乎是一个非常基本的概念。


脚注:

在随后的激烈讨论中,提到了使用协议。只是为了任何阅读的人的利益,这里是使用协议的一种方法:

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

4 回答 4

4

正如其他人所说,解决此问题的更好方法是有条件地进行类型转换,而不是使用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匹配。

于 2017-01-28T13:39:07.507 回答
2

不知何故,我认为你想要的是:

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

当您可以检查类型时,为什么还要检查一个类是否符合 setter?

检查选择器不应该在纯 Swift 中使用。您将主要需要它来与 Obj-C API 交互 - 动态方法、协议中的可选方法或非正式协议。

于 2017-01-28T13:12:55.413 回答
2

为什么不直接检查类型的一致性?就像是:

superview?.subviews.forEach {
    guard $0 !== self else { return }
    ($0 as? Blueable)?.blue = false
}
于 2017-01-28T13:21:26.080 回答
1

您可以添加此扩展程序

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 }
于 2017-01-28T13:29:08.323 回答