Please help with generic init definition

In @johnsundell IdentifierableIndices

He has this:

extension ForEach where ID == Data.Element.ID, Data.Element: Identifiable, Content: View {
    init<T>(_ indices: Data,  @ViewBuilder content: @escaping (Data.Index) -> Content) where Data == IdentifiableIndices<T> {
        self.init(indices) { index in
            content(index())
        }
    }
}

Used like this:

ForEach(someArray.identifierableIndices, content: contentView)

I want to add another init so I can:

ForEach(indicesOf: someArray, content: contentView)

I just couldn't make it:

extension ForEach where ID == Data.Element.ID, Content : View, Data.Element : Identifiable {
    // error: Cannot convert value of type 'IdentifiableIndices<Data>' to expected argument type 'Data'
    init(indicesOf data: Data,  @ViewBuilder content: @escaping (Data.Index) -> Content) {
        self.init(IdentifiableIndices(base: data), content: content)
    }
}
All the code
import Foundation
import SwiftUI

struct IdentifiableIndices<Base: RandomAccessCollection> where Base.Element: Identifiable {

    typealias Index = Base.Index

    struct Element: Identifiable {
        let id: Base.Element.ID
        let rawValue: Index

        func callAsFunction() -> Index { rawValue }
    }

    fileprivate var base: Base
}

extension IdentifiableIndices: RandomAccessCollection {
    var startIndex: Index { base.startIndex }
    var endIndex: Index { base.endIndex }

    subscript(position: Index) -> Element {
        Element(id: base[position].id, rawValue: position)
    }

    func index(before index: Index) -> Index {
        base.index(before: index)
    }

    func index(after index: Index) -> Index {
        base.index(after: index)
    }
}

extension RandomAccessCollection where Element: Identifiable {
    var identifiableIndices: IdentifiableIndices<Self> {
        IdentifiableIndices(base: self)
    }
}

extension ForEach where ID == Data.Element.ID, Data.Element: Identifiable, Content: View {
    init<T>(_ indices: Data,  @ViewBuilder content: @escaping (Data.Index) -> Content) where Data == IdentifiableIndices<T> {
        self.init(indices) { index in
            content(index())
        }
    }
}

extension ForEach where ID == Data.Element.ID, Content : View, Data.Element : Identifiable {
    // error: Cannot convert value of type 'IdentifiableIndices<Data>' to expected argument type 'Data'
    init(indicesOf data: Data,  @ViewBuilder content: @escaping (Data.Index) -> Content) {
        self.init(IdentifiableIndices(base: data), content: content)
    }
}
1 Like

I haven't read the linked article, but based solely on the type signatures and the compiler error you're receiving, I guess you're looking for the following:

extension ForEach where ID == Data.Element.ID, Data.Element: Identifiable, Content: View {
    init<T>(_ indices: Data,  @ViewBuilder content: @escaping (Data.Index) -> Content) where Data == IdentifiableIndices<T> {
        self.init(indices) { index in
            content(index())
        }
    }

    init<T>(indicesOf data: T,  @ViewBuilder content: @escaping (T.Index) -> Content) where Data == IdentifiableIndices<T> {
        self.init(IdentifiableIndices(base: data), content: content)
    }
}
2 Likes
Terms of Service

Privacy Policy

Cookie Policy