TLDR: Table view (and collection view) data source should be backed by a snapshot of your data store; not a real-time view of it.

I attended last week’s iOS KW meetup, which was a talk by Chris Liscio about Collection View Controllers on iOS and macOS. The talk was good, featuring a lot of interesting details of how Chris implemented the main view in his music app, Capo. But what was really interesting is what I learned in chatting with him afterwards. I’ve been doing iOS development for more than 6 years, and this finally flipped a switch in my brain about why managing updates in table views (and collection views) was always so difficult for me.

Animating updates to a UITableView’s contents is ostensibly pretty easy—you get notifications about the contents of your data store, and you tell your table view which rows were added, removed, or updated. In order to have things animate all together nicely, you do this in a transaction:

tableView.performBatchUpdates { 
	tableView.insertRows(at: [IndexPath(row: 3, section: 1)], animation: .automatic) 
	tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], animation: .automatic)
}

However, there are some arcane rules about the order in which these updates are processed—not in the order in which you submit them, but all reloads first, then deletes, then insertions. In other words, reloads and deletes are processed relative to the state of the table before you begin making any updates, and insertions are processed relative to the state of the table once deletions have completed.

In the past, when I had to make updates based on a completed network request, for instance, I would call tableView.beginUpdates(), then respond to KVO notifications by calling insertRows() and its friends as the network response handler added, updated, and removed items in the data store, and then call endUpdates() when processing was complete. Since the updates to the data store could happen in any order, it was extremely difficult to try to re-order everything so that it would make sense in the order that UITableView performs its updates. Crashes occurred often. This was also a source of high coupling between classes that should have little or now knowledge of each other.

It turns out the answer is very simple. As Chris described, your data source should represent a snapshot of your data, not a real-time view of it. After changes have finished, you move your snapshot forward, compute a diff, and send the necessary insert / delete / refresh messages to the table view. This is apparently what NSFetchedResultsController does under the covers, and other technologies such as Realm allow you to either update your thread’s snapshot manually or at the beginning of a runloop.

The key is that any changes that occur in your UITableViewDataSource should only happen during a table view updates transaction. If your data source reflects the real-time state of your backing store, values might have already changed by the time you’re responding to a them, which can get you into trouble with the frameworks.

So, lesson learned, 6+ years later: `UITableViewDataSource` shouldn’t represent live data. Move your snapshots forward during your table view’s update transactions. Have fewer crashes.


I wrote last year about Swift protocol extensions. If you define a method in a protocol extension that isn’t defined as a protocol requirement, it is dispatched statically, whereas methods defined as protocol requirements are dispatched dynamically. (See the original article for a detailed explanation.)

In March, there was an update – an acknowledgement by the Swift team of this shortcoming and a possibility for a change in behaviour.

Now Ole Begemann writes about Kevin Ballard’s post on swift-evolution explaining very nicely why this limitation exists in the first place:

So essentially, while protocols have a virtual function table, protocol extensions do not, and cannot easily have one because a type adopting the protocol won’t necessarily know about all extensions at compile time and therefore cannot add the extension methods to its own vtable. Opinions may vary whether dispatching protocols dynamically all the time would be a viable alternative, but it’s clearly not what the Swift team has in mind for the language.

Kevin’s post is very informative and worth reading in its entirety.


I wrote in August of last year about some potential confusion coming out of the decision to statically dispatch calls to methods defined in a protocol extension that were not defined in the protocol itself. (Whereas calls to methods defined in the protocol are always dynamically dispatched.) This allowed the protocol / extension designer to differentiate between customization points (methods defined in the protocol) and non-customizable code (methods not defined in the protocol, but implemented in an extension).

It looks like Apple’s received some feedback around this, and Doug Gregor acknowledges this is his “Completing Generics” Manifesto. (Update May 5: Austin Zheng has created a formatted version of the manifesto, available on GitHub.) However I’m not optimistic that this will get changed in future versions of Swift, as he puts it in his “Maybe” section:

Maybe

There are a number of features that get discussed from time-to-time, while they could fit into Swift’s generics system, it’s not clear that they belong in Swift at all. The important question for any feature in this category is not “can it be done” or “are there cool things we can express”, but “how can everyday Swift developers benefit from the addition of such a feature?”. Without strong motivating examples, none of these “maybes” will move further along.

Dynamic dispatch for members of protocol extensions

Only the requirements of protocols currently use dynamic dispatch, which can lead
to surprises:

protocol P {
  func foo()
}
extension P {
  func foo() { print(“P.foo()”)
  func bar() { print(“P.bar()”)
}
struct X : P {
  func foo() { print(“X.foo()”)
  func bar() { print(“X.bar()”)
}
let x = X()
x.foo() // X.foo()
x.bar() // X.bar()
let p: P = X()
p.foo() // X.foo()
p.bar() // P.bar()

Swift could adopt a model where members of protocol extensions are dynamically dispatched.

Fingers crossed, but I think the ship has probably sailed on this – I wonder if the change of behaviour would result in more confusing bugs than this quirk of the language did in the first place.


For a few weeks I’ve been working on a new iOS app, written in Swift. The problem domain is super simple: it’s just a list of what I’m calling “reminder snippets” – for now, basic Title / Value pairs – that are editable in the app, and show up in a Today View Snippet.

Screenshot of example app, Neumonic

Having the problem domain so small allows me to experiment with Swift and potential architectures. I’ve been incorporating some lessons I learned from colleagues at my last job, like using immutable model objects (Swift structs, naturally, for value semantics) and Repositories that are responsible for persistence, caching, and so on.

Protocols

I took the Protocol Oriented Programming talk from last year’s WWDC to heart, so every abstraction in the app is a protocol. (I’ve already written a bit about this talk here.) Specifically, I have a ReminderRepository protocol (with MockReminderRepository and PlistReminderRepository implementations) and a Reminder protocol, with one incredibly simple implementation.

public typealias ReminderID = String

public protocol Reminder{
    var id : ReminderID { get }
    var title : String { get }
    var value : String { get }
}

public protocol ReminderRepository {
    func getAllReminders(callback: Result<[Reminder]> -> Void)
    func getReminder(by id: ReminderID, callback: Result<Reminder> -> Void)
    func addReminder(reminder: Reminder, callback: VoidResult -> Void)
    func deleteReminder(reminder: Reminder, callback: VoidResult -> Void)
}

(Result is just a Success/Fail enum that contains some value on success and an error on failure)

Equatable

So far, so good. I really like this architecture. But problems start to crop up when I need to be able to compare Reminders, for instance, in an implementation of deleteReminder:

public func deleteReminder(reminder: Reminder, callback: VoidResult -> Void) {
    // Error. Can't call indexOf because reminder doesn't conform to Equatable
    if let index = reminders.indexOf(reminder) {        
        reminders.removeAtIndex(index)
        callback(.Success)
    } else {
        callback(.Failure)
    }
}

But if we make Reminder conform to Equatable, we lose the ability to have a heterogeneous array of types that conform to Reminder. (Details are in the Protocol Oriented Programming talk. Seriously, watch it.)

The solution given in the talk for general-case comparison is to implement an extension on our protocol. I thought I’d be clever and factor this out into a new protocol, HeterogeneousEquatable, and have Reminder extend from that.

public protocol HeterogeneousEquatable {
    func isEqual(other : Any) -> Bool
}

public extension HeterogeneousEquatable where Self : Equatable {
    public func isEqual(other : Any) -> Bool {
        if let typedOther = other as? Self {
            return typedOther == self
        }
        return false
    }
}

public protocol Reminder : HeterogeneousEquatable { /* ... */ }

Array.indexOf()

Now returning to the reason I initially wanted to make Reminders Equatable – so that I can call reminders.indexOf(someReminder). Right now we still can’t do that, because while we have roughly equivalent functionality, it doesn’t come under the auspices of the Equatable protocol.

Okay, so what if we just extend Array ourselves?

public extension Array where Element : HeterogeneousEquatable {
    func indexOf(element : Element) -> Index? {
        return indexOf({ (currentElement : Element ) -> Bool in
            element == currentElement
        })
    }
}

Great! Everything still compiles. Now we just have to call our overloaded implementation of indexOf:

public func deleteReminder(reminder: Reminder, callback: VoidResult -> Void) {
    // Error again. Sad face.
    if let index = reminders.indexOf(reminder) {        
        reminders.removeAtIndex(index)
        callback(.Success)
    } else {
        callback(.Failure)
    }
}

Now we get Using "Reminder" as a concrete type conforming to protocol "HeterogeneousEquatable" is not supported. Which is true. Reminder isn’t a concrete type. This is a shortcoming in the compiler; it needs things to be nailed down to concrete types here. One can assume that the reason for this is compiler implementation rather than an intentional limitation of the language at a design level. There’s a great Stack Overflow answer by Rob Napier on this.

A Mediocre Solution

Austin Zheng has a blog post about building a HeterogeneousEquatable (which he calls AnyEquatable), which is a good resource if you found my post hard to follow, but he doesn’t look at the case of implementing an extension on Array.

I asked about this on the swift-users mailing list, and Hooman Mehr pointed out that the best way to achieve this is to write a method in an unconditional extension on Array:

extension Array {
    func indexOf(element : HeterogeneousEquatable) -> Index? {
        return self.indexOf { (currentElement : Element) -> Bool in
            if let currentElement = currentElement as? HeterogeneousEquatable {
                return element.equals(currentElement)
            }
            return false
        }
    }
}

This makes me sad. It forces me to pollute the interface of Array with stuff that doesn’t apply in most cases, and it causes confusion about which implementation of indexOf will be called in an instance of [MyType] where MyType implements both Equatable and HeterogeneousEquatable. (The other option is to name it indexOfAny, as Hooman suggests, but I don’t much like that either.)

A Better Solution, Sometimes

I took my quest to the swift-evolution mailing list, and got better results, but they only apply in certain situations.

Dave Abrahams (the guy who gave the Protocol Oriented Programming talk in the first place!) showed that while we can’t use a value of type HeterogeneousEquatable (where the concrete type is unknown) where the requirement is Element : HeterogeneousEquatable, we can do that when the requirement is Element == HeterogeneousEquatable. That’s awesome!

But.

That means that the variable must be typed explicitly as HeterogeneousEquatable. Reminder, even though it extends from HeterogeneousEquatable, is not acceptable.

public extension CollectionType where Generator.Element == HeterogeneousEquatable {
    func indexOf(item: Generator.Element) -> Index? {
        return indexOf {
            return item.isEqual($0)
        }
    }
}

// ...

public func deleteReminder(reminder: Reminder, callback: VoidResult -> Void) {
    if let index = reminders.indexOf(reminder) {        
        reminders.removeAtIndex(index)
        callback(.Success)
    } else {
        callback(.Failure)
    }
}

Type HeterogeneousEquatable does not conform to protocol 'Reminder'

Conclusion

I’ve had to go ahead with the unconditional extension of Array. It’s the only thing that works properly for my use case, at least today.

It is my desperate hope that future versions of Swift will allow for this kind of abstraction – or just go ahead and solve the Equatable problem in a first-party way.

Denouement

Back when the WWDC talk was new there was a big kerfuffle in the Apple development community about the problem of heterogeneous collections of things that conform to a single protocol – how the decision to split protocols into “has Self requirements” and “doesn’t have self requirements” worlds was benefiting the compiler at the expense of the programmer. Michael Tsai has a good overview of the various blogs from that time, all of which are worth a read, including this post from Brent Simmons:

Something like this ought to come naturally and easily to a language, or else that language is not helping me write apps.

I’m generally very positive on Swift – I think when Swift 3.0 hits and the language starts to change a little more slowly, it will be the obvious choice for future projects – but it has some sharp edges for the time being, and if I was to start a production-ready project today, I’m not entirely sure whether I’d choose Swift or Objective-C.


Mike Ash’s Friday Q&A this week takes on Swift’s funny-looking String API. Most of what you’d normally want to do with strings is absent — for the time being, we should be using NSString methods — and it doesn’t allow us to iterate over its characters in the way we’d expect. As of Swift 2.0, we can’t do:

for char in "some string" { /* ... */ }

That’s because there are several ways to interpret the above code — do we want to iterate over all bytes in the string, assuming it’s represented as UTF-8? All Unicode code points? All grapheme clusters? The String API’s design in Swift 2 forces the developer to explicitly decide by exposing these possibilities as views on the string, leaving the system’s internal representation of the string as an invisible implementation detail.

From Mike’s post:

Swift’s String type takes an unusual approach to strings. Many other languages pick one canonical representation for strings and leave you to fend for yourself if you want anything else. Often they simply give up on important questions like “what exactly is a character?” and pick something which is easy to work with in code but which sugar-coats the inherently difficult problems encountered in string processing. Swift doesn’t sugar-coat it, but instead shows you the reality of what’s going on. This can be difficult, but it’s no more difficult than it needs to be.

This is an excellent companion to objc.io‘s must-read NSString and Unicode showing the implications for Swift.

If you want the Cole’s Notes version, Apple has a pretty good, much shorter explainer on their Swift blog.