diff --git a/Source/ASTextNode.mm b/Source/ASTextNode.mm index 5d51adbff..f71363d68 100644 --- a/Source/ASTextNode.mm +++ b/Source/ASTextNode.mm @@ -1346,36 +1346,29 @@ + (void)_registerAttributedText:(NSAttributedString *)str } #endif -+ (id)allocWithZone:(struct _NSZone *)zone +// All direct descendants of ASTextNode get their superclass replaced by ASTextNode2. ++ (void)initialize { - // If they're not experimenting, just forward. - if (!ASActivateExperimentalFeature(ASExperimentalTextNode)) { - return [super allocWithZone:zone]; - } - - // We are plain ASTextNode. Just swap in an ASTextNode2 instead. - if (self == [ASTextNode class]) { - return (ASTextNode *)[ASTextNode2 allocWithZone:zone]; - } - - // We are descended from ASTextNode. We need to change the superclass for the - // ASTextNode subclass to ASTextNode2. - // Walk up the class hierarchy until we find ASTextNode. - // Note: This may be called on multiple threads simultaneously. - Class s; - for (Class c = self; c != Nil && c != [ASTextNode class]; c = s) { - s = class_getSuperclass(c); - if (s == [ASTextNode class]) { + // Texture requires that node subclasses call [super initialize] + [super initialize]; + + if (class_getSuperclass(self) == [ASTextNode class] + && ASActivateExperimentalFeature(ASExperimentalTextNode)) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - // Direct descendent. Update superclass of c and end. - class_setSuperclass(c, [ASTextNode2 class]); + class_setSuperclass(self, [ASTextNode2 class]); #pragma clang diagnostic pop - break; - } } +} - return [super allocWithZone:zone]; +// For direct allocations of ASTextNode itself, we override allocWithZone: ++ (id)allocWithZone:(struct _NSZone *)zone +{ + if (ASActivateExperimentalFeature(ASExperimentalTextNode)) { + return (ASTextNode *)[ASTextNode2 allocWithZone:zone]; + } else { + return [super allocWithZone:zone]; + } } @end diff --git a/Tests/ASDisplayLayerTests.m b/Tests/ASDisplayLayerTests.m index 5f20e928e..e462e0a4a 100644 --- a/Tests/ASDisplayLayerTests.m +++ b/Tests/ASDisplayLayerTests.m @@ -217,7 +217,7 @@ + (BOOL)respondsToSelector:(SEL)selector } // DANGER: Don't use the delegate as the parameters in real code; this is not thread-safe and just for accounting in unit tests! -+ (UIImage *)displayWithParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(asdisplaynode_iscancelled_block_t)sentinelBlock ++ (UIImage *)displayWithParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)sentinelBlock { UIImage *contents = bogusImage(); if (delegate->_displayLayerBlock != NULL) { @@ -228,7 +228,7 @@ + (UIImage *)displayWithParameters:(_ASDisplayLayerTestDelegate *)delegate isCan } // DANGER: Don't use the delegate as the parameters in real code; this is not thread-safe and just for accounting in unit tests! -+ (void)drawRect:(CGRect)bounds withParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(asdisplaynode_iscancelled_block_t)sentinelBlock isRasterizing:(BOOL)isRasterizing ++ (void)drawRect:(CGRect)bounds withParameters:(_ASDisplayLayerTestDelegate *)delegate isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)sentinelBlock isRasterizing:(BOOL)isRasterizing { __atomic_add_fetch(&delegate->_drawRectCount, 1, __ATOMIC_SEQ_CST); }