|
26 | 26 | #import <objc/runtime.h>
|
27 | 27 |
|
28 | 28 | #define MAX_PENDING_APP_DELEGATE_BLOCKS 8
|
| 29 | +#define MAX_SEEN_DELEGATE_CLASSES 32 |
29 | 30 |
|
30 | 31 | static IMP g_original_setDelegate_imp = NULL;
|
31 |
| -static Class g_app_delegate_class = nil; |
| 32 | +// static Class g_app_delegate_class = nil; // Removed |
32 | 33 | static void (^g_pending_app_delegate_blocks[MAX_PENDING_APP_DELEGATE_BLOCKS])(Class) = {nil};
|
33 | 34 | static int g_pending_block_count = 0;
|
34 | 35 |
|
| 36 | +static Class g_seen_delegate_classes[MAX_SEEN_DELEGATE_CLASSES] = {nil}; |
| 37 | +static int g_seen_delegate_classes_count = 0; |
| 38 | + |
35 | 39 | // Swizzled implementation of setDelegate:
|
36 | 40 | static void Firebase_setDelegate(id self, SEL _cmd, id<UIApplicationDelegate> delegate) {
|
| 41 | + Class new_class = nil; |
37 | 42 | if (delegate) {
|
38 |
| - g_app_delegate_class = [delegate class]; |
| 43 | + new_class = [delegate class]; |
39 | 44 | NSLog(@"Firebase: UIApplication setDelegate: called with class %s (Swizzled)",
|
40 |
| - class_getName(g_app_delegate_class)); |
| 45 | + class_getName(new_class)); |
41 | 46 | } else {
|
42 |
| - g_app_delegate_class = nil; |
43 | 47 | NSLog(@"Firebase: UIApplication setDelegate: called with nil delegate (Swizzled)");
|
44 | 48 | }
|
45 | 49 |
|
46 |
| - // Check and execute/clear g_pending_app_delegate_blocks |
47 |
| - if (g_app_delegate_class) { // Delegate is valid, execute pending blocks |
48 |
| - if (g_pending_block_count > 0) { |
49 |
| - NSLog(@"Firebase: Firebase_setDelegate executing %d pending block(s) with delegate class: %s.", |
50 |
| - g_pending_block_count, class_getName(g_app_delegate_class)); |
51 |
| - for (int i = 0; i < g_pending_block_count; i++) { |
52 |
| - if (g_pending_app_delegate_blocks[i]) { |
53 |
| - g_pending_app_delegate_blocks[i](g_app_delegate_class); |
54 |
| - g_pending_app_delegate_blocks[i] = nil; // Release the block |
55 |
| - } |
| 50 | + if (new_class) { |
| 51 | + bool already_seen = false; |
| 52 | + for (int i = 0; i < g_seen_delegate_classes_count; i++) { |
| 53 | + if (g_seen_delegate_classes[i] == new_class) { |
| 54 | + already_seen = true; |
| 55 | + break; |
56 | 56 | }
|
57 |
| - // All pending blocks processed, reset count. |
58 |
| - g_pending_block_count = 0; |
59 | 57 | }
|
60 |
| - } else { // Delegate is nil, clear any pending blocks |
61 |
| - if (g_pending_block_count > 0) { |
62 |
| - NSLog(@"Firebase: Firebase_setDelegate called with nil delegate, clearing %d pending block(s).", g_pending_block_count); |
63 |
| - for (int i = 0; i < g_pending_block_count; i++) { |
64 |
| - if (g_pending_app_delegate_blocks[i]) { |
65 |
| - g_pending_app_delegate_blocks[i] = nil; // Release the block |
| 58 | + |
| 59 | + if (!already_seen) { |
| 60 | + if (g_seen_delegate_classes_count < MAX_SEEN_DELEGATE_CLASSES) { |
| 61 | + g_seen_delegate_classes[g_seen_delegate_classes_count] = new_class; |
| 62 | + g_seen_delegate_classes_count++; |
| 63 | + NSLog(@"Firebase: Added new delegate class %s to seen list (total seen: %d).", |
| 64 | + class_getName(new_class), g_seen_delegate_classes_count); |
| 65 | + |
| 66 | + if (g_pending_block_count > 0) { |
| 67 | + NSLog(@"Firebase: Executing %d pending block(s) for new delegate class: %s.", |
| 68 | + g_pending_block_count, class_getName(new_class)); |
| 69 | + for (int i = 0; i < g_pending_block_count; i++) { |
| 70 | + if (g_pending_app_delegate_blocks[i]) { |
| 71 | + g_pending_app_delegate_blocks[i](new_class); |
| 72 | + // Pending blocks are not cleared here; they persist to be run by RunOnAppDelegate |
| 73 | + // for all seen delegate classes, and for any future new delegate classes. |
| 74 | + } |
| 75 | + } |
66 | 76 | }
|
| 77 | + } else { |
| 78 | + NSLog(@"Firebase Error: Exceeded MAX_SEEN_DELEGATE_CLASSES (%d). Cannot add new delegate class %s or run pending blocks for it.", |
| 79 | + MAX_SEEN_DELEGATE_CLASSES, class_getName(new_class)); |
67 | 80 | }
|
68 |
| - // All pending blocks cleared, reset count. |
69 |
| - g_pending_block_count = 0; |
| 81 | + } else { |
| 82 | + NSLog(@"Firebase: Delegate class %s already seen. Not re-processing pending blocks for it here.", class_getName(new_class)); |
70 | 83 | }
|
71 | 84 | }
|
72 | 85 |
|
| 86 | + // Call the original setDelegate: implementation |
73 | 87 | if (g_original_setDelegate_imp) {
|
74 | 88 | ((void (*)(id, SEL, id<UIApplicationDelegate>))g_original_setDelegate_imp)(self, _cmd, delegate);
|
75 | 89 | } else {
|
@@ -155,24 +169,29 @@ - (BOOL)application:(UIApplication *)application
|
155 | 169 | namespace firebase {
|
156 | 170 | namespace util {
|
157 | 171 |
|
158 |
| -void ForEachAppDelegateClass(void (^block)(Class)) { |
159 |
| - if (g_app_delegate_class) { |
160 |
| - NSLog(@"Firebase: ForEachAppDelegateClass executing with stored delegate class: %s.", |
161 |
| - class_getName(g_app_delegate_class)); |
162 |
| - block(g_app_delegate_class); |
163 |
| - // If the delegate is already known and we execute immediately, |
164 |
| - // any previously pending blocks should have been cleared by Firebase_setDelegate. |
165 |
| - // No need to touch g_pending_app_delegate_blocks here as they are for pre-setDelegate calls. |
166 |
| - } else { |
167 |
| - // Delegate class not yet known, try to queue the block. |
168 |
| - if (g_pending_block_count < MAX_PENDING_APP_DELEGATE_BLOCKS) { |
169 |
| - g_pending_app_delegate_blocks[g_pending_block_count] = [block copy]; |
170 |
| - g_pending_block_count++; |
171 |
| - NSLog(@"Firebase: ForEachAppDelegateClass - delegate class not yet known. Saved block for later execution (pending count: %d).", g_pending_block_count); |
172 |
| - } else { |
173 |
| - NSLog(@"Firebase Error: ForEachAppDelegateClass - pending block queue is full (max %d). Discarding new block.", MAX_PENDING_APP_DELEGATE_BLOCKS); |
174 |
| - // Block is discarded. |
| 172 | +void RunOnAppDelegate(void (^block)(Class)) { |
| 173 | + if (g_seen_delegate_classes_count > 0) { |
| 174 | + NSLog(@"Firebase: RunOnAppDelegate executing block for %d already seen delegate class(es).", |
| 175 | + g_seen_delegate_classes_count); |
| 176 | + for (int i = 0; i < g_seen_delegate_classes_count; i++) { |
| 177 | + // Assuming classes in g_seen_delegate_classes up to count are non-nil |
| 178 | + if (g_seen_delegate_classes[i]) { // Additional safety check |
| 179 | + block(g_seen_delegate_classes[i]); |
| 180 | + } |
175 | 181 | }
|
| 182 | + } else { |
| 183 | + NSLog(@"Firebase: RunOnAppDelegate - no delegate classes seen yet. Block will be queued for future delegates."); |
| 184 | + } |
| 185 | + |
| 186 | + // Always try to queue the block for any future new delegate classes. |
| 187 | + // This block will be executed by Firebase_setDelegate if a new delegate class is set. |
| 188 | + if (g_pending_block_count < MAX_PENDING_APP_DELEGATE_BLOCKS) { |
| 189 | + g_pending_app_delegate_blocks[g_pending_block_count] = [block copy]; |
| 190 | + g_pending_block_count++; |
| 191 | + NSLog(@"Firebase: RunOnAppDelegate - added block to pending list (total pending: %d). This block will run on future new delegate classes.", g_pending_block_count); |
| 192 | + } else { |
| 193 | + NSLog(@"Firebase Error: RunOnAppDelegate - pending block queue is full (max %d). Cannot add new block for future execution. Discarding block.", MAX_PENDING_APP_DELEGATE_BLOCKS); |
| 194 | + // Block is discarded for future execution. |
176 | 195 | }
|
177 | 196 | }
|
178 | 197 |
|
|
0 commit comments