diff --git a/Source/TextKit/ASTextKitComponents.h b/Source/TextKit/ASTextKitComponents.h index 9fe5201c8..223abf5c1 100644 --- a/Source/TextKit/ASTextKitComponents.h +++ b/Source/TextKit/ASTextKitComponents.h @@ -59,7 +59,7 @@ AS_SUBCLASSING_RESTRICTED @property (nonatomic, strong, readonly) NSTextStorage *textStorage; @property (nonatomic, strong, readonly) NSTextContainer *textContainer; @property (nonatomic, strong, readonly) NSLayoutManager *layoutManager; -@property (nullable, nonatomic, strong) UITextView *textView; +@property (nonatomic, strong, nullable) UITextView *textView; @end diff --git a/Source/TextKit/ASTextKitComponents.mm b/Source/TextKit/ASTextKitComponents.mm index b733a4f4e..6b3955eb7 100644 --- a/Source/TextKit/ASTextKitComponents.mm +++ b/Source/TextKit/ASTextKitComponents.mm @@ -27,6 +27,9 @@ @interface ASTextKitComponents () @property (nonatomic, strong, readwrite) NSTextContainer *textContainer; @property (nonatomic, strong, readwrite) NSLayoutManager *layoutManager; +// Indicates whether or not this object must be deallocated on main thread. Defaults to YES. +@property (nonatomic, assign) BOOL requiresMainThreadDeallocation; + @end @implementation ASTextKitComponents @@ -58,6 +61,8 @@ + (instancetype)componentsWithTextStorage:(NSTextStorage *)textStorage components.textContainer.lineFragmentPadding = 0.0; // We want the text laid out up to the very edges of the text-view. [components.layoutManager addTextContainer:components.textContainer]; + components.requiresMainThreadDeallocation = YES; + return components; } @@ -65,10 +70,13 @@ + (instancetype)componentsWithTextStorage:(NSTextStorage *)textStorage - (void)dealloc { - ASDisplayNodeAssertMainThread(); - - // Nil out all delegate to prevent crash - _textView.delegate = nil; + if (_requiresMainThreadDeallocation) { + ASDisplayNodeAssertMainThread(); + } + // Nil out all delegates to prevent crash + if (_textView) { + _textView.delegate = nil; + } _layoutManager.delegate = nil; } @@ -82,6 +90,8 @@ - (CGSize)sizeForConstrainedWidth:(CGFloat)constrainedWidth // Otherwise, we create a temporary stack to size for `constrainedWidth`. if (CGRectGetWidth(components.textView.bounds) != constrainedWidth) { components = [ASTextKitComponents componentsWithAttributedSeedString:components.textStorage textContainerSize:CGSizeMake(constrainedWidth, CGFLOAT_MAX)]; + // The temporary stack can be deallocated off main + components.requiresMainThreadDeallocation = NO; } // Force glyph generation and layout, which may not have happened yet (and isn't triggered by -usedRectForTextContainer:). @@ -102,6 +112,8 @@ - (CGSize)sizeForConstrainedWidth:(CGFloat)constrainedWidth // Always use temporary stack in case of threading issues components = [ASTextKitComponents componentsWithAttributedSeedString:components.textStorage textContainerSize:CGSizeMake(constrainedWidth, CGFLOAT_MAX)]; + // The temporary stack can be deallocated off main + components.requiresMainThreadDeallocation = NO; // Force glyph generation and layout, which may not have happened yet (and isn't triggered by - usedRectForTextContainer:). [components.layoutManager ensureLayoutForTextContainer:components.textContainer];