Last active
April 12, 2018 16:38
-
-
Save loucimj/eb35f89ea4fd741b3585df828e0fa3a7 to your computer and use it in GitHub Desktop.
Diffable workaround for structs with IGListKit
This file contains 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
// | |
// Diffable.swift | |
// | |
// Created by danielgalasko on 8/5/17. | |
// | |
import Foundation | |
import IGListKit | |
/** | |
A diffable value type that can be used in conjunction with | |
`DiffUtility` to perform a diff between two result sets. | |
*/ | |
public protocol Diffable: Equatable { | |
/** | |
Returns a key that uniquely identifies the object. | |
- returns: A key that can be used to uniquely identify the object. | |
- note: Two objects may share the same identifier, but are not equal. | |
- warning: This value should never be mutated. | |
*/ | |
var diffIdentifier: String { get } | |
} | |
/** | |
Performs a diff operation between two sets of `ItemDiffable` results. | |
*/ | |
public struct DiffUtility { | |
public struct DiffResult { | |
public typealias Move = (from: Int, to: Int) | |
public let inserts: [Int] | |
public let deletions: [Int] | |
public let updates: [Int] | |
public let moves: [Move] | |
public let oldIndexForID: (_ id: String) -> Int | |
public let newIndexForID: (_ id: String) -> Int | |
} | |
public static func diff<T: Diffable>(originalItems: [T], newItems: [T]) -> DiffResult { | |
let old = originalItems.map({ DiffableBox(value: $0, identifier: $0.diffIdentifier as NSObjectProtocol, equal: ==) }) | |
let new = newItems.map({ DiffableBox(value: $0, identifier: $0.diffIdentifier as NSObjectProtocol, equal: ==) }) | |
let result = ListDiff(oldArray: (old as [ListDiffable]), newArray: (new as [ListDiffable]), option: .equality) | |
let inserts = Array(result.inserts) | |
let deletions = Array(result.deletes) | |
let updates = Array(result.updates) | |
let moves: [DiffResult.Move] = result.moves.map({ (from: $0.from, to: $0.to) }) | |
let oldIndexForID: (_ id: String) -> Int = { id in | |
return result.oldIndex(forIdentifier: NSString(string: id)) | |
} | |
let newIndexForID: (_ id: String) -> Int = { id in | |
return result.newIndex(forIdentifier: NSString(string: id)) | |
} | |
return DiffResult(inserts: inserts, deletions: deletions, updates: updates, moves: moves, oldIndexForID: oldIndexForID, newIndexForID: newIndexForID) | |
} | |
} | |
final class DiffableBox<T: Diffable>: ListDiffable { | |
let value: T | |
let identifier: NSObjectProtocol | |
let equal: (T, T) -> Bool | |
init(value: T, identifier: NSObjectProtocol, equal: @escaping(T, T) -> Bool) { | |
self.value = value | |
self.identifier = identifier | |
self.equal = equal | |
} | |
// IGListDiffable | |
func diffIdentifier() -> NSObjectProtocol { | |
return identifier | |
} | |
func isEqual(toDiffableObject object: ListDiffable?) -> Bool { | |
if let other = object as? DiffableBox<T> { | |
return equal(value, other.value) | |
} | |
return false | |
} | |
} | |
extension String: Diffable { | |
public var diffIdentifier: String { return self } | |
func diffable() -> ListDiffable { | |
return DiffableBox(value: self, identifier: self.diffIdentifier as NSObjectProtocol, equal: ==) | |
} | |
} | |
extension Int: Diffable { | |
public var diffIdentifier: String { return String(self) } | |
} | |
extension Sequence where Iterator.Element: Diffable { | |
func diffable() -> [ListDiffable] { | |
let toListDiffable: [ListDiffable] = map{ DiffableBox(value: $0, identifier: $0.diffIdentifier as NSObjectProtocol, equal: ==) } | |
return toListDiffable | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
when
DiffUtility
will be even used ?