Search code examples
swiftgenericsswift-extensions

Swift generic extension for an array in array


I want to define a extension to Array (or Sequence or Collector?) so I can query a list of lists of a custom object with a NSIndexPath and get the object based on the indexPath's section and row.

public var tableViewData = [[MyCellData]]() // Populated elsewhere

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var tableViewCellData = tableViewData.data(from: indexPath)
    // use tableViewCellData
}

// This does not compile as I want the return type to be that of which is the type "in the list in the list" (i.e. MyCellData)
extension Sequence<T> where Iterator.Element:Sequence, Iterator.Element.Element:T {
    func object(from indexPath: NSIndexPath) -> T {
        return self[indexPath.section][indexPath.row]
    }
}

Solution

    • A Sequence cannot be indexed via subscript, so you need a Collection.
    • The collections elements must be collections as well.
    • Since .row, .section are Int, the collection and its nested collection must be indexed by Int. (This is the case for many collections, e.g. arrays or array slices. String.CharacterView is an example of a collection which is not indexed by Int.)
    • You don't need any generic placeholder (and extension Sequence<T> is not valid Swift 3 syntax). Just specify the return type as the element type of the nested collection.

    Putting it all together:

    extension Collection where Index == Int, Iterator.Element: Collection, Iterator.Element.Index == Int {
        func object(from indexPath: IndexPath) -> Iterator.Element.Iterator.Element {
            return self[indexPath.section][indexPath.row]
        }
    }