ComponentKit/Core/CKOptimisticViewMutations.mm (91 lines of code) (raw):
/*
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#import "CKOptimisticViewMutations.h"
#import <RenderCore/RCAssert.h>
#import <ComponentKit/CKGlobalConfig.h>
#import <ComponentKit/ComponentUtilities.h>
#import <ComponentKit/ComponentViewManager.h>
void CKPerformOptimisticViewMutation(UIView *view,
CKOptimisticViewMutationGetter getter,
CKOptimisticViewMutationSetter setter,
id value,
id context)
{
CKPerformOptimisticViewMutation(view, 0, getter, setter, value, context);
}
void CKPerformOptimisticViewMutation(UIView *view,
CFTimeInterval persistTime,
CKOptimisticViewMutationGetter getter,
CKOptimisticViewMutationSetter setter,
id value,
id context)
{
RCCAssertMainThread();
RCCAssertNotNil(view, @"Must have a non-nil view");
RCCAssertNotNil(getter, @"Must have a non-nil getter");
RCCAssertNotNil(setter, @"Must have a non-nil setter");
if (view == nil || getter == nil || setter == nil) {
return;
}
if (CKReadGlobalConfig().useNewStyleOptimisticMutations) {
__block int loadCount = 0;
__block id oldValue = nil;
__block CKOptimisticMutationToken token = CKOptimisticMutationTokenNull;
auto undo = ^(UIView *v) {
if (!RCObjectIsEqual(getter(v, context), oldValue)) {
setter(v, oldValue, context);
RCCAssert(RCObjectIsEqual(getter(v, context), oldValue), @"Setter failed to undo to old value");
}
};
auto load = persistTime == 0 ?
^(UIView *v) {
if (loadCount++ == 0) {
oldValue = getter(view, context);
} else {
oldValue = getter(view, context);
CK::Component::AttributeApplicator::removeOptimisticViewMutation(token);
token = CKOptimisticMutationTokenNull;
}
} :
^(UIView *v) {
oldValue = getter(view, context);
};
auto apply = ^(UIView *v) {
if (!RCObjectIsEqual(getter(v, context), value)) {
setter(v, value, context);
RCCAssert(RCObjectIsEqual(getter(view, context), value), @"Setter failed to redo to new value");
}
};
if (persistTime != 0) {
const auto dispatchTime = dispatch_time(DISPATCH_TIME_NOW, int64_t(NSEC_PER_SEC * persistTime));
dispatch_after(dispatchTime, dispatch_get_main_queue(), ^{
CK::Component::AttributeApplicator::removeOptimisticViewMutation(token);
token = CKOptimisticMutationTokenNull;
});
}
token = CK::Component::AttributeApplicator::addOptimisticViewMutation(view, undo, apply, load);
} else {
id oldValue = getter(view, context);
CK::Component::AttributeApplicator::addOptimisticViewMutationTeardown_Old(view, ^(UIView *v) {
setter(v, oldValue, context);
RCCAssert(RCObjectIsEqual(getter(v, context), oldValue), @"Setter failed to restore old value");
});
setter(view, value, context);
RCCAssert(RCObjectIsEqual(getter(view, context), value), @"Setter failed to apply new value");
}
}
static id keyPathGetter(UIView *view, id keyPath)
{
return [view valueForKeyPath:keyPath];
}
static void keyPathSetter(UIView *view, id value, id keyPath)
{
[view setValue:value forKey:keyPath];
}
void CKPerformOptimisticViewMutation(UIView *view, NSString *keyPath, id value)
{
CKPerformOptimisticViewMutation(view, 0.0, keyPath, value);
}
void CKPerformOptimisticViewMutation(UIView *view, CFTimeInterval persistTime, NSString *keyPath, id value)
{
RCCAssertNotNil(keyPath, @"Must have a non-nil keyPath");
CKPerformOptimisticViewMutation(view, persistTime, &keyPathGetter, &keyPathSetter, value, keyPath);
}