diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm b/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm index 76e5145443b0a..a2ff91ff5c641 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm @@ -372,6 +372,7 @@ - (void)privateSetParent:(SemanticsObject*)parent; @implementation SemanticsObject { fml::scoped_nsobject _container; NSMutableArray* _children; + BOOL _inDealloc; } #pragma mark - Override base class designated initializers @@ -413,6 +414,7 @@ - (void)dealloc { _parent = nil; _container.get().semanticsObject = nil; [_platformViewSemanticsContainer release]; + _inDealloc = YES; [super dealloc]; } @@ -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; } diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm b/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm index 77e0edfc73e46..f6475beff2a1a 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObjectTest.mm @@ -644,6 +644,20 @@ - (void)testFlutterSwitchSemanticsObjectMatchesUISwitch { XCTAssertEqual(object.accessibilityValue, nativeSwitch.accessibilityValue); } +- (void)testSemanticsObjectDeallocated { + fml::WeakPtrFactory factory( + new flutter::MockAccessibilityBridge()); + fml::WeakPtr 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;