Accessing controls in UIView subviews

Sep 25, 2011 11:56 · 553 words · 3 minute read code iOS objective-C

The iPhone app I’m working on at the moment has a number of screens that consist of long list of questions - so the user needs to be able to scroll down to the bottom.

At the same time, there’s some information at the top of the screen which needs to stay visible. Within the subview containing the questions, there are also several buttons which need to trigger methods in the main view controller - save the answers, move to the next screen and so on.

I’ve done this placing a scrollview in the bottom 23 of the screen; and placing all the questions and their associated images into a subview which gets loaded into said scroll view.

The easiest way of putting together the questions view was as a separate nib, but that then posed the question “how to access the controls inside the nib once it’s loaded?” The answer actually seems fairly straight-forward once I figured it out.

The trick is to exploit the fact that controls like UIButtons, UITextLabels, UIImageViews and so on all inherit from the UIView parent class. That means they inherit the tag property - an integer value associated with that particularly control instance that allows you to uniquely identify it from within the overall hierarchy of views.

When creating the nib in Interface Builder, put it together as you would a normal view - but every control that you want to access from the main view controller needs to have a unique tag set.

I tend to start numbering them at 1010 and work up in 10s from there - which reminds me of the old Basic days when programs would start “10 print “hello”…

To get the custom view displayed in the scrollview, you first have to load it. That’s done with:

NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"scrollViewNib" owner:self options:nil];

This loads the nib and places its view objects into an array called nibObjects. As far as I can tell, the index of each UIView object in the array corresponds to its place in the hierarchy of views in the nib - which makes the view object at index 0 the main view object into which all the others have been placed.

Once you’ve got the array, you can get a reference to the main view of the nib through the object at index 0:

UIView *nibView = [nibObjects objectAtIndex:0];

At this point you’ll want to add it into the scrollview:

[scrollview addSubview:nibView];

and set the scrollView’s content size to the dimensions of the nibView:

[scrollView setContentSize:CGSizeMake(nibView.frame.size.width, nibView.frame.size.height);

Now you can access the individual buttons, labels, imageviews and so on by exploiting their having the aforementioned tag property. So getting a reference to a UIView subclass with the tag 1050 would be done with:

UIView *aButtonView = [nibView objectWithTag:1050];

That gives you a generic UIView object, which although helpful isn’t the full story. To access the properties of the control itself, you’ll first need to cast the generic object into the class that you’re trying to work with. So instead of the line above, you actually need:

UIButton *aButtonView = (UIButton *)[nibView objectWithTag:1050];

Now you’ve got a bona-fide UIButton, it’ll respond to button methods such as

[aButtonView addTarget:self action:@selector(aButtonTapped) forControlEvent:UIControlEventTouchUpInside];
[aButtonView setEnabled:YES]; 

and so on. Set each control’s methods as required, and away you go.