Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

customizing initWithFrame for UIView

I'm trying to decide on the best way to customize an initializer for UIView so a value can be passed into the initializer and it is immediately stored as an iVar in the UIView subclass, as this value is required for the drawing in drawRect.

Currently I am using the default initWithFrame and the class that creates this UIView then sets its iVar to a value after calling initWithFrame, and it is in fact working; somehow the drawRect is getting this iVar's value even though it is set after the UIView is initialized.

So I need either one of two things:

1) Confidence to know this is okay: that I can rely on drawRect somehow delaying the drawing for a bit so iVars are set by another object after UIView is initialized. In which case, just when in the UIView initializing does drawRect get called?

Or,

2) I need to pass value during initialization: is this the best way to create a custom initializer that takes more than (CGRect)frame as an argument for initWithFrame. Could it be as simple as doing this:

 myNewView=[[MyCustomView alloc] initWithFrame:myRect andMore:myValue];

And then in MyCustomView.m:

 - (id)initWithFrame:(CGRect)frame andMore:(int)someValue
  {
     self = [super initWithFrame:frame];
     if (self) {
       myIvar=someValue;
       ... //continue as normal
     }
  }

Would this code be a good approach? Then I would comfortably know that the value is there before drawRect is called.

like image 846
johnbakers Avatar asked Feb 21 '23 20:02

johnbakers


2 Answers

1.) You can rely on drawRect:to be called after any init. In fact, drawRect: will be called when the view drawing and compositing is done, which usually happens as a result of a Core Animation commit (done at the end of the runloop if you modify any CALayer or UIView (which are always backed by a CALayer)).

2.) This approach is better from an architectural point of view. If you consider this variable to be an integral part to the functionality of your class (and the class can't work properly without it), it should definitely be an init parameter. you might also consider throwing an NSInternalInconsistencyException (or any other exception) inside other init-Methods and/or mark them as deprecated (init-Methods of the superclass will still work fine when called with super initWithFrame:).

like image 132
Martin Ullrich Avatar answered Mar 05 '23 11:03

Martin Ullrich


The second approach is ideal when you explicitly create the view programmatically using the designated initializer you have specified. Caveat: This will not be the case if the view is constructed via a NIB.

like image 42
justin Avatar answered Mar 05 '23 11:03

justin