Created
January 9, 2021 10:49
-
-
Save koher/095eed09a3f8369bd0e72dbd9e689a72 to your computer and use it in GitHub Desktop.
Extensions for `Binding` to make collections available with `ForEach` keeping bindings to their elements
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
extension Binding: Identifiable where Value: Identifiable { | |
public var id: Value.ID { | |
wrappedValue.id | |
} | |
} | |
extension Binding: Sequence where Value: MutableCollection, Value: RandomAccessCollection, Value.Element: Identifiable { | |
public typealias Element = Binding<Value.Element> | |
public func makeIterator() -> BindingIterator { | |
BindingIterator(collection: self) | |
} | |
public struct BindingIterator: IteratorProtocol { | |
private let collection: Binding<Value> | |
private var indices: Value.Indices.SubSequence | |
fileprivate init(collection: Binding<Value>) { | |
self.collection = collection | |
self.indices = collection.wrappedValue.indices[...] | |
} | |
public mutating func next() -> Binding<Value.Element>? { | |
guard let index = indices.popFirst() else { return nil } | |
return collection[index] | |
} | |
} | |
} | |
extension Binding: Collection where Value: MutableCollection, Value: RandomAccessCollection, Value.Element: Identifiable { | |
public typealias Index = Value.Index | |
public typealias Indices = Value.Indices | |
public typealias SubSequence = Binding<Value.SubSequence> | |
public subscript(index: Value.Index) -> Binding<Value.Element> { | |
get { | |
var element0 = wrappedValue[index] | |
let id = element0.id | |
return Binding<Value.Element>( | |
get: { | |
let element = wrappedValue[index] | |
if element.id == id { | |
element0 = element | |
return element | |
} else { | |
if let element = wrappedValue.first(where: { $0.id == id }) { | |
element0 = element | |
return element | |
} else { | |
// Dummy value for dangling bindings | |
return element0 | |
} | |
} | |
}, | |
set: { newValue in | |
let element = wrappedValue[index] | |
if element.id == id { | |
wrappedValue[index] = newValue | |
} else { | |
if let index = wrappedValue.firstIndex(where: { $0.id == id }) { | |
wrappedValue[index] = newValue | |
} else { | |
// Ignores changes through dangling bindings | |
} | |
} | |
} | |
) | |
} | |
} | |
public var indices: Value.Indices { | |
wrappedValue.indices | |
} | |
public var startIndex: Value.Index { | |
wrappedValue.startIndex | |
} | |
public var endIndex: Value.Index { | |
wrappedValue.endIndex | |
} | |
public func index(after i: Value.Index) -> Value.Index { | |
wrappedValue.index(after: i) | |
} | |
} | |
extension Binding: BidirectionalCollection where Value: MutableCollection, Value: RandomAccessCollection, Value.Element: Identifiable { | |
public func index(before i: Value.Index) -> Value.Index { | |
wrappedValue.index(before: i) | |
} | |
} | |
extension Binding: RandomAccessCollection where Value: MutableCollection, Value: RandomAccessCollection, Value.Element: Identifiable { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment