消除Swift中重复的“用户定义的运行时属性”代码

时间:2017-02-26 19:22:11

标签: ios swift

我有很多类都有borderColor属性。我可以在故事板中的用户定义属性中设置此属性,然后使用单个UIView扩展名来实际添加边框及其颜色。效果很好。

但是我必须在每个子类中声明'borderColor'属性。协议扩展和UIView扩展都不允许我只声明一次这种计算属性,所以我可以在所有子类中使用它。

我有许多其他类和许多其他属性,如borderWidthshadowColor等,因此它最终会成为大量重复的代码。

每个子类都需要继承特定的超类,即UIImageView,而不仅仅是UIView,因为下面的例子中还没有详细说明其他方法。所以我不能只将它们添加到某个UIView子类中,然后让所有这些类继承它。

关于如何减少项目中所有重复属性的任何想法?

谢谢!

class BDRImageView: UIImageView {
    var borderColor: UIColor? {
        willSet {
            if let color = newValue {
                addBorder(color: color)
            }
        }
    }
}

class BDRLabel: UILabel {
    var borderColor: UIColor? {
        willSet {
            if let color = newValue {
                addBorder(color: color)
            }
        }
    }
}

class BDRButton: UIButton {
    var borderColor: UIColor? {
        willSet {
            if let color = newValue {
                addBorder(color: color)
            }
        }
    }
}

//and so on...

extension UIView {
    func addBorder(color: UIColor) {
        //does add border stuff...
    }
}

3 个答案:

答案 0 :(得分:6)

您可以通过在协议中声明计算属性然后创建采用该协议的每个子类的扩展来减少代码。例如,您当前的代码可以简化为:

protocol BorderColorSettable {}
extension BorderColorSettable where Self: UIView {
    var borderColor: UIColor? {
        get {
            //you will have to supply something here
        }
        set {
            if let color = newValue {
                self.addBorder(color: color)
            }
        }
    }
}

extension UIImageView: BorderColorSettable {}
extension UILabel: BorderColorSettable {}
extension UIButton: BorderColorSettable {}

extension UIView {
    func addBorder(color: UIColor) {
        //does add border stuff...
    }
}

您甚至可以将实现放在协议中以删除UIView约束

extension BorderColorSettable {
    var borderColor: UIColor? {
        get {
            //you will have to supply something here
        }
        set {
            if let color = newValue {
                self.addBorder(color: color)
            }
        }
    }

    func addBorder(color: UIColor) {
        //does add border stuff...
    }
}

概念基本上是这样的:声明一个具有所需功能的协议。创建现有类的扩展(例如UIImageView),除了采用该协议之外什么都不做。然后,它为UIImageView的所有实例提供该协议的功能。

如果你给我一点时间,我可以在测试项目中运行它,以确保它开箱即用。否则你可以尝试自己调整它。

编辑:我把它扔进了一个小项目,似乎工作得很好。例如,在实现所有代码之后,我能够运行这样的操作:

let label = UILabel()
label.addBorder(color: .black)

var label = UILabel()
label.borderColor = .black

希望这符合您的需求。如果我能更彻底地解释它的任何部分,请告诉我。

答案 1 :(得分:1)

您可以利用Objective C运行时功能的关联对象将自定义属性添加到类别中的现有类

extension UIView {

    private struct customProperties {
        static var borderColor: UIColor = .clear
    }

    var borderColor: UIColor? {
        get {
            return objc_getAssociatedObject(self,
                                  &customProperties.borderColor) as?   UIColor
        }
        set {
           if let color = newValue {
                objc_setAssociatedObject(self,
                             &customProperties.borderColor,
                             color,
                             .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
               // Do whatever you want to do with color
          }
       }
    }
}

答案 2 :(得分:0)

您可以在 objc 扩展中添加您的属性,以便它们在 objc 运行时编译并可从子类访问。

@objc extension UIView {
    var borderColor: UIColor {
        get { UIColor(cgColor: layer.borderColor ?? UIColor.clear.cgColor) }
        set { layer.borderColor = newValue.cgColor }
    }
}