1

Context:

  • MainView.xib: I've laid out my UI elements and painstakingly aligned them perfectly using autolayout. There are a whole bunch of UIButtons, a UILabel and a UIToolbar. The hierarchy is pretty flat like this:

    UIView // Hooked up to ViewController
    |
    - UILabel
    - UIButton
    - UIButton
    - UIButton
    - ... // more buttons
    - UIToolbar
    
  • ViewController.m:

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property NSArray *_allButtons;
    
    // Interface elements
    @property IBOutlet UILabel *titleLabel;
    @property IBOutlet UIButton *button1;
    @property IBOutlet UIButton *button2;
    // ... lots more buttons
    @property IBOutlet UIToolbar *toolbar;
    
    @end
    
    @implementation ViewController
    
    - (void)loadView {
        UIView *mainView = [[[NSBundle mainBundle] loadNibNamed:@"MainView"
                                                          owner:self
                                                        options:nil] objectAtIndex:0];
        self.view = mainView;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // BREAK_POINT
    
        // ... code to wire up the UIButtons to dynamically created objects
    }
    

Wierd Observation:

I've correctly hooked up my individually created IBOutlet UIButton button<n> pointers to the UIButtons in the .xib file. And that code works fine.

However, it's a pain to maintain all the buttons individually like this. I could create them all programmatically, but it's much nicer to move them around visually in Interface Builder (now that I've learnt how to use it).

I figured I could remove the IBOutlet connections for the UIButtons, and find them as subviews of the main UIView in MainView.xib, with some code like this in viewDidLoad:

for (UIView *view in self.view.subviews) {
    if( [view isKindOfClass:[UIButton class]]) {
        [self._allButtons addObject:view];
    }
}

Unfortunately, self._allButtons was turning out to be an empty array.

So, I brought back the IBOutlet connections, dropped in a break point in viewDidLoad, and saw this:

(lldb) po self.view
<UIView: 0x7fa7897e2140; frame = (0 0; 600 600); autoresize = W+H; layer = <CALayer: 0x7fa7897e2210>>

(lldb) po self.view.subviews
<__NSArrayI 0x7fa789713500>(

)
(lldb) po [self.view.subviews count];
 nil
(lldb) po self.button1
<UIButton: 0x7fa78955ea70; frame = (-23 -15; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fa7897663d0>>

Which is incredibly strange...that button1 is initialized, but is not a subview of the UIView.

Questions:

1. Why is self.view.subviews empty in viewDidLoad?

2. Is there a way I can create UIButtons in Interface Builder and get a reference to them in viewDidLoad?

Vidur
  • 1,442
  • 2
  • 17
  • 37

2 Answers2

1

Try to do that in

- (void)viewDidLayoutSubviews{


}

This method get called after loading all the subviews. Hope this will help you :)

Augustine P A
  • 5,008
  • 3
  • 35
  • 39
  • That didn't work. I moved that part of the question here if you're interested: http://stackoverflow.com/questions/27149391/why-is-self-view-subviews-an-empty-array-in-viewdidload – Vidur Nov 26 '14 at 12:57
  • Huh, you were right after all...I just tried it again and it worked out. Do you mind replying to the question here with this answer? - http://stackoverflow.com/questions/27149391/why-is-self-view-subviews-an-empty-array-in-viewdidload and I'll gladly accept it as the best one. Thanks! – Vidur Nov 26 '14 at 16:03
0

So I figured out a bunch of this myself, using some old Apple documentation. It's kinda common sensical really. I'll move Question #1 to a separate question with less overhead since it doesn't look like anyone is bothered to read this huge question.

Easiest way to not make a shit load of IBOutlets for a collection of UIButtons is to...wait for it...use an IBOutletCollection:

@property IBOutletCollection(UIButton) NSArray *buttons;

And then drag and order the UIButtons into the File Owner's IBOutletCollection in the xib. My code is a whole lot cleaner, and I didn't have to hackily loop through subviews etc.

Source:

View Programming Guide for iOS - Locating Views in a View Hierarchy:

Storing references to relevant views is the most common approach to locating views and makes accessing those views very convenient. If you used Interface Builder to create your views, you can connect objects in your nib file (including the File’s Owner object that represents the managing controller object) to one another using outlets. For views you create programmatically, you can store references to those views in private member variables.

Looks like the only way to access elments created in Interface Builder is through IBOutlets/IBOutletCollections.

Will edit this answer with a link to my new question in a bit.

Question #1 moved here: Why is self.view.subviews an empty array in viewDidLoad?

Community
  • 1
  • 1
Vidur
  • 1,442
  • 2
  • 17
  • 37