Started clearing out the parent of orphaned semantic objects. (#17499)
diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h
index d6e0bb6..772c84e 100644
--- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h
+++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h
@@ -43,7 +43,7 @@
* 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 @@
* Direct children of this semantics object. Each child's `parent` property must
* be equal to this object.
*/
-@property(nonatomic, strong) NSMutableArray<SemanticsObject*>* children;
+@property(nonatomic, strong) NSArray<SemanticsObject*>* 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/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm
index 53f097e..46224c1 100644
--- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm
+++ b/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 @@
@end
+@interface SemanticsObject ()
+/** Should only be called in conjunction with setting child/parent relationship. */
+- (void)privateSetParent:(SemanticsObject*)parent;
+@end
+
@implementation SemanticsObject {
fml::scoped_nsobject<SemanticsObjectContainer> _container;
+ NSMutableArray<SemanticsObject*>* _children;
}
#pragma mark - Override base class designated initializers
@@ -197,7 +205,7 @@
- (void)dealloc {
for (SemanticsObject* child in _children) {
- child.parent = nil;
+ [child privateSetParent:nil];
}
[_children removeAllObjects];
[_children release];
@@ -239,6 +247,28 @@
return [self.children count] != 0;
}
+- (void)privateSetParent:(SemanticsObject*)parent {
+ _parent = parent;
+}
+
+- (void)setChildren:(NSArray<SemanticsObject*>*)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 @@
return ((FlutterPlatformViewSemanticsContainer*)element).index;
}
- NSMutableArray<SemanticsObject*>* children = [_semanticsObject children];
+ NSArray<SemanticsObject*>* 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 @@
[[[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 @@
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;
}