在Swift3中,组合响应#和一次性呼叫?

时间:2017-01-28 13:06:13

标签: swift respondstoselector

例如,

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,正是如此原因:why you can't do it

4 个答案:

答案 0 :(得分:4)

正如其他人所说,更好的解决方法是通过有条件的类型转换而不是使用fun f (z, w) = (z (w 4)) + 3 fun foo z = z + 1; fun bar x = x * 2; val ans = f(foo, bar); val ans = ((4 * 2) + 1) + 3 。但是,不要忽略只使用responds(to:)循环 - 它们非常强大,允许您使用模式匹配和for in子句,允许您迭代给定的元素子集。

where
  • for case let blueable as Blueable in superview?.subviews ?? [] where blueable !== self { blueable.blue = false } 使用type-casting pattern仅匹配case let blueable as Blueable的元素,并在成功时将其绑定到Blueable

  • blueable排除了where blueable !== self的匹配。

答案 1 :(得分:2)

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

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

为什么要在检查类型时检查类是否符合setter?

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

答案 2 :(得分:2)

为什么不直接检查类型的一致性?类似的东西:

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

答案 3 :(得分: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 }