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

Commit dc6e438

Browse files
authored
Fix UIVisualEffectView leak in platform view filter (#52591)
I found this while migrating `FlutterPlatformViews_Internal.mm` to ARC #52535. I'll land this first. ```objc if (_backdropFilterView != visualEffectView) { _backdropFilterView = [visualEffectView retain]; } ``` should instead be something like: ```objc if (_backdropFilterView != visualEffectView) { id oldBackdropFilterView = _backdropFilterView; _backdropFilterView = [visualEffectView retain]; [oldBackdropFilterView release]; } ``` But that's already what the built-in MRC `nonatomic, retain` property setter does, so use that instead. Added a test that passes on this PR and fails on main.
1 parent 3fb0011 commit dc6e438

File tree

3 files changed

+48
-20
lines changed

3 files changed

+48
-20
lines changed

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

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,38 @@ - (void)testChildClippingViewHitTests {
251251

252252
- (void)testReleasesBackdropFilterSubviewsOnChildClippingViewDealloc {
253253
__weak NSMutableArray<UIVisualEffectView*>* weakBackdropFilterSubviews = nil;
254+
__weak UIVisualEffectView* weakVisualEffectView1 = nil;
255+
__weak UIVisualEffectView* weakVisualEffectView2 = nil;
256+
254257
@autoreleasepool {
255-
ChildClippingView* clipping_view = [[ChildClippingView alloc] initWithFrame:CGRectZero];
256-
weakBackdropFilterSubviews = clipping_view.backdropFilterSubviews;
258+
ChildClippingView* clippingView = [[ChildClippingView alloc] initWithFrame:CGRectZero];
259+
UIVisualEffectView* visualEffectView1 = [[UIVisualEffectView alloc]
260+
initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
261+
weakVisualEffectView1 = visualEffectView1;
262+
PlatformViewFilter* platformViewFilter1 =
263+
[[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
264+
blurRadius:5
265+
visualEffectView:visualEffectView1];
266+
267+
[clippingView applyBlurBackdropFilters:@[ platformViewFilter1 ]];
268+
269+
// Replace the blur filter to validate the original and new UIVisualEffectView are released.
270+
UIVisualEffectView* visualEffectView2 = [[UIVisualEffectView alloc]
271+
initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
272+
weakVisualEffectView2 = visualEffectView2;
273+
PlatformViewFilter* platformViewFilter2 =
274+
[[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
275+
blurRadius:5
276+
visualEffectView:visualEffectView2];
277+
[clippingView applyBlurBackdropFilters:@[ platformViewFilter2 ]];
278+
279+
weakBackdropFilterSubviews = clippingView.backdropFilterSubviews;
257280
XCTAssertNotNil(weakBackdropFilterSubviews);
258-
clipping_view = nil;
281+
clippingView = nil;
259282
}
260283
XCTAssertNil(weakBackdropFilterSubviews);
284+
XCTAssertNil(weakVisualEffectView1);
285+
XCTAssertNil(weakVisualEffectView2);
261286
}
262287

263288
- (void)testApplyBackdropFilter {
@@ -595,6 +620,7 @@ - (void)testAddBackdropFilters {
595620
XCTAssertEqual(originalView, newView);
596621
id mockOrignalView = OCMPartialMock(originalView);
597622
OCMReject([mockOrignalView removeFromSuperview]);
623+
[mockOrignalView stopMocking];
598624
}
599625
}
600626

@@ -1302,20 +1328,26 @@ - (void)testApplyBackdropFilterAPIChangedInvalidInputRadius {
13021328
}
13031329

13041330
- (void)testBackdropFilterVisualEffectSubviewBackgroundColor {
1305-
UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc]
1306-
initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
1307-
PlatformViewFilter* platformViewFilter =
1308-
[[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
1309-
blurRadius:5
1310-
visualEffectView:visualEffectView];
1311-
CGColorRef visualEffectSubviewBackgroundColor = nil;
1312-
for (UIView* view in [platformViewFilter backdropFilterView].subviews) {
1313-
if ([NSStringFromClass([view class]) hasSuffix:@"VisualEffectSubview"]) {
1314-
visualEffectSubviewBackgroundColor = view.layer.backgroundColor;
1331+
__weak UIVisualEffectView* weakVisualEffectView;
1332+
1333+
@autoreleasepool {
1334+
UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc]
1335+
initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
1336+
weakVisualEffectView = visualEffectView;
1337+
PlatformViewFilter* platformViewFilter =
1338+
[[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10)
1339+
blurRadius:5
1340+
visualEffectView:visualEffectView];
1341+
CGColorRef visualEffectSubviewBackgroundColor = nil;
1342+
for (UIView* view in [platformViewFilter backdropFilterView].subviews) {
1343+
if ([NSStringFromClass([view class]) hasSuffix:@"VisualEffectSubview"]) {
1344+
visualEffectSubviewBackgroundColor = view.layer.backgroundColor;
1345+
}
13151346
}
1347+
XCTAssertTrue(
1348+
CGColorEqualToColor(visualEffectSubviewBackgroundColor, UIColor.clearColor.CGColor));
13161349
}
1317-
XCTAssertTrue(
1318-
CGColorEqualToColor(visualEffectSubviewBackgroundColor, UIColor.clearColor.CGColor));
1350+
XCTAssertNil(weakVisualEffectView);
13191351
}
13201352

13211353
- (void)testCompositePlatformView {

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,7 @@ - (void)updateVisualEffectView:(UIVisualEffectView*)visualEffectView {
172172
visualEffectSubview.layer.backgroundColor = UIColor.clearColor.CGColor;
173173
visualEffectView.frame = _frame;
174174

175-
if (_backdropFilterView != visualEffectView) {
176-
_backdropFilterView = [visualEffectView retain];
177-
}
175+
self.backdropFilterView = visualEffectView;
178176
}
179177

180178
@end

testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,6 @@
487487
BUNDLE_LOADER = "$(TEST_HOST)";
488488
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
489489
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
490-
CLANG_ENABLE_OBJC_ARC = NO;
491490
CODE_SIGN_STYLE = Automatic;
492491
HEADER_SEARCH_PATHS = (
493492
../../../..,
@@ -532,7 +531,6 @@
532531
BUNDLE_LOADER = "$(TEST_HOST)";
533532
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
534533
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
535-
CLANG_ENABLE_OBJC_ARC = NO;
536534
CODE_SIGN_STYLE = Automatic;
537535
HEADER_SEARCH_PATHS = (
538536
../../../..,

0 commit comments

Comments
 (0)