Ars looks at an intriguing little puzzle: how can you (elegantly) supply a …

Share this story

IRC development rooms can be funky places; sometimes people approach you with unusual questions that make you think for a bit before you realize the answer might help other developers. Take the other evening, for instance, when someone asked me whether there was an easy way to manage a table data source that could not extend beyond a certain number of cells.

The developer asynchronously downloaded new items and wanted to append these to his data without going past a maximum count for an array. Normally, I'd recommend that he use an NSMutableArray as a queue, but then he pointed out one small issue: he could not guarantee whether the array would be fully populated when adding those new items.

A queue doesn't know much about delaying pops. Whereas a queue takes two operators:push and pull, regardless of its contents, my class needed to use just one: push, returning the head object only when it had filled its capacity. Yes, you can emulate this with a queue by adding a lot of code checking for its size, capacity, etc but there had to be a simpler solution.

Now, seriously, I spent a good deal of time googling for data types and I could not for the life of me remember what a structure like this is called so I am going to be calling it a "data tube". It's not a ring buffer. It's not a blocking queue. It's...a...whatever. Someone should be along shortly to correct me in the comments and tell me exactly what this is.

To create my DataTube, I initially subclassed NSMutableArray until I quickly remembered that you cannot inherit array-ness (to coin a word), but you can create a class that contains one. Instead, I built a simple abstract class that contained a size and an array. The size variable limits the width of the tube. The array stores, as you'd expect, the mutable array.

To make the tube work, each object must pass through the tube before it's pulled out in a FIFO manner. Here's the code I used to create that DataTube class:

To use this class, you initialize it, set its size, and then push items onto it. The following code produces nil, nil, nil, and then @"hello" as return values. (The return values are ignored in this example, but I put them in there because they fit with the way the class should work.)

To use this as your data source, you must be sure to use tube.array.count to set the number of rows for your table. Do not use tube.size. That's because you cannot guarantee that the tube will ever fill. Access the data by recovering [tube.array objectAtIndex:anIndex]. The tube fills from back to front, so the "top" of your table will always be at index 0 if the array count is greater than one.

This isn't all that common a problem to encounter, but I thought it was nifty enough to share. And, if you can tell me exactly what it is that I have defined in official Computer Science-ese or want to improve the implementation, please jump in in the comments.