From 59cd68ef8adcbd950e7a9627844da702c16ea2dd Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Mon, 6 May 2024 17:14:10 -0700 Subject: [PATCH] Fix UIVisualEffectView leak in platform view filter --- .../Source/FlutterPlatformViewsTest.mm | 62 ++++++++++++++----- .../Source/FlutterPlatformViews_Internal.mm | 4 +- .../IosUnitTests.xcodeproj/project.pbxproj | 2 - 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 2dc397d756a7c..7b4c82d8d5c7e 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -251,13 +251,38 @@ - (void)testChildClippingViewHitTests { - (void)testReleasesBackdropFilterSubviewsOnChildClippingViewDealloc { __weak NSMutableArray* weakBackdropFilterSubviews = nil; + __weak UIVisualEffectView* weakVisualEffectView1 = nil; + __weak UIVisualEffectView* weakVisualEffectView2 = nil; + @autoreleasepool { - ChildClippingView* clipping_view = [[ChildClippingView alloc] initWithFrame:CGRectZero]; - weakBackdropFilterSubviews = clipping_view.backdropFilterSubviews; + ChildClippingView* clippingView = [[ChildClippingView alloc] initWithFrame:CGRectZero]; + UIVisualEffectView* visualEffectView1 = [[UIVisualEffectView alloc] + initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; + weakVisualEffectView1 = visualEffectView1; + PlatformViewFilter* platformViewFilter1 = + [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) + blurRadius:5 + visualEffectView:visualEffectView1]; + + [clippingView applyBlurBackdropFilters:@[ platformViewFilter1 ]]; + + // Replace the blur filter to validate the original and new UIVisualEffectView are released. + UIVisualEffectView* visualEffectView2 = [[UIVisualEffectView alloc] + initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; + weakVisualEffectView2 = visualEffectView2; + PlatformViewFilter* platformViewFilter2 = + [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) + blurRadius:5 + visualEffectView:visualEffectView2]; + [clippingView applyBlurBackdropFilters:@[ platformViewFilter2 ]]; + + weakBackdropFilterSubviews = clippingView.backdropFilterSubviews; XCTAssertNotNil(weakBackdropFilterSubviews); - clipping_view = nil; + clippingView = nil; } XCTAssertNil(weakBackdropFilterSubviews); + XCTAssertNil(weakVisualEffectView1); + XCTAssertNil(weakVisualEffectView2); } - (void)testApplyBackdropFilter { @@ -595,6 +620,7 @@ - (void)testAddBackdropFilters { XCTAssertEqual(originalView, newView); id mockOrignalView = OCMPartialMock(originalView); OCMReject([mockOrignalView removeFromSuperview]); + [mockOrignalView stopMocking]; } } @@ -1302,20 +1328,26 @@ - (void)testApplyBackdropFilterAPIChangedInvalidInputRadius { } - (void)testBackdropFilterVisualEffectSubviewBackgroundColor { - UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] - initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; - PlatformViewFilter* platformViewFilter = - [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) - blurRadius:5 - visualEffectView:visualEffectView]; - CGColorRef visualEffectSubviewBackgroundColor = nil; - for (UIView* view in [platformViewFilter backdropFilterView].subviews) { - if ([NSStringFromClass([view class]) hasSuffix:@"VisualEffectSubview"]) { - visualEffectSubviewBackgroundColor = view.layer.backgroundColor; + __weak UIVisualEffectView* weakVisualEffectView; + + @autoreleasepool { + UIVisualEffectView* visualEffectView = [[UIVisualEffectView alloc] + initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; + weakVisualEffectView = visualEffectView; + PlatformViewFilter* platformViewFilter = + [[PlatformViewFilter alloc] initWithFrame:CGRectMake(0, 0, 10, 10) + blurRadius:5 + visualEffectView:visualEffectView]; + CGColorRef visualEffectSubviewBackgroundColor = nil; + for (UIView* view in [platformViewFilter backdropFilterView].subviews) { + if ([NSStringFromClass([view class]) hasSuffix:@"VisualEffectSubview"]) { + visualEffectSubviewBackgroundColor = view.layer.backgroundColor; + } } + XCTAssertTrue( + CGColorEqualToColor(visualEffectSubviewBackgroundColor, UIColor.clearColor.CGColor)); } - XCTAssertTrue( - CGColorEqualToColor(visualEffectSubviewBackgroundColor, UIColor.clearColor.CGColor)); + XCTAssertNil(weakVisualEffectView); } - (void)testCompositePlatformView { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm index 2aa13f5ae09f5..ebdb0cc7a4979 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.mm @@ -172,9 +172,7 @@ - (void)updateVisualEffectView:(UIVisualEffectView*)visualEffectView { visualEffectSubview.layer.backgroundColor = UIColor.clearColor.CGColor; visualEffectView.frame = _frame; - if (_backdropFilterView != visualEffectView) { - _backdropFilterView = [visualEffectView retain]; - } + self.backdropFilterView = visualEffectView; } @end diff --git a/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj b/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj index 0ff04e310ac72..87f291b87dd38 100644 --- a/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj +++ b/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj @@ -487,7 +487,6 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_ENABLE_OBJC_ARC = NO; CODE_SIGN_STYLE = Automatic; HEADER_SEARCH_PATHS = ( ../../../.., @@ -532,7 +531,6 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CLANG_ENABLE_OBJC_ARC = NO; CODE_SIGN_STYLE = Automatic; HEADER_SEARCH_PATHS = ( ../../../..,