Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f93c945

Browse files
zhongwuzwgaaclarke
andauthored
Fix iOS platform view not deallocated (#18164)
Co-authored-by: Aaron Clarke <[email protected]>
1 parent d0b69d0 commit f93c945

File tree

3 files changed

+127
-9
lines changed

3 files changed

+127
-9
lines changed

shell/platform/darwin/ios/framework/Source/SemanticsObject.mm

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -508,10 +508,12 @@ - (UIAccessibilityTraits)accessibilityTraits {
508508

509509
@end
510510

511-
@implementation FlutterPlatformViewSemanticsContainer {
512-
SemanticsObject* _semanticsObject;
513-
UIView* _platformView;
514-
}
511+
@interface FlutterPlatformViewSemanticsContainer ()
512+
@property(nonatomic, assign) SemanticsObject* semanticsObject;
513+
@property(nonatomic, strong) UIView* platformView;
514+
@end
515+
516+
@implementation FlutterPlatformViewSemanticsContainer
515517

516518
// Method declared as unavailable in the interface
517519
- (instancetype)init {
@@ -531,13 +533,22 @@ - (instancetype)initWithSemanticsObject:(SemanticsObject*)object {
531533
flutter::FlutterPlatformViewsController* controller =
532534
object.bridge->GetPlatformViewsController();
533535
if (controller) {
534-
_platformView = [controller->GetPlatformViewByID(object.node.platformViewId) view];
536+
_platformView = [[controller->GetPlatformViewByID(object.node.platformViewId) view] retain];
535537
}
536-
self.accessibilityElements = @[ _semanticsObject, _platformView ];
537538
}
538539
return self;
539540
}
540541

542+
- (void)dealloc {
543+
[_platformView release];
544+
_platformView = nil;
545+
[super dealloc];
546+
}
547+
548+
- (NSArray*)accessibilityElements {
549+
return @[ _semanticsObject, _platformView ];
550+
}
551+
541552
- (CGRect)accessibilityFrame {
542553
return _semanticsObject.accessibilityFrame;
543554
}

shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@
8989
if (object.node.IsPlatformViewNode()) {
9090
FlutterPlatformViewsController* controller = GetPlatformViewsController();
9191
if (controller) {
92-
object.platformViewSemanticsContainer =
93-
[[FlutterPlatformViewSemanticsContainer alloc] initWithSemanticsObject:object];
92+
object.platformViewSemanticsContainer = [[[FlutterPlatformViewSemanticsContainer alloc]
93+
initWithSemanticsObject:object] autorelease];
9494
}
9595
} else if (object.platformViewSemanticsContainer) {
96-
[object.platformViewSemanticsContainer release];
96+
object.platformViewSemanticsContainer = nil;
9797
}
9898
}
9999

shell/platform/darwin/ios/framework/Source/accessibility_bridge_test.mm

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,67 @@
55
#import <XCTest/XCTest.h>
66

77
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
8+
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
9+
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
810
#import "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h"
911
#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
1012
#import "third_party/ocmock/Source/OCMock/OCMock.h"
1113

1214
FLUTTER_ASSERT_NOT_ARC
15+
@class MockPlatformView;
16+
static MockPlatformView* gMockPlatformView = nil;
17+
18+
@interface MockPlatformView : UIView
19+
@end
20+
@implementation MockPlatformView
21+
22+
- (instancetype)init {
23+
self = [super init];
24+
if (self) {
25+
gMockPlatformView = self;
26+
}
27+
return self;
28+
}
29+
30+
- (void)dealloc {
31+
gMockPlatformView = nil;
32+
[super dealloc];
33+
}
34+
35+
@end
36+
37+
@interface MockFlutterPlatformView : NSObject <FlutterPlatformView>
38+
@property(nonatomic, strong) UIView* view;
39+
@end
40+
41+
@implementation MockFlutterPlatformView
42+
43+
- (instancetype)init {
44+
if (self = [super init]) {
45+
_view = [[MockPlatformView alloc] init];
46+
}
47+
return self;
48+
}
49+
50+
- (void)dealloc {
51+
[_view release];
52+
_view = nil;
53+
[super dealloc];
54+
}
55+
56+
@end
57+
58+
@interface MockFlutterPlatformFactory : NSObject <FlutterPlatformViewFactory>
59+
@end
60+
61+
@implementation MockFlutterPlatformFactory
62+
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
63+
viewIdentifier:(int64_t)viewId
64+
arguments:(id _Nullable)args {
65+
return [[[MockFlutterPlatformView alloc] init] autorelease];
66+
}
67+
68+
@end
1369

1470
namespace flutter {
1571
namespace {
@@ -131,4 +187,55 @@ - (void)testUpdateSemanticsOneNode {
131187
OCMVerifyAll(mockFlutterView);
132188
}
133189

190+
- (void)testSemanticsDeallocated {
191+
@autoreleasepool {
192+
flutter::MockDelegate mock_delegate;
193+
auto thread_task_runner = CreateNewThread("AccessibilityBridgeTest");
194+
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
195+
/*platform=*/thread_task_runner,
196+
/*raster=*/thread_task_runner,
197+
/*ui=*/thread_task_runner,
198+
/*io=*/thread_task_runner);
199+
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
200+
/*delegate=*/mock_delegate,
201+
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
202+
/*task_runners=*/runners);
203+
id mockFlutterView = OCMClassMock([FlutterView class]);
204+
std::string label = "some label";
205+
206+
auto flutterPlatformViewsController =
207+
std::make_unique<flutter::FlutterPlatformViewsController>();
208+
flutterPlatformViewsController->SetFlutterView(mockFlutterView);
209+
210+
MockFlutterPlatformFactory* factory = [[MockFlutterPlatformFactory new] autorelease];
211+
flutterPlatformViewsController->RegisterViewFactory(
212+
factory, @"MockFlutterPlatformView",
213+
FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
214+
FlutterResult result = ^(id result) {
215+
};
216+
flutterPlatformViewsController->OnMethodCall(
217+
[FlutterMethodCall
218+
methodCallWithMethodName:@"create"
219+
arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
220+
result);
221+
222+
auto bridge = std::make_unique<flutter::AccessibilityBridge>(
223+
/*view=*/mockFlutterView,
224+
/*platform_view=*/platform_view.get(),
225+
/*platform_views_controller=*/flutterPlatformViewsController.get());
226+
227+
flutter::SemanticsNodeUpdates nodes;
228+
flutter::SemanticsNode semantics_node;
229+
semantics_node.id = 2;
230+
semantics_node.platformViewId = 2;
231+
semantics_node.label = label;
232+
nodes[kRootNodeId] = semantics_node;
233+
flutter::CustomAccessibilityActionUpdates actions;
234+
bridge->UpdateSemantics(/*nodes=*/nodes, /*actions=*/actions);
235+
XCTAssertNotNil(gMockPlatformView);
236+
flutterPlatformViewsController->Reset();
237+
}
238+
XCTAssertNil(gMockPlatformView);
239+
}
240+
134241
@end

0 commit comments

Comments
 (0)