1

I am implementing a Circle class (subclass of UIView) in Swift that sets its radius in its initializer according to the frame that is passed in init(frame: CGRect) like so:

override init(frame: CGRect)
{
    radius = frame.width/2.0
    super.init(frame: frame)
}

I also want to ensure for the case when the circle is instantiated from Interface Builder, so I also implement 'required init(coder aDecoder: NSCoder)` (which I am forced to do by Xcode anyway).

How can I retrieve the frame property of the view that is somehow contained in aDecoder. What I want to achieve basically would look like this:

required init(coder aDecoder: NSCoder)
{
   var theFrame = aDecoder.someHowRetrieveTheFramePropertyOfTheView // how can I achieve this?
   radius = theFrame.width/2.0
   super.init(coder: aDecoder)
}
nburk
  • 22,409
  • 18
  • 87
  • 132

2 Answers2

8

You could compute the radius after the frame has been set by super.init():

required init(coder aDecoder: NSCoder)
{
    radius = 0 // Must be initialized before calling super.init()
    super.init(coder: aDecoder)
    radius = frame.width/2.0
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Isn't it possible to get such a value from `NSCoder` directly? Anyway, that'll solve my problem, just wondering if there is a more "elegant" way. – nburk Oct 12 '14 at 09:53
  • @nburk: You could try `let theFrame = (aDecoder.decodeObjectForKey("frame") as NSValue).CGRectValue()` but I doubt that that is more elegant. And it might break if the representation of the frame in the coder changes. – Martin R Oct 12 '14 at 10:02
3

Martin's answer is the correct one. (Voted). You might be able to find the way that the base class encodes the frame value and extract it, but that is fragile. (It relies on private details of the implementation of the base class, which might change and break your app in the future.) Don't develop code that depends on non-public implementation details of another class, or of your base class. That's a future bug just waiting to happen.

The pattern in initWithCoder is to first call super to get the values for the ancestor class, then extract the values for your custom class.

When you do it that way, the ancestor class will have already set up your view's frame for you, and you can just use that.

Duncan C
  • 128,072
  • 22
  • 173
  • 272