Skip to content

Instantly share code, notes, and snippets.

@loucimj
Last active April 12, 2018 16:38
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loucimj/eb35f89ea4fd741b3585df828e0fa3a7 to your computer and use it in GitHub Desktop.
Save loucimj/eb35f89ea4fd741b3585df828e0fa3a7 to your computer and use it in GitHub Desktop.
Diffable workaround for structs with IGListKit
//
// 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
}
}
@tunidev
Copy link

tunidev commented Oct 11, 2017

when DiffUtility will be even used ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment