YapDatabase icon indicating copy to clipboard operation
YapDatabase copied to clipboard

Calling -[YapDatabaseViewMapping updateWithTransaction:] before calling -[YapDatabaseReadTransaction ext:] results in YapDatabaseViewTransactions never being created

Open coreyfloyd opened this issue 9 years ago • 0 comments

Is this expected behavior:

NSString* viewName = [[self class] viewName];

YapDatabaseViewGrouping* grouping = [YapDatabaseViewGrouping withObjectBlock:^NSString* _Nullable (YapDatabaseReadTransaction* _Nonnull transaction, NSString* _Nonnull collection, NSString* _Nonnull key, MWKHistoryEntry* _Nonnull object) {
        if (![collection isEqualToString:[MWKHistoryEntry databaseCollectionName]]) {
            return nil;
        }
        if (object.dateViewed == nil) {
            return nil;
        }

        NSDate* date = [[object dateViewed] dateAtStartOfDay];
        return [NSString stringWithFormat:@"%f", [date timeIntervalSince1970]];
    }];


YapDatabaseViewSorting* sorting = [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult (YapDatabaseReadTransaction* _Nonnull transaction, NSString* _Nonnull group, NSString* _Nonnull collection1, NSString* _Nonnull key1, MWKHistoryEntry* _Nonnull object1, NSString* _Nonnull collection2, NSString* _Nonnull key2, MWKHistoryEntry* _Nonnull object2) {
        return -[object1.dateViewed compare:object2.dateViewed];
    }];
    YapDatabaseView* databaseView = [[YapDatabaseView alloc] initWithGrouping:grouping sorting:sorting];

 [self.database registerView:databaseView withName:viewName];

 YapDatabaseViewMappings* mappings = [[YapDatabaseViewMappings alloc] initWithGroupFilterBlock:^BOOL (NSString* _Nonnull group, YapDatabaseReadTransaction* _Nonnull transaction) {
        return YES;
    } sortBlock:^NSComparisonResult (NSString* _Nonnull group1, NSString* _Nonnull group2, YapDatabaseReadTransaction* _Nonnull transaction) {
        if ([group1 doubleValue] < [group2 doubleValue]) {
            return NSOrderedDescending;
        } else if ([group1 doubleValue] > [group2 doubleValue]) {
            return NSOrderedAscending;
        } else {
            return NSOrderedSame;
        }
    } view:viewName];

[self.readConnection readWithBlock:^(YapDatabaseReadTransaction* _Nonnull transaction) {

        //This line is required to be called before calling  [self.groupSortMappings updateWithTransaction:transaction] for the read block below to work
        //IOW, If I comment out this line, the assertion below will fail.
        YapDatabaseViewTransaction* view = [transaction ext:viewName];

        [self.groupSortMappings updateWithTransaction:transaction];
 }];


[self.readConnection readWithBlock:^(YapDatabaseReadTransaction* _Nonnull transaction) {
        YapDatabaseViewTransaction* view = [transaction ext:viewName];

        //This will fail if I comment out YapDatabaseViewTransaction* view = [transaction ext:viewName]; in the read block above
        //From here on the connection will never be able to create a YapDatabaseViewTransaction for the viewName
        NSParameterAssert(view);
 }];


I traced the problem to the extension: method of YapDatabaseConnection. If I call updateWithTransaction: on the mappings before calling ext: the connection, extensionsReady will be YES which causes the connection to never check registeredExtensions. Thus always returning nil for the YapDatabaseViewTransaction:

- (id)extension:(NSString *)extName
{
    // This method is PUBLIC.
    //
    // This method returns a subclass of YapDatabaseExtensionConnection.
    // To get:
    // - YapDatabaseExtension            => [database registeredExtension:@"registeredNameOfExtension"]
    // - YapDatabaseExtensionConnection  => [databaseConnection extension:@"registeredNameOfExtension"]
    // - YapDatabaseExtensionTransaction => [databaseTransaction extension:@"registeredNameOfExtension"]

    __block id extConnection = nil;

    dispatch_block_t block = ^{

        extConnection = [extensions objectForKey:extName];

        if (!extConnection && !extensionsReady)
        {
            // We don't have an existing connection for the extension.
            // Create one (if we can).

            YapDatabaseExtension *ext = [registeredExtensions objectForKey:extName];
            if (ext)
            {
                extConnection = [ext newConnection:self];
                [extensions setObject:extConnection forKey:extName];
            }
        }
    };

    if (dispatch_get_specific(IsOnConnectionQueueKey))
        block();
    else
        dispatch_sync(connectionQueue, block);

    return extConnection;
}

Basically this puts the connection in an inconsistent state where it thinks extensions are ready, but they are not. Any thoughts here? Am I just using the API wrong?

coreyfloyd avatar Aug 05 '16 17:08 coreyfloyd