diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 800025c14a61d..39c23e8c0de54 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -83,6 +83,8 @@ source_set("flutter_framework_source_arc") { "framework/Source/FlutterPluginAppLifeCycleDelegate.mm", "framework/Source/FlutterRestorationPlugin.h", "framework/Source/FlutterRestorationPlugin.mm", + "framework/Source/FlutterSemanticsScrollView.h", + "framework/Source/FlutterSemanticsScrollView.mm", "framework/Source/FlutterSpellCheckPlugin.h", "framework/Source/FlutterSpellCheckPlugin.mm", "framework/Source/FlutterTextInputDelegate.h", @@ -100,6 +102,8 @@ source_set("flutter_framework_source_arc") { "framework/Source/FlutterViewResponder.h", "framework/Source/KeyCodeMap.g.mm", "framework/Source/KeyCodeMap_Internal.h", + "framework/Source/SemanticsObject.h", + "framework/Source/SemanticsObject.mm", "framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.h", "framework/Source/UIViewController+FlutterScreenAndSceneIfLoaded.mm", "framework/Source/connection_collection.h", @@ -173,12 +177,8 @@ source_set("flutter_framework_source") { "framework/Source/FlutterHeadlessDartRunner.mm", "framework/Source/FlutterPlatformPlugin.h", "framework/Source/FlutterPlatformPlugin.mm", - "framework/Source/FlutterSemanticsScrollView.h", - "framework/Source/FlutterSemanticsScrollView.mm", "framework/Source/FlutterViewController.mm", "framework/Source/FlutterViewController_Internal.h", - "framework/Source/SemanticsObject.h", - "framework/Source/SemanticsObject.mm", "framework/Source/accessibility_bridge.h", "framework/Source/accessibility_bridge.mm", "framework/Source/accessibility_text_entry.h", diff --git a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h index f83047f28b562..28b9b5636296b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN */ @interface FlutterSemanticsScrollView : UIScrollView -@property(nonatomic, assign, nullable) SemanticsObject* semanticsObject; +@property(nonatomic, weak, nullable) SemanticsObject* semanticsObject; - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm index 2a0083a22d1f3..9b74e2ddabc79 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.mm @@ -4,8 +4,11 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" #import "flutter/shell/platform/darwin/ios/framework/Source/SemanticsObject.h" +FLUTTER_ASSERT_ARC + @implementation FlutterSemanticsScrollView - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject { diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObject.h b/shell/platform/darwin/ios/framework/Source/SemanticsObject.h index 792113c501636..d3441ec0058b1 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObject.h +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObject.h @@ -38,7 +38,7 @@ constexpr float kScrollExtentMaxForInf = 1000; * The parent of this node in the node tree. Will be nil for the root node and * during transient state changes. */ -@property(nonatomic, assign, readonly) SemanticsObject* parent; +@property(nonatomic, weak, readonly) SemanticsObject* parent; /** * The accessibility bridge that this semantics object is attached to. This @@ -231,7 +231,7 @@ constexpr float kScrollExtentMaxForInf = 1000; bridge:(fml::WeakPtr)bridge NS_DESIGNATED_INITIALIZER; -@property(nonatomic, assign) SemanticsObject* semanticsObject; +@property(nonatomic, weak) SemanticsObject* semanticsObject; @end diff --git a/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm b/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm index ef97d929f05ba..2fe38516f4f5f 100644 --- a/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm +++ b/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm @@ -7,6 +7,8 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterSemanticsScrollView.h" +FLUTTER_ASSERT_ARC + namespace { flutter::SemanticsAction GetSemanticsActionForScrollDirection( @@ -107,11 +109,6 @@ - (instancetype)initWithBridge:(fml::WeakPtr)br return self; } -- (void)dealloc { - [_nativeSwitch release]; - [super dealloc]; -} - - (NSMethodSignature*)methodSignatureForSelector:(SEL)sel { NSMethodSignature* result = [super methodSignatureForSelector:sel]; if (!result) { @@ -145,7 +142,7 @@ - (UIAccessibilityTraits)accessibilityTraits { @end // FlutterSwitchSemanticsObject @interface FlutterScrollableSemanticsObject () -@property(nonatomic, retain) FlutterSemanticsScrollView* scrollView; +@property(nonatomic) FlutterSemanticsScrollView* scrollView; @end @implementation FlutterScrollableSemanticsObject @@ -164,9 +161,6 @@ - (instancetype)initWithBridge:(fml::WeakPtr)br - (void)dealloc { [_scrollView removeFromSuperview]; - _scrollView.semanticsObject = nil; - [_scrollView release]; - [super dealloc]; } - (void)accessibilityBridgeDidFinishUpdate { @@ -249,10 +243,10 @@ @implementation FlutterCustomAccessibilityAction { @end @interface SemanticsObject () -@property(nonatomic, retain) SemanticsObjectContainer* container; +@property(nonatomic) SemanticsObjectContainer* container; /** Should only be called in conjunction with setting child/parent relationship. */ -@property(nonatomic, assign, readwrite) SemanticsObject* parent; +@property(nonatomic, weak, readwrite) SemanticsObject* parent; @end @@ -261,15 +255,6 @@ @implementation SemanticsObject { BOOL _inDealloc; } -#pragma mark - Override base class designated initializers - -// Method declared as unavailable in the interface -- (instancetype)init { - [self release]; - [super doesNotRecognizeSelector:_cmd]; - return nil; -} - #pragma mark - Designated initializers - (instancetype)initWithBridge:(fml::WeakPtr)bridge @@ -293,17 +278,19 @@ - (instancetype)initWithBridge:(fml::WeakPtr)br } - (void)dealloc { + // Set parent and children parents to nil explicitly in dealloc. + // -[UIAccessibilityElement dealloc] has in the past called into -accessibilityContainer + // and self.children. There have also been crashes related to iOS + // accessing methods during dealloc, and there's a lag before the tree changes. + // See https://github.com/flutter/engine/pull/4602 and + // https://github.com/flutter/engine/pull/27786. for (SemanticsObject* child in _children) { child.parent = nil; } [_children removeAllObjects]; - [_children release]; - [_childrenInHitTestOrder release]; _parent = nil; - [_container release]; _inDealloc = YES; - [super dealloc]; } #pragma mark - Semantic object property accesser @@ -312,7 +299,6 @@ - (void)setChildren:(NSArray*)children { for (SemanticsObject* child in _children) { child.parent = nil; } - [_children release]; _children = [children mutableCopy]; for (SemanticsObject* child in _children) { child.parent = self; @@ -323,7 +309,6 @@ - (void)setChildrenInHitTestOrder:(NSArray*)childrenInHitTestO for (SemanticsObject* child in _childrenInHitTestOrder) { child.parent = nil; } - [_childrenInHitTestOrder release]; _childrenInHitTestOrder = [childrenInHitTestOrder copy]; for (SemanticsObject* child in _childrenInHitTestOrder) { child.parent = self; @@ -416,7 +401,7 @@ - (NSAttributedString*)createAttributedStringFromString:(NSString*)string withAttributes: (const flutter::StringAttributes&)attributes { NSMutableAttributedString* attributedString = - [[[NSMutableAttributedString alloc] initWithString:string] autorelease]; + [[NSMutableAttributedString alloc] initWithString:string]; for (const auto& attribute : attributes) { NSRange range = NSMakeRange(attribute->start, attribute->end - attribute->start); switch (attribute->type) { @@ -686,9 +671,8 @@ - (id)accessibilityContainer { if ([self hasChildren] || self.uid == kRootNodeId) { if (self.container == nil) { - self.container = - [[[SemanticsObjectContainer alloc] initWithSemanticsObject:self - bridge:self.bridge] autorelease]; + self.container = [[SemanticsObjectContainer alloc] initWithSemanticsObject:self + bridge:self.bridge]; } return self.container; } @@ -787,17 +771,7 @@ - (void)accessibilityElementDidLoseFocus { @end -@implementation FlutterSemanticsObject { -} - -#pragma mark - Override base class designated initializers - -// Method declared as unavailable in the interface -- (instancetype)init { - [self release]; - [super doesNotRecognizeSelector:_cmd]; - return nil; -} +@implementation FlutterSemanticsObject #pragma mark - Designated initializers @@ -853,7 +827,7 @@ - (UIAccessibilityTraits)accessibilityTraits { @end @interface FlutterPlatformViewSemanticsContainer () -@property(nonatomic, assign) UIView* platformView; +@property(nonatomic, weak) UIView* platformView; @end @implementation FlutterPlatformViewSemanticsContainer @@ -868,11 +842,6 @@ - (instancetype)initWithBridge:(fml::WeakPtr)br return self; } -- (void)dealloc { - _platformView = nil; - [super dealloc]; -} - - (id)nativeAccessibility { return self.platformView; } @@ -885,13 +854,6 @@ @implementation SemanticsObjectContainer { #pragma mark - initializers -// Method declared as unavailable in the interface -- (instancetype)init { - [self release]; - [super doesNotRecognizeSelector:_cmd]; - return nil; -} - - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject bridge:(fml::WeakPtr)bridge { FML_DCHECK(semanticsObject) << "semanticsObject must be set";