array index confusion

Hello,

I am curently study the Apple book "Develop in Swift EXPLORATION" and here is something I don't understand: at page 392, there is this advice, of how to populate a segmentedControl with some emoji, each emoji being previously saved in the elements of "topChoices" array.

Here is how the book advice to proceed:

for choice in topChoices {
    topCaptionSegmentedControl.insertSegment(withTitle:
   choice.emoji, at: topChoices.count,animated: false)
}

My confusion come from the fact that although the property "count" means the number of elements in that array, in this above case, it seems that topChoices . count means each index, from zero to the last element (because the segmentedControl is populated with each emoji saved in topChoices elements).

If topChoices.count means the number of elements in the topChoices array, that implies the segmentedControl would have been populated ONLY with the emoji being saved in the last element of the topChoices array. But, the segmentsControl gets populated with all emojis from the topChoices array. How is that? Thank you!

Replies

You need to read carefully what is explained.

  • First, they remove all segments
  • So there are 0 segment left in topCaptionSegmentedControl
  • as they explain, if you insertSegment beyond the number of segments in topCaptionSegmentedControl, it is simply added as the last segment: First segment 0, then segment 1, etc…
  • That's what is happening: until you have topChoices.count segments in topCaptionSegmentedControl (which occurs when the for loop has ended), you add at the end of topCaptionSegmentedControl.

There’s a subtle API design issue that’s helpful to be aware of here...

as they explain, if you insertSegment beyond the number of segments in topCaptionSegmentedControl, it is simply added as the last segment: First segment 0, then segment 1, etc…

UISegmentedControl is a little unusual among array-like data structures as it happily accepts an out-of-bounds index. You could even do this:

topCaptionSegmentedControl.insertSegment(withTitle: choice.emoji, at: 9999999, animated: false)

In fact most of the segmented control methods that accept an index are documented that way:

An index number identifying a segment in the control. It must be a number between 0 and the number of segments (numberOfSegments) minus 1; the segmented control pins values exceeding this upper range to the last segment.

But data structures like NSMutableArray or Swift Array will fail if you pass an out-of-bounds index like that.

IMHO, this was a poor choice in the UISegmentedControl API design. It’s trying to be helpfully forgiving, but this can just mask bugs in the calling code, and is inconsistent with other array-like APIs you use every day. It’s even internally inconsistent: it helpfully clamps indexes that exceed the upper bound, but not the lower bound. Passing +999 works but -1 fails.