iOS: Apply nullability annotations to FlutterPlatformViewsController (#56839)

Applies non-null by default annotations to
FlutterPlatformViewsController with opt-outs where necessary. Updates unit tests to create graphics contexts where requried.

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h
index 9ce3c7f..5b55ce6 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h
@@ -23,24 +23,23 @@
 #import "flutter/shell/platform/darwin/ios/framework/Source/overlay_layer_pool.h"
 #import "flutter/shell/platform/darwin/ios/ios_context.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 @class FlutterTouchInterceptingView;
 @class FlutterClippingMaskViewPool;
 
 @interface FlutterPlatformViewsController : NSObject
 
-- (id)init NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
 
 /// The task runner used to post rendering tasks to the platform thread.
 @property(nonatomic, assign) const fml::RefPtr<fml::TaskRunner>& taskRunner;
 
 /// The flutter view.
-@property(nonatomic, weak) UIView* flutterView;
+@property(nonatomic, weak) UIView* _Nullable flutterView;
 
 /// @brief The flutter view controller.
-@property(nonatomic, weak) UIViewController<FlutterViewResponder>* flutterViewController;
-
-/// @brief Retrieve the view controller.
-- (UIViewController<FlutterViewResponder>*)flutterViewController;
+@property(nonatomic, weak) UIViewController<FlutterViewResponder>* _Nullable flutterViewController;
 
 /// @brief set the factory used to construct embedded UI Views.
 - (void)registerViewFactory:(NSObject<FlutterPlatformViewFactory>*)factory
@@ -101,7 +100,7 @@
 /// Called from the raster thread.
 - (BOOL)submitFrame:(std::unique_ptr<flutter::SurfaceFrame>)frame
      withIosContext:(const std::shared_ptr<flutter::IOSContext>&)iosContext
-          grContext:(GrDirectContext*)grContext;
+          grContext:(GrDirectContext* _Nullable)grContext;
 
 /// @brief Handler for platform view message channels.
 - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
@@ -130,7 +129,7 @@
 // If the `PlatformViewsController` does not contain any `FlutterPlatformView` object or
 // a `FlutterPlatformView` object associated with the view_id cannot be found, the method
 // returns nil.
-- (UIView*)platformViewForId:(int64_t)viewId;
+- (UIView* _Nullable)platformViewForId:(int64_t)viewId;
 
 // Composite the PlatformView with `viewId`.
 //
@@ -146,4 +145,6 @@
 
 @end
 
+NS_ASSUME_NONNULL_END
+
 #endif  // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWSCONTROLLER_H_
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm
index ba531ca..7a452ba 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.mm
@@ -705,6 +705,7 @@
 }
 
 - (flutter::DlCanvas*)compositeEmbeddedViewWithId:(int64_t)viewId {
+  FML_DCHECK(self.slices.find(viewId) != self.slices.end());
   return self.slices[viewId]->canvas();
 }
 
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
index dd48e60..2a890cc 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm
@@ -8,6 +8,8 @@
 #import <UIKit/UIKit.h>
 #import <XCTest/XCTest.h>
 
+#include <memory>
+
 #include "flutter/display_list/effects/dl_image_filters.h"
 #include "flutter/fml/synchronization/count_down_latch.h"
 #include "flutter/fml/thread.h"
@@ -17,6 +19,7 @@
 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsController.h"
 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTouchInterceptingView_Test.h"
+#include "flutter/shell/platform/darwin/ios/ios_context_noop.h"
 #include "flutter/shell/platform/darwin/ios/platform_view_ios.h"
 
 FLUTTER_ASSERT_ARC
@@ -3103,9 +3106,10 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return false; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-  XCTAssertFalse([flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                                              withIosContext:nil
-                                                   grContext:nil]);
+  XCTAssertFalse([flutterPlatformViewsController
+         submitFrame:std::move(mock_surface)
+      withIosContext:std::make_shared<flutter::IOSContextNoop>()
+           grContext:nil]);
 
   auto embeddedViewParams_2 =
       std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
@@ -3120,9 +3124,10 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-  XCTAssertTrue([flutterPlatformViewsController submitFrame:std::move(mock_surface_submit_true)
-                                             withIosContext:nil
-                                                  grContext:nil]);
+  XCTAssertTrue([flutterPlatformViewsController
+         submitFrame:std::move(mock_surface_submit_true)
+      withIosContext:std::make_shared<flutter::IOSContextNoop>()
+           grContext:nil]);
 }
 
 - (void)
@@ -3328,10 +3333,10 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-
-  XCTAssertTrue([flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                                             withIosContext:nil
-                                                  grContext:nil]);
+  XCTAssertTrue([flutterPlatformViewsController
+         submitFrame:std::move(mock_surface)
+      withIosContext:std::make_shared<flutter::IOSContextNoop>()
+           grContext:nil]);
 
   // platform view is wrapped by touch interceptor, which itself is wrapped by clipping view.
   UIView* clippingView1 = view1.superview.superview;
@@ -3359,9 +3364,10 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-  XCTAssertTrue([flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                                             withIosContext:nil
-                                                  grContext:nil]);
+  XCTAssertTrue([flutterPlatformViewsController
+         submitFrame:std::move(mock_surface)
+      withIosContext:std::make_shared<flutter::IOSContextNoop>()
+           grContext:nil]);
 
   XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] >
                     [flutterView.subviews indexOfObject:clippingView2],
@@ -3442,10 +3448,10 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-
-  XCTAssertTrue([flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                                             withIosContext:nil
-                                                  grContext:nil]);
+  XCTAssertTrue([flutterPlatformViewsController
+         submitFrame:std::move(mock_surface)
+      withIosContext:std::make_shared<flutter::IOSContextNoop>()
+           grContext:nil]);
 
   // platform view is wrapped by touch interceptor, which itself is wrapped by clipping view.
   UIView* clippingView1 = view1.superview.superview;
@@ -3473,10 +3479,10 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-
-  XCTAssertTrue([flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                                             withIosContext:nil
-                                                  grContext:nil]);
+  XCTAssertTrue([flutterPlatformViewsController
+         submitFrame:std::move(mock_surface)
+      withIosContext:std::make_shared<flutter::IOSContextNoop>()
+           grContext:nil]);
 
   XCTAssertTrue([flutterView.subviews indexOfObject:clippingView1] <
                     [flutterView.subviews indexOfObject:clippingView2],
@@ -3945,10 +3951,10 @@
         [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
         [](const flutter::SurfaceFrame& surface_frame) { return true; },
         /*frame_size=*/SkISize::Make(800, 600));
-
-    XCTAssertTrue([flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                                               withIosContext:nil
-                                                    grContext:nil]);
+    XCTAssertTrue([flutterPlatformViewsController
+           submitFrame:std::move(mock_surface)
+        withIosContext:std::make_shared<flutter::IOSContextNoop>()
+             grContext:nil]);
 
     // Disposing won't remove embedded views until the view is removed from the composition_order_
     XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 2UL);
@@ -3975,10 +3981,10 @@
         [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
         [](const flutter::SurfaceFrame& surface_frame) { return true; },
         /*frame_size=*/SkISize::Make(800, 600));
-
-    XCTAssertTrue([flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                                               withIosContext:nil
-                                                    grContext:nil]);
+    XCTAssertTrue([flutterPlatformViewsController
+           submitFrame:std::move(mock_surface)
+        withIosContext:std::make_shared<flutter::IOSContextNoop>()
+             grContext:nil]);
 
     // Disposing won't remove embedded views until the view is removed from the composition_order_
     XCTAssertEqual(flutterPlatformViewsController.embeddedViewCount, 1UL);
@@ -4051,9 +4057,8 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-
   [flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                               withIosContext:nil
+                               withIosContext:std::make_shared<flutter::IOSContextNoop>()
                                     grContext:nil];
 
   UIView* someView = [[UIView alloc] init];
@@ -4130,9 +4135,8 @@
       [](const flutter::SurfaceFrame& surface_frame, flutter::DlCanvas* canvas) { return true; },
       [](const flutter::SurfaceFrame& surface_frame) { return true; },
       /*frame_size=*/SkISize::Make(800, 600));
-
   [flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                               withIosContext:nil
+                               withIosContext:std::make_shared<flutter::IOSContextNoop>()
                                     grContext:nil];
 
   XCTAssertEqual(flutterView.subviews.count, 1u);
@@ -4252,7 +4256,7 @@
   });
 
   [flutterPlatformViewsController submitFrame:std::move(mock_surface)
-                               withIosContext:nil
+                               withIosContext:std::make_shared<flutter::IOSContextNoop>()
                                     grContext:nil];
 
   XCTAssertTrue(submit_info.has_value());