Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
10 changes: 10 additions & 0 deletions shell/platform/darwin/ios/framework/Source/SemanticsObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ - (void)privateSetParent:(SemanticsObject*)parent;
@implementation SemanticsObject {
fml::scoped_nsobject<SemanticsObjectContainer> _container;
NSMutableArray<SemanticsObject*>* _children;
BOOL _inDealloc;
}

#pragma mark - Override base class designated initializers
Expand Down Expand Up @@ -413,6 +414,7 @@ - (void)dealloc {
_parent = nil;
_container.get().semanticsObject = nil;
[_platformViewSemanticsContainer release];
_inDealloc = YES;
[super dealloc];
}

Expand Down Expand Up @@ -686,6 +688,14 @@ - (void)setAccessibilityContainer:(id)container {
}

- (id)accessibilityContainer {
if (_inDealloc) {
// In iOS9, `accessibilityContainer` will be called by `[UIAccessibilityElementSuperCategory
// dealloc]` during `[super dealloc]`. And will crash when accessing `_children` which has
// called `[_children release]` in `[SemanticsObject dealloc]`.
// https://github.com/flutter/flutter/issues/87247
return nil;
}

if (![self isAccessibilityBridgeAlive]) {
return nil;
}
Expand Down
14 changes: 14 additions & 0 deletions shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,20 @@ - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch {
XCTAssertEqual(object.accessibilityValue, nativeSwitch.accessibilityValue);
}

- (void)testSemanticsObjectDeallocated {
fml::WeakPtrFactory<flutter::AccessibilityBridgeIos> factory(
new flutter::MockAccessibilityBridge());
fml::WeakPtr<flutter::AccessibilityBridgeIos> bridge = factory.GetWeakPtr();
SemanticsObject* parent = [[SemanticsObject alloc] initWithBridge:bridge uid:0];
SemanticsObject* child = [[SemanticsObject alloc] initWithBridge:bridge uid:1];
parent.children = @[ child ];
// Validate SemanticsObject deallocation does not crash.
// https://github.com/flutter/flutter/issues/66032
__weak SemanticsObject* weakObject = parent;
parent = nil;
XCTAssertNil(weakObject);
}

- (void)testFlutterSemanticsObjectReturnsNilContainerWhenBridgeIsNotAlive {
FlutterSemanticsObject* parentObject;
FlutterSemanticsObject* delegate;
Expand Down