1

I have three Swift Classes:

@IBDesignable class CustomTextField : UITextField {

  @IBInspectable var borderColor: UIColor = UIColor.clearColor() {
    didSet {
      layer.borderColor = borderColor.CGColor
    }
  }

}

@IBDesignable class CustomView : UIView {

  @IBInspectable var borderColor: UIColor = UIColor.clearColor() {
    didSet {
      layer.borderColor = borderColor.CGColor
    }
  }

}

@IBDesignable class CustomButton : UIButton {

  @IBInspectable var borderColor: UIColor = UIColor.clearColor() {
    didSet {
      layer.borderColor = borderColor.CGColor
    }
  }

}

All three classes have the same computed property (borderColor). I want to be DRY (don't repeat yourself) and have such repeated computed properties or methods inherited from somewhere. Is there a way to do that?

I know there's a way to do this with protocol extensions and default implementations of protocol methods - but it doesn't seem so clean:

Calling protocol default implementation from regular method

Community
  • 1
  • 1
etayluz
  • 15,920
  • 23
  • 106
  • 151
  • If creating these 3 new classes is not necessary, see http://stackoverflow.com/questions/14792238. – kennytm Aug 23 '16 at 05:44

2 Answers2

0

I guess this can work, although IMO not perfect:

protocol BorderColorView {
    var borderColor: UIColor! { get set }
}

extension BorderColorView {
    var borderColor: UIColor! {
        get {
            if let color = (self as? UIView)?.layer.borderColor {
                return UIColor(CGColor: color)
            }
            return nil
        }
        set {
            (self as? UIView)?.layer.borderColor = newValue.CGColor
        }
    }
}

//Example usage:

class MyView: UIView, BorderColorView { }

A disadvantage of this is that you can only conform to this protocol in a UIView, but not other classes.

Alternatively, you can do this:

protocol BorderColorView {
    var view: UIView { get }
    var borderColor: UIColor! { get set }
}

extension BorderColorView {
    var borderColor: UIColor! {
        get {
            if let color = (self as? UIView)?.layer.borderColor {
                return UIColor(CGColor: color)
            }
            return nil
        }
        set {
            (self as? UIView)?.layer.borderColor = newValue.CGColor
        }
    }
}

// Example usage:

class MyView: UIView, BorderColorView {
    var view: UIView {
        return self
    }
}

You see, this will create a little duplicate code. Not as much as that in your question, but still, it's duplicate code. Choose wisely which onw you want.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Thanks for the effort, but your code doesn't compile. – etayluz Aug 23 '16 at 06:56
  • @etayluz Really? I tried it in the playground! Did you use the code from before the edit? That was wrong. Please use the code from revision number 2. – Sweeper Aug 23 '16 at 06:59
  • I'm seeing Type 'MyView' does not conform to protocol 'BorderColorView'. Running XCode 7.3.1 – etayluz Aug 23 '16 at 07:15
  • @etayluz Yes, this is exactly the error you get when you use the old code. Copy the code in the answer now and try it again – Sweeper Aug 23 '16 at 07:16
  • OK that's cool thanks, Sweeper - can you get @IBInspectable in there as well? – etayluz Aug 23 '16 at 07:19
  • 1
    @etayluz unfortuantely, no. `@IBInspectable` can only be applied to instance properties. I'm sorry. – Sweeper Aug 23 '16 at 07:22
0

Why don't you write an extension for UIView and you will be able to use it in every UI element

JuicyFruit
  • 2,638
  • 2
  • 18
  • 35