YapDatabaseViewRowChange

@interface YapDatabaseViewRowChange : NSObject <NSCopying>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  • The type will be one of:

  • YapDatabaseViewChangeInsert
  • YapDatabaseViewChangeDelete
  • YapDatabaseViewChangeMove
  • YapDatabaseViewChangeUpdate

  • See

    YapDatabaseViewChangeType

    Declaration

    Objective-C

    @property (readonly, nonatomic) YapDatabaseViewChangeType type;

    Swift

    var type: YapDatabaseViewChangeType { get }
  • The changes property is a bitmask representing what changed for the corresponding row in the database.

    There are 3 types represented in the bit mask:

    • YapDatabaseViewChangedObject
    • YapDatabaseViewChangedMetadata
    • YapDatabaseViewChangedDependency

    YapDatabaseViewChangedObject means the object was changed via setObject:forKey:inCollection:.

    YapDatabaseViewChangedMetadata means the metadata was changed. This might have happend implicitly if the user invoked setObject:forKey:inCollection: (implicitly setting the metadata to nil). Or explicitly if the user invoked setObject:forKey:inCollection:withMetadata: or replaceMetadata:forKey:inCollection:.

    YapDatabaseViewChangedDependency means the row was flagged due to a cell drawing dependency configuration. See YapDatabaseViewMappings: setCellDrawingDependencyForNeighboringCellWithOffset:forGroup:

    Keep in mind that this is a bitmask. So, for example, all bits might be set if a row was updated, and was also flagged due to an inter-cell drawing dependency.

    This may be useful for various optimizations. For example: The drawing of your cell depends only on the object. However, your objects are rather large, and you’re using metadata to store small subsets of the object that often need to be fetched. In addition, you’re keeping other information in metadata such as refresh dates for pulling updates from the server. The grouping and sorting block are optimized and use only the metadata. However this means that the metadata may change (due to a refresh date update), when in fact the object itself didn’t change. So you could optimize a bit here by skipping some cell updates.

    if (change.type == YapDatabaseViewChangeUpdate) { if (change.modifiedColumns & YapDatabaseViewChangedObject) { // object changed, update cell } else { // only the metadata changed, so we can skip updating the cell } }

    See

    YapDatabaseViewChangesBitMask

    Declaration

    Objective-C

    @property (readonly, nonatomic) YapDatabaseViewChangesBitMask changes;

    Swift

    var changes: YapDatabaseViewChangesBitMask { get }
  • The indexPath & newIndexPath are available after you’ve invoked getSectionChanges:rowChanges:forNotifications:withMappings:.

    See

    YapDatabaseConnection getSectionChanges:rowChanges:forNotifications:withMappings:

    These properties are designed to help facilitate animations to tableViews and collectionsViews.

    Recall that a view has no concept of sections. That is, a view has groups not sections. A group is a string, and a section is just a number.

    Using groups allows a view to be more dynamic. Your view may contain dozens of groups, but a particular tableView within your app may only display a subset of the groups.

    For example, you may have a view for displaying products in a grocery store. Each product is grouped by department (e.g. produce, deli, bakery), and sorted sorted by name. Using this view you can easily bring up a table view which displays only a few departments such as: liquor, wine, beer.

    In this example:

    • Section 0 = liquor
    • Section 1 = wine
    • Section 2 = beer

    NSArray *groups = @{ @liquor:@(0), @wine:@(1), @beer:@(2) }; YapDatabaseMappings *mappings = [YapDatabaseViewMappings mappingsWithGroups:groups view:@order];

    The mappings are then used to map between the ‘groups in the view’ and ‘items in the table’.

    Mappings can provide a lot of additional functionality as well. For example, you can configure the mappings to only display a particular range within a group. This is similar to a LIMIT & OFFSET in SQL. This is the tip of the iceberg. See YapDatabaseViewMappings.h for more info.

    In order to animate changes to your tableView or collectionView, you eventually do something like this:

    NSArray *sectionChanges = nil; NSArray *rowChanges = nil; [databaseConnection getSectionChanges:&sectionChanges rowChanges:&rowChanges forNotifications:notifications withMappings:mappings];

    This gives you a list of changes as they affect your tableView / collectionView.

    The indexPath and newIndexPath properties are modeled after: NSFetchedResultsControllerDelegate controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:

    • indexPath represents the ORIGINAL indexPath for the row. It is non-nil for the following types : Delete, Move, Update. (And nil for insert since there was no original indexPath.)

    • newIndexPath represents the FINAL indexPath for the row. It is non-nil for the following types : Insert, Move. (And nil for delete since there is no final indexPath.) (And nil for update since that’s how NSFetchedResultsController works, and thus how existing code might expect it to work.)

    Once you have the sectionChanges & rowChanges, you can animate your tableView very simply like so:

    PS - For a FULL CODE EXAMPLE, see the wiki: https://github.com/yapstudios/YapDatabase/wiki/Views#wiki-animating_updates_in_tableviews_collectionviews

    if ([sectionChanges count] == 0 & [rowChanges count] == 0) { // Nothing has changed that affects our tableView return; }

    // Familiar with NSFetchedResultsController? // Then this should look pretty familiar

    [self.tableView beginUpdates];

    for (YapDatabaseViewSectionChange *sectionChange in sectionChanges) { switch (sectionChange.type) { case YapDatabaseViewChangeDelete : { [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionChange.index] withRowAnimation:UITableViewRowAnimationAutomatic]; break; } case YapDatabaseViewChangeInsert : { [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionChange.index] withRowAnimation:UITableViewRowAnimationAutomatic]; break; } } }

    for (YapDatabaseViewRowChange *rowChange in rowChanges) { switch (rowChange.type) { case YapDatabaseViewChangeDelete : { [self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic]; break; } case YapDatabaseViewChangeInsert : { [self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ] withRowAnimation:UITableViewRowAnimationAutomatic]; break; } case YapDatabaseViewChangeMove : { [self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ] withRowAnimation:UITableViewRowAnimationAutomatic]; break; } case YapDatabaseViewChangeUpdate : { [self.tableView reloadRowsAtIndexPaths:@[ rowChange.indexPath ] withRowAnimation:UITableViewRowAnimationNone]; break; } } }

    [self.tableView endUpdates];

    Declaration

    Objective-C

    @property (readonly, nonatomic, nullable) NSIndexPath *indexPath;

    Swift

    var indexPath: IndexPath? { get }
  • Undocumented

    Declaration

    Objective-C

    @property (nonatomic, readonly, nullable) NSIndexPath *newIndexPath

    Swift

    var newIndexPath: IndexPath? { get }
  • The original values represent the location of the changed item at the BEGINNING of the read-write transaction(s).

    The final values represent the location of the changed item at the END of the read-write transaction(s).

    This information also available in another form via the indexPath & newIndexPath properties.

    Declaration

    Objective-C

    @property (readonly, nonatomic) NSUInteger originalIndex;

    Swift

    var originalIndex: UInt { get }
  • Undocumented

    Declaration

    Objective-C

    @property (nonatomic, readonly) NSUInteger finalIndex

    Swift

    var finalIndex: UInt { get }
  • Undocumented

    Declaration

    Objective-C

    @property (nonatomic, readonly) NSUInteger originalSection

    Swift

    var originalSection: UInt { get }
  • Undocumented

    Declaration

    Objective-C

    @property (nonatomic, readonly) NSUInteger finalSection

    Swift

    var finalSection: UInt { get }
  • Undocumented

    Declaration

    Objective-C

    @property (nonatomic, readonly) NSString *originalGroup

    Swift

    var originalGroup: String { get }
  • Undocumented

    Declaration

    Objective-C

    @property (nonatomic, readonly) NSString *finalGroup

    Swift

    var finalGroup: String { get }
  • Gives you the {collection,key} tuple that caused the row change.

    Please note that this information is not always available. In particular, it may not be available if:

    • the rowChange was due solely to a dependency (YapDatabaseViewChangedDependency)
    • the rowChange was due solely to satisfy a range constraint (YapDatabaseViewRangeOptions)
    • the rowChange was due to the database being cleared (removeAllObjectsInAllCollections)

    However, it will be available for the most important situation, which is when a particular item from the database has been removed. (YapDatabaseViewChangeDelete)

    In other situations (YapDatabaseViewChangeInsert, YapDatabaseViewChangeUpdate, YapDatabaseViewChangeMove) you’d be able to fetch the corresponding information directly from the View. For example:

    for (YapDatabaseViewRowChange *rowChange in rowChanges) { switch (rowChange.type) { // … case YapDatabaseViewChangeInsert : { // What changed exactly ? __block NSString *collection = nil; __block NSString *key = nil; [databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){ [[transaction ext:@view] getKey:&key collection:&collection atIndexPath:rowChange.newIndexPath withMappings:mappings]; // … } // …. } }

    However, you’ll notice that you wouldn’t be able to fetch the collection/key for a deleted item, because the rowChange.indexPath is no longer valid for the current state of the database/view.

    And thus that information is available via this property, should you ever need it.

    Declaration

    Objective-C

    @property (readonly, nonatomic) YapCollectionKey *_Nonnull collectionKey;

    Swift

    var collectionKey: YapCollectionKey { get }