diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h index d6e0bb6446e..772c84eb5ef 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h @@ -43,7 +43,7 @@ class AccessibilityBridge; * The parent of this node in the node tree. Will be nil for the root node and * during transient state changes. */ -@property(nonatomic, assign) SemanticsObject* parent; +@property(nonatomic, readonly) SemanticsObject* parent; /** * The accessibility bridge that this semantics object is attached to. This @@ -85,13 +85,15 @@ class AccessibilityBridge; * Direct children of this semantics object. Each child's `parent` property must * be equal to this object. */ -@property(nonatomic, strong) NSMutableArray* children; +@property(nonatomic, strong) NSArray* children; /** * Used if this SemanticsObject is for a platform view. */ @property(strong, nonatomic) FlutterPlatformViewSemanticsContainer* platformViewSemanticsContainer; +- (void)replaceChildAtIndex:(NSInteger)index withChild:(SemanticsObject*)child; + - (BOOL)nodeWillCauseLayoutChange:(const flutter::SemanticsNode*)node; #pragma mark - Designated initializers diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 53f097e65b0..46224c1ea4d 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -14,6 +14,8 @@ #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" #include "flutter/shell/platform/darwin/ios/platform_view_ios.h" +FLUTTER_ASSERT_NOT_ARC + namespace { constexpr int32_t kRootNodeId = 0; @@ -162,8 +164,14 @@ flutter::SemanticsAction GetSemanticsActionForScrollDirection( @end +@interface SemanticsObject () +/** Should only be called in conjunction with setting child/parent relationship. */ +- (void)privateSetParent:(SemanticsObject*)parent; +@end + @implementation SemanticsObject { fml::scoped_nsobject _container; + NSMutableArray* _children; } #pragma mark - Override base class designated initializers @@ -197,7 +205,7 @@ flutter::SemanticsAction GetSemanticsActionForScrollDirection( - (void)dealloc { for (SemanticsObject* child in _children) { - child.parent = nil; + [child privateSetParent:nil]; } [_children removeAllObjects]; [_children release]; @@ -239,6 +247,28 @@ flutter::SemanticsAction GetSemanticsActionForScrollDirection( return [self.children count] != 0; } +- (void)privateSetParent:(SemanticsObject*)parent { + _parent = parent; +} + +- (void)setChildren:(NSArray*)children { + for (SemanticsObject* child in _children) { + [child privateSetParent:nil]; + } + [_children release]; + _children = [[NSMutableArray alloc] initWithArray:children]; + for (SemanticsObject* child in _children) { + [child privateSetParent:self]; + } +} + +- (void)replaceChildAtIndex:(NSInteger)index withChild:(SemanticsObject*)child { + SemanticsObject* oldChild = _children[index]; + [oldChild privateSetParent:nil]; + [child privateSetParent:self]; + [_children replaceObjectAtIndex:index withObject:child]; +} + #pragma mark - UIAccessibility overrides - (BOOL)isAccessibilityElement { @@ -653,7 +683,7 @@ flutter::SemanticsAction GetSemanticsActionForScrollDirection( return ((FlutterPlatformViewSemanticsContainer*)element).index; } - NSMutableArray* children = [_semanticsObject children]; + NSArray* children = [_semanticsObject children]; for (size_t i = 0; i < [children count]; i++) { SemanticsObject* child = children[i]; if ((![child hasChildren] && child == element) || @@ -741,7 +771,6 @@ void AccessibilityBridge::UpdateSemantics(flutter::SemanticsNodeUpdates nodes, [[[NSMutableArray alloc] initWithCapacity:newChildCount] autorelease]; for (NSUInteger i = 0; i < newChildCount; ++i) { SemanticsObject* child = GetOrCreateObject(node.childrenInTraversalOrder[i], nodes); - child.parent = object; [newChildren addObject:child]; } object.children = newChildren; @@ -847,10 +876,8 @@ static void ReplaceSemanticsObject(SemanticsObject* oldObject, assert(oldObject.node.id == newObject.node.id); NSNumber* nodeId = @(oldObject.node.id); NSUInteger positionInChildlist = [oldObject.parent.children indexOfObject:oldObject]; - SemanticsObject* parent = oldObject.parent; [objects removeObjectForKey:nodeId]; - newObject.parent = parent; - [newObject.parent.children replaceObjectAtIndex:positionInChildlist withObject:newObject]; + [oldObject.parent replaceChildAtIndex:positionInChildlist withChild:newObject]; objects[nodeId] = newObject; }