Jessica
Jessica

Reputation: 2435

Where is the best place to define frame sizes for subviews?

Where do most programmers specify how big frames are supposed to be? I tried to put the following code in the instance variables section of a .h file

    CGRect backButtonRect = CGRectMake(2 * w/25, 18 * h/25, 6 * w/25, 2 * h/25);

but it won't let me for some reason. I want to put the parameters in a place that's easy to remember so I can debug it later.

Upvotes: 0

Views: 76

Answers (2)

rob mayoff
rob mayoff

Reputation: 386018

You cannot initialize an instance variable in its declaration. That's just the way Objective-C is. It's different from Java or C# (or C++11) in this regard. All instance variables are initialized to zero.

You didn't say what class contains this instance variable.

If you're loading the object from a XIB or storyboard, it doesn't matter what class it is; it will be initialized by receiving an initWithCoder: message. So initialize backButtonRect in initWithCoder:. Example:

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) {
        CGFloat w = 100, h = 64;
        backButtonRect = CGRectMake(2 * w/25, 18 * h/25, 6 * w/25, 2 * h/25);
    }
    return self;
}

Alternatively, if you won't know w and h until all of your outlets are hooked up, initialize backButtonRect in awakeFromNib:

- (void)awakeFromNib {
    [super awakeFromNib];
    backButtonRect = CGRectMake(2 * w/25, 18 * h/25, 6 * w/25, 2 * h/25);
}

If you're creating the object in code, then it does matter what class it is. If it's a UIView subclass, the designated initializer is initWithFrame:, so that's a good method to override for your initialization:

- (instancetype)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        CGFloat w = 100, h = 64;
        backButtonRect = CGRectMake(2 * w/25, 18 * h/25, 6 * w/25, 2 * h/25);
    }
    return self;
}

If it's a UIViewController subclass, then the designated initializer is initWithNibName:bundle:.

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        CGFloat w = 100, h = 64;
        backButtonRect = CGRectMake(2 * w/25, 18 * h/25, 6 * w/25, 2 * h/25);
    }
    return self;
}

Upvotes: 4

Wain
Wain

Reputation: 119041

You should try not to have explicit frame definitions anywhere. If you do need them then putting them in an XIB with the view definitions is good. Where you do want to specify frames in code you should try to make things proportional and dynamic so the sizes of some things are set but most things are calculated based on the superview frame and the things with static sizes. This supports modifications in the future for slightly different screen sizes.

For the things you do need to specify, adding #define at the top of the .m file is good. It's good to name these with capitals and underscores so you can clearly see when reading the code that they are defined constants.

Upvotes: 0

Related Questions