[ASDisplayNode] Add support for setting non-fatal error block (#2993)

* Add support for setting non-fatal error block

* Better documentation and fix typos

* Added ASDisplayNodeAssertNonFatal macro that asserts in dev and call block in prod

* Make non fatal error code equals to 1

* Add support for condition in ASDisplayNodeAssertNonFatal

* Only call non fatal block if condition isn’t satisfied
This commit is contained in:
Rocir Santiago 2017-02-07 17:13:33 -08:00 committed by Garrett Moon
parent f21254593d
commit b33cced1eb
3 changed files with 48 additions and 0 deletions

View File

@ -56,6 +56,12 @@ typedef void (^ASDisplayNodeContextModifier)(CGContextRef context);
*/
typedef ASLayoutSpec * _Nonnull(^ASLayoutSpecBlock)(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize);
/**
* AsyncDisplayKit non-fatal error block. This block can be used for handling non-fatal errors. Useful for reporting
* errors that happens in production.
*/
typedef void (^ASDisplayNodeNonFatalErrorBlock)(__kindof NSError * _Nonnull error);
/**
* Interface state is available on ASDisplayNode and ASViewController, and
* allows checking whether a node is in an interface situation where it is prudent to trigger certain
@ -253,6 +259,16 @@ extern NSInteger const ASDefaultDrawingPriority;
*/
@property (readonly) ASInterfaceState interfaceState;
/**
* @abstract Class property that allows to set a block that can be called on non-fatal errors. This
* property can be useful for cases when Async Display Kit can recover from an abnormal behavior, but
* still gives the opportunity to use a reporting mechanism to catch occurrences in production. In
* development, Async Display Kit will assert instead of calling this block.
*
* @warning This method is not thread-safe.
*/
@property (nonatomic, class, copy) ASDisplayNodeNonFatalErrorBlock nonFatalErrorBlock;
/** @name Managing dimensions */

View File

@ -63,6 +63,8 @@
#define TIME_SCOPED(outVar)
#endif
static ASDisplayNodeNonFatalErrorBlock _nonFatalErrorBlock = nil;
// Forward declare CALayerDelegate protocol as the iOS 10 SDK moves CALayerDelegate from a formal delegate to a protocol.
// We have to forward declare the protocol as this place otherwise it will not compile compiling with an Base SDK < iOS 10
@protocol CALayerDelegate;
@ -2250,6 +2252,20 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
return (id)kCFNull;
}
#pragma mark - Error Handling
+ (void)setNonFatalErrorBlock:(ASDisplayNodeNonFatalErrorBlock)nonFatalErrorBlock
{
if (_nonFatalErrorBlock != nonFatalErrorBlock) {
_nonFatalErrorBlock = [nonFatalErrorBlock copy];
}
}
+ (ASDisplayNodeNonFatalErrorBlock)nonFatalErrorBlock
{
return _nonFatalErrorBlock;
}
#pragma mark - Converting to and from the Node's Coordinate System
- (CATransform3D)_transformToAncestor:(ASDisplayNode *)ancestor

View File

@ -59,3 +59,19 @@
#define ASDisplayNodeCAssertPositiveReal(description, num) ASDisplayNodeCAssert(num >= 0 && num <= CGFLOAT_MAX, @"%@ must be a real positive integer.", description)
#define ASDisplayNodeCAssertInfOrPositiveReal(description, num) ASDisplayNodeCAssert(isinf(num) || (num >= 0 && num <= CGFLOAT_MAX), @"%@ must be infinite or a real positive integer.", description)
#define ASDisplayNodeErrorDomain @"ASDisplayNodeErrorDomain"
#define ASDisplayNodeNonFatalErrorCode 1
#define ASDisplayNodeAssertNonFatal(condition, desc, ...) \
ASDisplayNodeAssert(condition, desc, ##__VA_ARGS__); \
if (condition == NO) { \
ASDisplayNodeNonFatalErrorBlock block = [ASDisplayNode nonFatalErrorBlock]; \
if (block != nil) { \
NSDictionary *userInfo = nil; \
if (desc.length > 0) { \
userInfo = @{ NSLocalizedDescriptionKey : desc }; \
} \
NSError *error = [NSError errorWithDomain:ASDisplayNodeErrorDomain code:ASDisplayNodeNonFatalErrorCode userInfo:userInfo]; \
block(error); \
} \
}