32

I have two contradicting sources in regards to IBOutletCollection with NSArray. First says that the order that you link things from interface to outlet collection is significant, and it will always be the same in outlet collection. E.g. if we link first text field first to collection, element number 0 will be that field, etc.

But another source tells me that this is wrong and actually Outlet collection is randomized and there is absolutely no guarantee in the order of things. So element number zero can be any text field, and not just the first connected in interface.

"iOS 6 Programming - exploring iOS SDK" is the first source and Stanford course on iTunes is the second source. Who is right?

Mike Abdullah
  • 14,933
  • 2
  • 50
  • 75
Dvole
  • 5,725
  • 10
  • 54
  • 87

4 Answers4

30

Simply assign the order of controls by tag and on load reorder them.


property observing:

@IBOutlet var btnCollection: [UIButton]! {
    didSet {
        btnCollection.sort { $0.tag < $1.tag }
    }
}

in viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    btnCollection = btnCollection.sorted { $0.tag < $1.tag }
}
LionHere
  • 9
  • 1
  • 2
Darshit Shah
  • 2,366
  • 26
  • 33
20

Both sources are sort of right: on one hand, due to the implementation details of the Interface Builder, the order in which you add items to IBOutletCollection will be maintained on retrieval; on the other hand, you should avoid making use of that ordering in your code, because there is no way to check this order.

Imagine taking over someone else's project. If you see a loop over an IBOutletCollection, observe that the order of iteration matters, and decide to check what that order is or force the new order, you would have to remove and re-add the controls to your outlet collection. That is why you should treat your IBOutletCollection elements as unordered. If it is necessary to maintain a specific order, copy the elements into an NSArray, sort them on some known property, and then iterate the copied collection.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • This means that Stanford Course is wrong. Since Paul Hegarty (At least on the latest iOS 7 course https://itunes.apple.com/us/course/developing-ios-7-apps-for/id733644550?affId=1736887 3.Objective-C class time - 47:50 ) said that there is NO order. He didn't argue that you shouldn't depend on it, he said there is no specified order :). – Paweł Brewczynski Dec 11 '13 at 20:17
  • 3
    @bluesm There's no such thing as "no order": where there's a sequence, there's *some* order. It may be arbitrary, but if you can enumerate something, that something does have an order. When they say that a sequence has no order, they mean that the sequence has no *specific* order. – Sergey Kalinichenko Dec 11 '13 at 20:23
  • Yes. I meant that Paul Hegarty said "Order is not specified by the order you drag the views to Outlet collection." Which is wrong. – Paweł Brewczynski Dec 11 '13 at 20:36
  • I think you could be wrong that new Developer CAN'T figure out the order of the objects in outletCollection which is really just NSArray. See: http://grab.by/sMgK (whole code here : https://gist.github.com/bluesm/7919727#file-gistfile1-xml-L151 lines 151-184) and read comments. It just seems that you CAN check that in the source code of storyboard. Thanks in advance for answer. – Paweł Brewczynski Dec 11 '13 at 22:35
  • @bluesm Storyboard has no "source code" - its structure is supposed to be opaque. Moreover, Apple should have the full power to change the implementation of storyboards at a later time, in a way that reorders items inside `IBOutletCollection` - say, by employing a hash set during preprocessing. – Sergey Kalinichenko Dec 11 '13 at 22:40
  • The order is fixed when the elements are connected to the collection. But when the container view is 'embed in view' the order will be messed up. If the order matters you should tag each view and then sort the views by tag before using them. – Alex Pelletier Jun 12 '17 at 07:02
6

It seems like in Xcode 7.x IBOutlet collection is ordered.

For sure, you can assign tag property to every element in collection in needed order and do something like

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.outletCollection = [self.outletCollection sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"tag" ascending:YES]]];
}
art-of-dreams
  • 241
  • 3
  • 12
  • 5
    In Swift you can use "outletCollection = outletCollection.sorted { $0.tag < $1.tag }" or "outletCollection.sort { $0.tag < $1.tag }". – Monte Hurd Mar 08 '17 at 00:41
2

In Xcode 7.2 IBOutlet collection is ordered in the way as connections were made. I did test it using Swift on iOS 8.2 and 9.2.

Ramis
  • 13,985
  • 7
  • 81
  • 100