Remove -[NSNotificationCenter removeObserver:] in deallocs (#52772)

Removing `NSNotificationCenter` observers in dealloc hasn't been necessary since iOS 8 or macOS 10.10.

> If your app targets iOS 9.0 and later or macOS 10.11 and later, and you used [addObserver:selector:name:object:](https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415360-addobserver), you do not need to unregister the observer. If you forget or are unable to remove the observer, the system cleans up the next time it would have posted to it.

https://developer.apple.com/documentation/foundation/nsnotificationcenter/1413994-removeobserver

Remove it.
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngineGroup.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngineGroup.mm
index fc5beec..b0eca94 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterEngineGroup.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterEngineGroup.mm
@@ -38,8 +38,6 @@
 }
 
 - (void)dealloc {
-  NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
-  [center removeObserver:self];
   [_name release];
   [_engines release];
   [_project release];
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm b/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm
index 83d248f..a343e90 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterMetalLayer.mm
@@ -186,10 +186,6 @@
   return self;
 }
 
-- (void)dealloc {
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-}
-
 - (void)setMaxRefreshRate:(double)refreshRate forceMax:(BOOL)forceMax {
   // This is copied from vsync_waiter_ios.mm. The vsync waiter has display link scheduled on UI
   // thread which does not trigger actual core animation frame. As a workaround FlutterMetalLayer
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm b/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm
index 81c6799..11451d3 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm
@@ -31,7 +31,6 @@
 @end
 
 @implementation FlutterPluginAppLifeCycleDelegate {
-  NSMutableArray* _notificationUnsubscribers;
   UIBackgroundTaskIdentifier _debugBackgroundTask;
 
   // Weak references to registered plugins.
@@ -40,16 +39,10 @@
 
 - (void)addObserverFor:(NSString*)name selector:(SEL)selector {
   [[NSNotificationCenter defaultCenter] addObserver:self selector:selector name:name object:nil];
-  __block NSObject* blockSelf = self;
-  dispatch_block_t unsubscribe = ^{
-    [[NSNotificationCenter defaultCenter] removeObserver:blockSelf name:name object:nil];
-  };
-  [_notificationUnsubscribers addObject:[unsubscribe copy]];
 }
 
 - (instancetype)init {
   if (self = [super init]) {
-    _notificationUnsubscribers = [[NSMutableArray alloc] init];
     std::string cachePath = fml::paths::JoinPaths({getenv("HOME"), kCallbackCacheSubDir});
     [FlutterCallbackCache setCachePath:[NSString stringWithUTF8String:cachePath.c_str()]];
 #if not APPLICATION_EXTENSION_API_ONLY
@@ -70,12 +63,6 @@
   return self;
 }
 
-- (void)dealloc {
-  for (dispatch_block_t unsubscribe in _notificationUnsubscribers) {
-    unsubscribe();
-  }
-}
-
 static BOOL IsPowerOfTwo(NSUInteger x) {
   return x != 0 && (x & (x - 1)) == 0;
 }
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.mm
index 9fcc645..d96ae4c 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegateTest.mm
@@ -10,6 +10,12 @@
 
 FLUTTER_ASSERT_ARC
 
+@interface FakePlugin : NSObject <FlutterApplicationLifeCycleDelegate>
+@end
+
+@implementation FakePlugin
+@end
+
 @interface FlutterPluginAppLifeCycleDelegateTest : XCTestCase
 @end
 
@@ -89,6 +95,21 @@
   [self waitForExpectations:@[ expectation ] timeout:5.0];
   OCMVerify([plugin applicationWillTerminate:[UIApplication sharedApplication]]);
 }
+
+- (void)testReleasesPluginOnDealloc {
+  __weak id<FlutterApplicationLifeCycleDelegate> weakPlugin;
+  __weak FlutterPluginAppLifeCycleDelegate* weakDelegate;
+  @autoreleasepool {
+    FakePlugin* fakePlugin = [[FakePlugin alloc] init];
+    weakPlugin = fakePlugin;
+    FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
+    [delegate addDelegate:fakePlugin];
+    weakDelegate = delegate;
+  }
+  XCTAssertNil(weakPlugin);
+  XCTAssertNil(weakDelegate);
+}
+
 #endif
 
 @end
diff --git a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm b/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm
index ba53217..e2439b3 100644
--- a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm
+++ b/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegate.mm
@@ -13,23 +13,14 @@
 #include "flutter/fml/logging.h"
 #include "flutter/fml/paths.h"
 
-@implementation FlutterAppLifecycleRegistrar {
-  NSMutableArray* _notificationUnsubscribers;
-}
+@implementation FlutterAppLifecycleRegistrar
 
 - (void)addObserverFor:(NSString*)name selector:(SEL)selector {
   [[NSNotificationCenter defaultCenter] addObserver:self selector:selector name:name object:nil];
-  __block NSObject* blockSelf = self;
-  dispatch_block_t unsubscribe = ^{
-    [[NSNotificationCenter defaultCenter] removeObserver:blockSelf name:name object:nil];
-  };
-  [_notificationUnsubscribers addObject:[unsubscribe copy]];
 }
 
 - (instancetype)init {
   if (self = [super init]) {
-    _notificationUnsubscribers = [[NSMutableArray alloc] init];
-
 // Using a macro to avoid errors where the notification doesn't match the
 // selector.
 #ifdef OBSERVE_NOTIFICATION
@@ -60,15 +51,6 @@
   return self;
 }
 
-- (void)dealloc {
-  for (dispatch_block_t unsubscribe in _notificationUnsubscribers) {
-    unsubscribe();
-  }
-  [_notificationUnsubscribers removeAllObjects];
-  _delegates = nil;
-  _notificationUnsubscribers = nil;
-}
-
 static BOOL IsPowerOfTwo(NSUInteger x) {
   return x != 0 && (x & (x - 1)) == 0;
 }
diff --git a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm
index 079ddbb..e073cc3 100644
--- a/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm
+++ b/shell/platform/darwin/macos/framework/Source/FlutterAppLifecycleDelegateTest.mm
@@ -220,4 +220,18 @@
   }
 }
 
+TEST(FlutterAppLifecycleDelegateTest, ReleasesDelegateOnDealloc) {
+  __weak FlutterAppLifecycleRegistrar* weakRegistrar;
+  __weak TestFlutterAppLifecycleDelegate* weakDelegate;
+  @autoreleasepool {
+    FlutterAppLifecycleRegistrar* registrar = [[FlutterAppLifecycleRegistrar alloc] init];
+    weakRegistrar = registrar;
+    TestFlutterAppLifecycleDelegate* delegate = [[TestFlutterAppLifecycleDelegate alloc] init];
+    weakDelegate = delegate;
+    [registrar addDelegate:delegate];
+  }
+  EXPECT_EQ(weakRegistrar, nil);
+  EXPECT_EQ(weakDelegate, nil);
+}
+
 }  // namespace flutter::testing