Is it nil or isn’t it?

A bit of Objective-C weirdness I don’t quite get. The weirdness occurs if “view” in the code below is nil, that is if [idr getAsView:newFrame] returns nil. You’d expect the verticalOffset not to be incremented, but it is. Even though view is nil, view.frame.size.height still evaluates to “21” (in this case) and verticalOffset gets incremented. (The first returned view was 21 high, the second returned view was nil in the debug run I’m referring to.)

- (UIView *)getAsView:(CGRect)theFrame {
	CGFloat verticalOffset = 0.0;
	CGRect hugeFrame = myCGRectHuge(theFrame);
	IDVBase *returnView = [[IDVBase alloc] initWithFrame:hugeFrame];
	hugeFrame = myCGRectResetToZero(hugeFrame);
	
	for (IDRBase *idr in self.parts.parts) {
		CGRect newFrame = myCGRectDown(hugeFrame, verticalOffset);
		UIView *view = [idr getAsView:newFrame];
		[returnView addSubview:view];
		verticalOffset += view.frame.size.height;
	}
	[returnView sizeToFit];
	return [returnView autorelease];
}

To avoid the unintended increment, I have to add the conditional if (view) {…} (which is a pretty good idea anyway, since it’s rather pointless, or maybe even bad, to add a nil as a subView):

- (UIView *)getAsView:(CGRect)theFrame {
	CGFloat verticalOffset = 0.0;
	CGRect hugeFrame = myCGRectHuge(theFrame);
	IDVBase *returnView = [[IDVBase alloc] initWithFrame:hugeFrame];
	hugeFrame = myCGRectResetToZero(hugeFrame);
	
	for (IDRBase *idr in self.parts.parts) {
		CGRect newFrame = myCGRectDown(hugeFrame, verticalOffset);
		UIView *view = [idr getAsView:newFrame];
		if (view) {
			[returnView addSubview:view];
			verticalOffset += view.frame.size.height;
		}
		[returnView addSubview:view];
		verticalOffset += view.frame.size.height;
	}
	[returnView sizeToFit];
	return [returnView autorelease];
}

I don’t know what the moral of this story is. I assume that if I should delve into the language reference, this will turn out to be undefined behaviour. Trying to figure out what could have been defined behaviour, I can’t come up with a reasonable answer, so I guess it’s just one of those things you should avoid doing. Maybe a compiler warning would have been nice, though.

3 thoughts on “Is it nil or isn’t it?”

  1. Isn’t addSubview with a nil argument forbidden, anyway? I would expect that to crash…

    Anyways, iirc, only the first int-sized chunk of the return value is nil’ed, so view.frame.origin.x would be 0, the rest would be junk.

  2. I had assumed that if view is nil, view.frame would be equivalent to [view frame] and be nil, etc. Or rather, [view frame] would not call anything, so maybe the return stack would be garbage.

Leave a Reply

Your email address will not be published. Required fields are marked *