Skip to content

Commit

Permalink
Adding ability to use YapDatabaseActionManager with a custom block, a…
Browse files Browse the repository at this point in the history
…s opposed to requiring database objects to implment YapActionable protocol.
  • Loading branch information
robbiehanson committed Jan 22, 2019
1 parent 41aface commit 943e05d
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

#import "YapCache.h"

@interface YapDatabaseActionManager () {
@public

YapActionScheduler scheduler;
}
@end

@interface YapDatabaseActionManagerConnection () {
@public

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

NS_ASSUME_NONNULL_BEGIN

typedef NSArray<YapActionItem*> *_Nullable (^YapActionScheduler)(NSString *collection, NSString *key, id object);

/**
* This extension automatically monitors the database for objects that support the YapActionable protocol.
*
Expand All @@ -34,10 +36,16 @@ NS_ASSUME_NONNULL_BEGIN
@interface YapDatabaseActionManager : YapDatabaseAutoView

- (instancetype)init;

- (instancetype)initWithConnection:(nullable YapDatabaseConnection *)connection;

- (instancetype)initWithConnection:(nullable YapDatabaseConnection *)connection
options:(nullable YapDatabaseViewOptions *)options;

- (instancetype)initWithConnection:(nullable YapDatabaseConnection *)connection
options:(nullable YapDatabaseViewOptions *)options
scheduler:(nullable YapActionScheduler)scheduler;

#if !TARGET_OS_WATCH
/**
* YapDatabaseActionManager relies on a reachability instance to monitory for internet connectivity.
Expand Down
62 changes: 45 additions & 17 deletions YapDatabase/Extensions/ActionManager/YapDatabaseActionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,22 @@ - (instancetype)initWithGrouping:(YapDatabaseViewGrouping __unused *)inGrouping

- (instancetype)init
{
return [self initWithConnection:nil options:nil];
return [self initWithConnection:nil options:nil scheduler:nil];
}

- (instancetype)initWithConnection:(YapDatabaseConnection *)inConnection
{
return [self initWithConnection:inConnection options:nil];
return [self initWithConnection:inConnection options:nil scheduler:nil];
}

- (instancetype)initWithConnection:(YapDatabaseConnection *)inConnection options:(YapDatabaseViewOptions *)inOptions
{
return [self initWithConnection:inConnection options:inOptions scheduler:nil];
}

- (instancetype)initWithConnection:(nullable YapDatabaseConnection *)inConnection
options:(nullable YapDatabaseViewOptions *)inOptions
scheduler:(nullable YapActionScheduler)inScheduler
{
// Create and configure view

Expand All @@ -115,6 +122,8 @@ - (instancetype)initWithConnection:(YapDatabaseConnection *)inConnection options
self.weakDbConnection = inConnection;
useWeakDbConnection = (inConnection != nil);

scheduler = inScheduler;

actionItemsDict = [[NSMutableDictionary alloc] init];

suspendCount = 0;
Expand All @@ -125,12 +134,14 @@ - (instancetype)initWithConnection:(YapDatabaseConnection *)inConnection options

- (void)dealloc
{
// libdispatch isn't happy about releasing suspended dispatch sources.
// See _dispatch_source_xref_release at https://opensource.apple.com/source/libdispatch/libdispatch-187.7/src/source.c
if(timer && timerSuspended) {
dispatch_resume(timer);
timerSuspended = NO;
}
// libdispatch isn't happy about releasing suspended dispatch sources.
// See _dispatch_source_xref_release at:
// https://opensource.apple.com/source/libdispatch/libdispatch-187.7/src/source.c
//
if (timer && timerSuspended) {
dispatch_resume(timer);
timerSuspended = NO;
}

[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Expand Down Expand Up @@ -164,16 +175,33 @@ - (BOOL)supportsDatabaseWithRegisteredExtensions:(NSDictionary<NSString*, YapDat

__block BOOL supported = YES;

[registeredExtensions enumerateKeysAndObjectsUsingBlock:^(id __unused key, id obj, BOOL *stop) {
if (scheduler)
{
// This ActionManager instance is configured with an explicit scheduler.
// Since the scheduler handles all the logic, there can be multiple such ActionManager instances.
}
else
{
// The ActionManager instance is configured to react to objects that
// implement the YapActionItem protocol. So there can only be one such
// configured ActionManager instance at a time. Otherwise EVERY registered
// ActionManager would react to the YapActionItem.

if ([obj isKindOfClass:[YapDatabaseActionManager class]])
{
YDBLogWarn(@"Only 1 YapDatabaseActionManager instance is supported at a time");

supported = NO;
*stop = YES;
}
}];
[registeredExtensions enumerateKeysAndObjectsUsingBlock:^(id __unused key, id obj, BOOL *stop) {

if ([obj isKindOfClass:[YapDatabaseActionManager class]])
{
YapDatabaseActionManager *ext = (YapDatabaseActionManager *)obj;
if (ext->scheduler == nil)
{
YDBLogWarn(@"Only 1 YapDatabaseActionManager instance (sans scheduler) is supported at a time");

supported = NO;
*stop = YES;
}
}
}];
}

if (!supported) return NO;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ @implementation YapDatabaseActionManagerTransaction

- (NSArray *)actionItemsForCollectionKey:(YapCollectionKey *)ck
{
__unsafe_unretained YapDatabaseActionManagerConnection *amConnection =
(YapDatabaseActionManagerConnection *)parentConnection;
__unsafe_unretained YapDatabaseActionManagerConnection *_connection =
(YapDatabaseActionManagerConnection *)parentConnection;

__unsafe_unretained YapDatabaseActionManager *_parent =
(YapDatabaseActionManager *)_connection->parent;

id cached = [amConnection->actionItemsCache objectForKey:ck];
id cached = [_connection->actionItemsCache objectForKey:ck];
if (cached)
{
if (cached == [NSNull null])
Expand All @@ -37,15 +40,19 @@ - (NSArray *)actionItemsForCollectionKey:(YapCollectionKey *)ck
id object = [databaseTransaction objectForKey:ck.key inCollection:ck.collection];

NSArray<YapActionItem*> *actionItems = nil;
if ([object conformsToProtocol:@protocol(YapActionable)])
if (_parent->scheduler)
{
actionItems = _parent->scheduler(ck.collection, ck.key, object);
}
else if ([object conformsToProtocol:@protocol(YapActionable)])
{
actionItems = [[(id <YapActionable>)object yapActionItems] sortedArrayUsingSelector:@selector(compare:)];
}

if (actionItems)
[amConnection->actionItemsCache setObject:actionItems forKey:ck];
[_connection->actionItemsCache setObject:actionItems forKey:ck];
else
[amConnection->actionItemsCache setObject:[NSNull null] forKey:ck];
[_connection->actionItemsCache setObject:[NSNull null] forKey:ck];

return actionItems;
}
Expand Down

0 comments on commit 943e05d

Please sign in to comment.