-
Notifications
You must be signed in to change notification settings - Fork 75
EpoxyCore
EpoxyCore
contains shared logic that all of the other Epoxy
module rely on. While we feel that EpoxyCore
is best used with the rest of Epoxy
, you can certainly use it by itself.
The diffing section of EpoxyCore
implements a version of Paul Heckel's difference algorithm for fast and efficient diffing between two collections. There are two protocols of note: Diffable
and DiffableSection
:
/// A protocol that allows us to check identity and equality between items for the purposes of
/// diffing.
public protocol Diffable {
/// Checks for equality between items when diffing.
///
/// - Parameters:
/// - otherDiffableItem: The other item to check equality against while diffing.
func isDiffableItemEqual(to otherDiffableItem: Diffable) -> Bool
/// The identifier to use when checking identity while diffing.
var diffIdentifier: AnyHashable { get }
}
/// A protocol that allows us to check identity and equality between sections of `Diffable` items
/// for the purposes of diffing.
public protocol DiffableSection: Diffable {
/// The diffable items in this section.
associatedtype DiffableItems: Collection where
DiffableItems.Index == Int,
DiffableItems.Element: Diffable
/// The diffable items in this section.
var diffableItems: DiffableItems { get }
}
Conforming to these protocol allows you to easily create changesets between two sets of Diffables
or two sets of DiffableSections
:
extension String: Diffable {
func isDiffableItemEqual(to otherDiffableItem: Diffable) -> Bool {
guard let otherString = otherDiffableItem as? String else { return false }
return self == otherString
}
var diffIdentifier: AnyHashable { self }
}
let set1 = ["a", "b", "c", "d"]
let set2 = ["c", "d", "e", "a"]
let changeset = set1.makeChangeset(from: set2)
The result of the makeChangeset(from:)
call will be an IndexChangeset
populated with the minimal set of inserts, deletes, updates, and moves that are needed to go from set1
to set2
DiffableSection
is very similar where each DiffableSection
contains a set of Diffable
items internally. As an example, we could use the String
extension above and introduce a StringSection
to get changesets between sections of Strings
struct StringSection: DiffableSection: Equatable {
let diffIdentifier: String
let diffableItems: [String]
func isDiffableItemEqual(to otherDiffableItem: Diffable) -> Bool {
guard let otherSection = otherDiffableItem as? StringSection else { return false }
return self == otherSection
}
}
let section1 = StringSection(
diffIdentifier: 1,
diffableItems: ["a", "b", "c", "d"])
let section2 = StringSection(
diffIdentifier: 2,
diffableItems: ["c", "d", "e", "a"])
let section3 = StringSection(
diffIdentifier: 1,
diffableItems: ["d", "e", "f"])
let changeset = [section1, section2].makeSectionedChangeset(from: [section3])
The resulting changeset
above will be populated with the necessary changes to go from the set of sections in the first array to the set of sections in the second array. It will include information about the sections that have been moved, inserted, or deleted as well as the items that have been moved, inserted, or deleted using IndexPaths
to give information on the item's location in the section.
EpoxyLogger
provides a way to intercept assertions, assertionFailures, and warnings that occur within Epoxy. In order to use it, you just need to set the global EpoxyLogger.shared
to your own instance of EpoxyLogger
. As an example, you could do this in your AppDelegate
to intercept assertions and log them to a server:
import Epoxy
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
-> Bool
{
...
EpoxyLogger.shared = EpoxyLogger(
assert: { condition, message, fileID, line in
// custom logging of assertions here
},
assertionFailure: { message, fileID, line in
// custom logging of assertion failures here
},
warn: { message, fileID, line in
// custom handling of warnings here
})
return true
}
}
- Overview
ItemModel
andItemModeling
- Using
EpoxyableView
CollectionViewController
CollectionView
- Handling selection
- Setting view delegates and closures
- Highlight and selection states
- Responding to view appear / disappear events
- Using
UICollectionViewFlowLayout
- Overview
GroupItem
andGroupItemModeling
- Composing groups
- Spacing
StaticGroupItem
GroupItem
withoutEpoxyableView
- Creating components inline
- Alignment
- Accessibility layouts
- Constrainable and ConstrainableContainer
- Accessing properties of underlying Constrainables