SDL: Explicitly retain and release NSObjects in C structures (971c5)

From 971c5c26106fe0498c601b71009e82303188d1e9 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 12 Feb 2024 10:20:06 -0800
Subject: [PATCH] Explicitly retain and release NSObjects in C structures

Fixes https://github.com/libsdl-org/SDL/issues/9021
Fixes https://github.com/libsdl-org/SDL/issues/9042

(cherry picked from commit 42cdbf6b214a4a4b614e6086d80bb12a1fce32be)
---
 src/joystick/iphoneos/SDL_mfijoystick.m | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/joystick/iphoneos/SDL_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m
index 4bcaede9134e..be70a0710930 100644
--- a/src/joystick/iphoneos/SDL_mfijoystick.m
+++ b/src/joystick/iphoneos/SDL_mfijoystick.m
@@ -510,7 +510,7 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
         NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
 
         /* Provide both axes and analog buttons as SDL axes */
-        device->axes = [[[elements allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
+        NSArray *axes = [[[elements allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
                                          filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
             GCControllerElement *element;
 
@@ -527,8 +527,7 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
             }
             return NO;
         }]];
-        device->naxes = (int)device->axes.count;
-        device->buttons = [[[elements allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
+        NSArray *buttons = [[[elements allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
                                             filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
             GCControllerElement *element;
 
@@ -542,7 +541,12 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
             }
             return NO;
         }]];
-        device->nbuttons = (int)device->buttons.count;
+        /* Explicitly retain the arrays because SDL_JoystickDeviceItem is a
+         * struct, and ARC doesn't work with structs. */
+        device->naxes = (int)axes.count;
+        device->axes = (__bridge NSArray *)CFBridgingRetain(axes);
+        device->nbuttons = (int)buttons.count;
+        device->buttons = (__bridge NSArray *)CFBridgingRetain(buttons);
         subtype = 4;
 
 #ifdef DEBUG_CONTROLLER_PROFILE
@@ -779,13 +783,20 @@ static void IOS_AddJoystickDevice(GCController *controller, SDL_bool acceleromet
 
 #ifdef SDL_JOYSTICK_MFI
     @autoreleasepool {
+        /* These were explicitly retained in the struct, so they should be explicitly released before freeing the struct. */
         if (device->controller) {
-            /* The controller was explicitly retained in the struct, so it
-             * should be explicitly released before freeing the struct. */
             GCController *controller = CFBridgingRelease((__bridge CFTypeRef)(device->controller));
             controller.controllerPausedHandler = nil;
             device->controller = nil;
         }
+        if (device->axes) {
+            NSArray *axes = CFBridgingRelease((__bridge CFTypeRef)(device->axes));
+            device->axes = nil;
+        }
+        if (device->buttons) {
+            NSArray *buttons = CFBridgingRelease((__bridge CFTypeRef)(device->buttons));
+            device->buttons = nil;
+        }
     }
 #endif /* SDL_JOYSTICK_MFI */