Added lightweight generic annotations

Summary: public

Added lightweight genarics annotations to make the code more readable and help the compiler catch bugs.

Fixed some type bugs and improved bridge validation in a few places.

Reviewed By: javache

Differential Revision: D2600189

fb-gh-sync-id: f81e22f2cdc107bf8d0b15deec6d5b83aacc5b56
This commit is contained in:
Nick Lockwood
2015-11-03 14:45:46 -08:00
committed by facebook-github-bot-7
parent 31565781f2
commit c5b990f65f
78 changed files with 497 additions and 422 deletions

View File

@@ -10,6 +10,7 @@
#import "RCTAlertManager.h"
#import "RCTAssert.h"
#import "RCTConvert.h"
#import "RCTLog.h"
#import "RCTUtils.h"
@@ -19,10 +20,10 @@
@implementation RCTAlertManager
{
NSMutableArray *_alerts;
NSMutableArray *_alertControllers;
NSMutableArray *_alertCallbacks;
NSMutableArray *_alertButtonKeys;
NSMutableArray<UIAlertView *> *_alerts;
NSMutableArray<UIAlertController *> *_alertControllers;
NSMutableArray<RCTResponseSenderBlock> *_alertCallbacks;
NSMutableArray<NSArray<NSString *> *> *_alertButtonKeys;
}
RCT_EXPORT_MODULE()
@@ -70,10 +71,10 @@ RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
callback:(RCTResponseSenderBlock)callback)
{
NSString *title = args[@"title"];
NSString *message = args[@"message"];
NSString *type = args[@"type"];
NSArray *buttons = args[@"buttons"];
NSString *title = [RCTConvert NSString:args[@"title"]];
NSString *message = [RCTConvert NSString:args[@"message"]];
NSString *type = [RCTConvert NSString:args[@"type"]];
NSDictionaryArray *buttons = [RCTConvert NSDictionaryArray:args[@"buttons"]];
BOOL allowsTextInput = [type isEqual:@"plain-text"];
if (!title && !message) {
@@ -95,9 +96,11 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
if ([UIAlertController class] == nil) {
UIAlertView *alertView = RCTAlertView(title, nil, self, nil, nil);
NSMutableArray *buttonKeys = [[NSMutableArray alloc] initWithCapacity:buttons.count];
NSMutableArray<NSString *> *buttonKeys = [[NSMutableArray alloc] initWithCapacity:buttons.count];
if (allowsTextInput) {
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
@@ -126,8 +129,11 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
[_alertButtonKeys addObject:buttonKeys];
[alertView show];
} else
#endif
{
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:title
@@ -152,7 +158,7 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
UITextField *textField = allowsTextInput ? alertController.textFields.firstObject : nil;
[alertController addAction:[UIAlertAction actionWithTitle:buttonTitle
style:buttonStyle
handler:^(UIAlertAction *action) {
handler:^(__unused UIAlertAction *action) {
if (callback) {
if (allowsTextInput) {
callback(@[buttonKey, textField.text]);
@@ -175,17 +181,14 @@ RCT_EXPORT_METHOD(alertWithArgs:(NSDictionary *)args
RCTAssert(index != NSNotFound, @"Dismissed alert was not recognised");
RCTResponseSenderBlock callback = _alertCallbacks[index];
NSArray *buttonKeys = _alertButtonKeys[index];
NSArray *args;
NSArray<NSString *> *buttonKeys = _alertButtonKeys[index];
if (alertView.alertViewStyle == UIAlertViewStylePlainTextInput) {
args = @[buttonKeys[buttonIndex], [alertView textFieldAtIndex:0].text];
callback(@[buttonKeys[buttonIndex], [alertView textFieldAtIndex:0].text]);
} else {
args = @[buttonKeys[buttonIndex]];
callback(@[buttonKeys[buttonIndex]]);
}
callback(args);
[_alerts removeObjectAtIndex:index];
[_alertCallbacks removeObjectAtIndex:index];
[_alertButtonKeys removeObjectAtIndex:index];

View File

@@ -27,11 +27,8 @@
@property (nonatomic, readonly, getter=isValid) BOOL valid;
- (void)multiGet:(NSArray *)keys callback:(RCTResponseSenderBlock)callback;
- (void)multiSet:(NSArray *)kvPairs callback:(RCTResponseSenderBlock)callback;
- (void)multiRemove:(NSArray *)keys callback:(RCTResponseSenderBlock)callback;
- (void)clear:(RCTResponseSenderBlock)callback;
- (void)getAllKeys:(RCTResponseSenderBlock)callback;
// Clear the RCTAsyncLocalStorage data from native code
- (void)clearAllData;
// For clearing data when the bridge may not exist, e.g. when logging out.
+ (void)clearAllData;

View File

@@ -14,6 +14,7 @@
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonDigest.h>
#import "RCTConvert.h"
#import "RCTLog.h"
#import "RCTUtils.h"
@@ -23,7 +24,7 @@ static const NSUInteger RCTInlineValueThreshold = 100;
#pragma mark - Static helper functions
static id RCTErrorForKey(NSString *key)
static NSDictionary *RCTErrorForKey(NSString *key)
{
if (![key isKindOfClass:[NSString class]]) {
return RCTMakeAndLogError(@"Invalid key - must be a string. Key: ", key, @{@"key": key});
@@ -34,7 +35,7 @@ static id RCTErrorForKey(NSString *key)
}
}
static void RCTAppendError(id error, NSMutableArray **errors)
static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> **errors)
{
if (error && errors) {
if (!*errors) {
@@ -44,7 +45,7 @@ static void RCTAppendError(id error, NSMutableArray **errors)
}
}
static id RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut)
static NSString *RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut)
{
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSError *error;
@@ -148,6 +149,14 @@ RCT_EXPORT_MODULE()
return RCTGetMethodQueue();
}
- (void)clearAllData
{
dispatch_async(RCTGetMethodQueue(), ^{
_manifest = [NSMutableDictionary new];
RCTDeleteStorageDirectory();
});
}
+ (void)clearAllData
{
dispatch_async(RCTGetMethodQueue(), ^{
@@ -181,7 +190,7 @@ RCT_EXPORT_MODULE()
return [RCTGetStorageDirectory() stringByAppendingPathComponent:safeFileName];
}
- (id)_ensureSetup
- (NSDictionary *)_ensureSetup
{
RCTAssertThread(RCTGetMethodQueue(), @"Must be executed on storage thread");
@@ -199,7 +208,7 @@ RCT_EXPORT_MODULE()
if (!_haveSetup) {
NSDictionary *errorOut;
NSString *serialized = RCTReadFile(RCTGetManifestFilePath(), nil, &errorOut);
_manifest = serialized ? [RCTJSONParse(serialized, &error) mutableCopy] : [NSMutableDictionary new];
_manifest = serialized ? RCTJSONParseMutable(serialized, &error) : [NSMutableDictionary new];
if (error) {
RCTLogWarn(@"Failed to parse manifest - creating new one.\n\n%@", error);
_manifest = [NSMutableDictionary new];
@@ -209,12 +218,12 @@ RCT_EXPORT_MODULE()
return nil;
}
- (id)_writeManifest:(NSMutableArray **)errors
- (NSDictionary *)_writeManifest:(NSMutableArray<NSDictionary *> **)errors
{
NSError *error;
NSString *serialized = RCTJSONStringify(_manifest, &error);
[serialized writeToFile:RCTGetManifestFilePath() atomically:YES encoding:NSUTF8StringEncoding error:&error];
id errorOut;
NSDictionary *errorOut;
if (error) {
errorOut = RCTMakeError(@"Failed to write manifest file.", error, nil);
RCTAppendError(errorOut, errors);
@@ -222,20 +231,21 @@ RCT_EXPORT_MODULE()
return errorOut;
}
- (id)_appendItemForKey:(NSString *)key toArray:(NSMutableArray *)result
- (NSDictionary *)_appendItemForKey:(NSString *)key
toArray:(NSMutableArray<NSArray<NSString *> *> *)result
{
id errorOut = RCTErrorForKey(key);
NSDictionary *errorOut = RCTErrorForKey(key);
if (errorOut) {
return errorOut;
}
id value = [self _getValueForKey:key errorOut:&errorOut];
NSString *value = [self _getValueForKey:key errorOut:&errorOut];
[result addObject:@[key, RCTNullIfNil(value)]]; // Insert null if missing or failure.
return errorOut;
}
- (NSString *)_getValueForKey:(NSString *)key errorOut:(NSDictionary **)errorOut
{
id value = _manifest[key]; // nil means missing, null means there is a data file, anything else is an inline value.
id value = _manifest[key]; // nil means missing, null means there is a data file, else: NSString
if (value == (id)kCFNull) {
NSString *filePath = [self _filePathForKey:key];
value = RCTReadFile(filePath, key, errorOut);
@@ -243,16 +253,13 @@ RCT_EXPORT_MODULE()
return value;
}
- (id)_writeEntry:(NSArray *)entry
- (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry
{
if (![entry isKindOfClass:[NSArray class]] || entry.count != 2) {
if (entry.count != 2) {
return RCTMakeAndLogError(@"Entries must be arrays of the form [key: string, value: string], got: ", entry, nil);
}
if (![entry[1] isKindOfClass:[NSString class]]) {
return RCTMakeAndLogError(@"Values must be strings, got: ", entry[1], @{@"key": entry[0]});
}
NSString *key = entry[0];
id errorOut = RCTErrorForKey(key);
NSDictionary *errorOut = RCTErrorForKey(key);
if (errorOut) {
return errorOut;
}
@@ -278,66 +285,63 @@ RCT_EXPORT_MODULE()
#pragma mark - Exported JS Functions
RCT_EXPORT_METHOD(multiGet:(NSArray *)keys
RCT_EXPORT_METHOD(multiGet:(NSStringArray *)keys
callback:(RCTResponseSenderBlock)callback)
{
if (!callback) {
RCTLogError(@"Called getItem without a callback.");
return;
}
id errorOut = [self _ensureSetup];
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[@[errorOut], (id)kCFNull]);
return;
}
NSMutableArray *errors;
NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:keys.count];
NSMutableArray<NSDictionary *> *errors;
NSMutableArray<NSArray<NSString *> *> *result = [[NSMutableArray alloc] initWithCapacity:keys.count];
for (NSString *key in keys) {
id keyError = [self _appendItemForKey:key toArray:result];
NSDictionary *keyError = [self _appendItemForKey:key toArray:result];
RCTAppendError(keyError, &errors);
}
callback(@[RCTNullIfNil(errors), result]);
}
RCT_EXPORT_METHOD(multiSet:(NSArray *)kvPairs
RCT_EXPORT_METHOD(multiSet:(NSStringArrayArray *)kvPairs
callback:(RCTResponseSenderBlock)callback)
{
id errorOut = [self _ensureSetup];
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[@[errorOut]]);
return;
}
NSMutableArray *errors;
for (NSArray *entry in kvPairs) {
id keyError = [self _writeEntry:entry];
NSMutableArray<NSDictionary *> *errors;
for (NSArray<NSString *> *entry in kvPairs) {
NSDictionary *keyError = [self _writeEntry:entry];
RCTAppendError(keyError, &errors);
}
[self _writeManifest:&errors];
if (callback) {
callback(@[RCTNullIfNil(errors)]);
}
callback(@[RCTNullIfNil(errors)]);
}
RCT_EXPORT_METHOD(multiMerge:(NSArray *)kvPairs
callback:(RCTResponseSenderBlock)callback)
RCT_EXPORT_METHOD(multiMerge:(NSStringArrayArray *)kvPairs
callback:(RCTResponseSenderBlock)callback)
{
id errorOut = [self _ensureSetup];
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[@[errorOut]]);
return;
}
NSMutableArray *errors;
for (__strong NSArray *entry in kvPairs) {
id keyError;
NSMutableArray<NSDictionary *> *errors;
for (__strong NSArray<NSString *> *entry in kvPairs) {
NSDictionary *keyError;
NSString *value = [self _getValueForKey:entry[0] errorOut:&keyError];
if (keyError) {
RCTAppendError(keyError, &errors);
} else {
if (value) {
NSMutableDictionary *mergedVal = [RCTJSONParseMutable(value, &keyError) mutableCopy];
RCTMergeRecursive(mergedVal, RCTJSONParse(entry[1], &keyError));
entry = @[entry[0], RCTJSONStringify(mergedVal, &keyError)];
NSError *jsonError;
NSMutableDictionary *mergedVal = RCTJSONParseMutable(value, &jsonError);
RCTMergeRecursive(mergedVal, RCTJSONParse(entry[1], &jsonError));
entry = @[entry[0], RCTNullIfNil(RCTJSONStringify(mergedVal, NULL))];
if (jsonError) {
keyError = RCTJSErrorFromNSError(jsonError);
}
}
if (!keyError) {
keyError = [self _writeEntry:entry];
@@ -346,22 +350,20 @@ RCT_EXPORT_METHOD(multiMerge:(NSArray *)kvPairs
}
}
[self _writeManifest:&errors];
if (callback) {
callback(@[RCTNullIfNil(errors)]);
}
callback(@[RCTNullIfNil(errors)]);
}
RCT_EXPORT_METHOD(multiRemove:(NSArray *)keys
RCT_EXPORT_METHOD(multiRemove:(NSStringArray *)keys
callback:(RCTResponseSenderBlock)callback)
{
id errorOut = [self _ensureSetup];
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[@[errorOut]]);
return;
}
NSMutableArray *errors;
NSMutableArray<NSDictionary *> *errors;
for (NSString *key in keys) {
id keyError = RCTErrorForKey(key);
NSDictionary *keyError = RCTErrorForKey(key);
if (!keyError) {
NSString *filePath = [self _filePathForKey:key];
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
@@ -370,23 +372,19 @@ RCT_EXPORT_METHOD(multiRemove:(NSArray *)keys
RCTAppendError(keyError, &errors);
}
[self _writeManifest:&errors];
if (callback) {
callback(@[RCTNullIfNil(errors)]);
}
callback(@[RCTNullIfNil(errors)]);
}
RCT_EXPORT_METHOD(clear:(RCTResponseSenderBlock)callback)
{
_manifest = [NSMutableDictionary new];
NSError *error = RCTDeleteStorageDirectory();
if (callback) {
callback(@[RCTNullIfNil(error)]);
}
callback(@[RCTNullIfNil(error)]);
}
RCT_EXPORT_METHOD(getAllKeys:(RCTResponseSenderBlock)callback)
{
id errorOut = [self _ensureSetup];
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[errorOut, (id)kCFNull]);
} else {

View File

@@ -138,8 +138,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
NSURLSessionDataTask *_updateTask;
NSURL *_liveReloadURL;
BOOL _jsLoaded;
NSArray *_presentedItems;
NSMutableArray *_extraMenuItems;
NSArray<RCTDevMenuItem *> *_presentedItems;
NSMutableArray<RCTDevMenuItem *> *_extraMenuItems;
}
@synthesize bridge = _bridge;
@@ -375,9 +375,9 @@ RCT_EXPORT_MODULE()
[self settingsDidChange];
}
- (NSArray *)menuItems
- (NSArray<RCTDevMenuItem *> *)menuItems
{
NSMutableArray *items = [NSMutableArray new];
NSMutableArray<RCTDevMenuItem *> *items = [NSMutableArray new];
// Add built-in items
@@ -435,7 +435,7 @@ RCT_EXPORT_METHOD(show)
actionSheet.title = @"React Native: Development";
actionSheet.delegate = self;
NSArray *items = [self menuItems];
NSArray<RCTDevMenuItem *> *items = [self menuItems];
for (RCTDevMenuItem *item in items) {
switch (item.type) {
case RCTDevMenuTypeButton: {

View File

@@ -15,13 +15,14 @@
// NOTE: Remove these three methods and the @optional directive after updating the codebase to use only the three below
@optional
- (void)handleSoftJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack;
- (void)handleFatalJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack;
- (void)updateJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack;
- (void)handleSoftJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack exceptionId:(NSNumber *)exceptionId;
- (void)handleFatalJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack exceptionId:(NSNumber *)exceptionId;
- (void)updateJSExceptionWithMessage:(NSString *)message stack:(NSArray *)stack exceptionId:(NSNumber *)exceptionId;
- (void)handleSoftJSExceptionWithMessage:(NSString *)message stack:(NSArray<NSDictionary *> *)stack;
- (void)handleFatalJSExceptionWithMessage:(NSString *)message stack:(NSArray<NSDictionary *> *)stack;
- (void)updateJSExceptionWithMessage:(NSString *)message stack:(NSArray<NSDictionary *> *)stack;
- (void)handleSoftJSExceptionWithMessage:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId;
- (void)handleFatalJSExceptionWithMessage:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId;
- (void)updateJSExceptionWithMessage:(NSString *)message stack:(NSArray<NSDictionary *> *)stack exceptionId:(NSNumber *)exceptionId;
@end

View File

@@ -9,6 +9,7 @@
#import "RCTExceptionsManager.h"
#import "RCTConvert.h"
#import "RCTDefines.h"
#import "RCTLog.h"
#import "RCTRedBox.h"
@@ -39,7 +40,7 @@ RCT_EXPORT_MODULE()
}
RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
stack:(NSArray *)stack
stack:(NSDictionaryArray *)stack
exceptionId:(nonnull NSNumber *)exceptionId)
{
// TODO(#7070533): report a soft error to the server
@@ -55,7 +56,7 @@ RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
}
RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
stack:(NSArray *)stack
stack:(NSDictionaryArray *)stack
exceptionId:(nonnull NSNumber *)exceptionId)
{
if (_delegate) {
@@ -98,7 +99,7 @@ RCT_EXPORT_METHOD(reportFatalException:(NSString *)message
}
RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message
stack:(NSArray *)stack
stack:(NSDictionaryArray *)stack
exceptionId:(nonnull NSNumber *)exceptionId)
{
if (_delegate) {
@@ -115,7 +116,7 @@ RCT_EXPORT_METHOD(updateExceptionMessage:(NSString *)message
// Deprecated. Use reportFatalException directly instead.
RCT_EXPORT_METHOD(reportUnhandledException:(NSString *)message
stack:(NSArray *)stack)
stack:(NSDictionaryArray *)stack)
{
[self reportFatalException:message stack:stack exceptionId:@-1];
}

View File

@@ -17,8 +17,8 @@
- (void)showError:(NSError *)error;
- (void)showErrorMessage:(NSString *)message;
- (void)showErrorMessage:(NSString *)message withDetails:(NSString *)details;
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack;
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray *)stack;
- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack;
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack;
- (void)dismiss;

View File

@@ -23,7 +23,7 @@
{
UITableView *_stackTraceTableView;
NSString *_lastErrorMessage;
NSArray *_lastStackTrace;
NSArray<NSDictionary *> *_lastStackTrace;
}
- (instancetype)initWithFrame:(CGRect)frame
@@ -103,7 +103,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
[[[NSURLSession sharedSession] dataTaskWithRequest:request] resume];
}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack showIfHidden:(BOOL)shouldShow
- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack showIfHidden:(BOOL)shouldShow
{
if ((self.hidden && shouldShow) || (!self.hidden && [_lastErrorMessage isEqualToString:message])) {
_lastStackTrace = stack;
@@ -225,7 +225,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
#pragma mark - Key commands
- (NSArray *)keyCommands
- (NSArray<UIKeyCommand *> *)keyCommands
{
// NOTE: We could use RCTKeyCommands for this, but since
// we control this window, we can use the standard, non-hacky
@@ -281,17 +281,17 @@ RCT_EXPORT_MODULE()
[self showErrorMessage:combinedMessage];
}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack
- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack
{
[self showErrorMessage:message withStack:stack showIfHidden:YES];
}
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray *)stack
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack
{
[self showErrorMessage:message withStack:stack showIfHidden:NO];
}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack showIfHidden:(BOOL)shouldShow
- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack showIfHidden:(BOOL)shouldShow
{
dispatch_async(dispatch_get_main_queue(), ^{
if (!_window) {
@@ -332,9 +332,9 @@ RCT_EXPORT_MODULE()
- (void)showError:(NSError *)message {}
- (void)showErrorMessage:(NSString *)message {}
- (void)showErrorMessage:(NSString *)message withDetails:(NSString *)details {}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack {}
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray *)stack {}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack showIfHidden:(BOOL)shouldShow {}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack {}
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack {}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray<NSDictionary *> *)stack showIfHidden:(BOOL)shouldShow {}
- (void)dismiss {}
@end

View File

@@ -145,7 +145,7 @@ RCT_EXPORT_MODULE()
- (void)didUpdateFrame:(__unused RCTFrameUpdate *)update
{
NSMutableArray *timersToCall = [NSMutableArray new];
NSMutableArray<NSNumber *> *timersToCall = [NSMutableArray new];
for (RCTTimer *timer in _timers.allObjects) {
if ([timer updateFoundNeedsJSUpdate]) {
[timersToCall addObject:timer.callbackID];

View File

@@ -191,8 +191,8 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim
dispatch_queue_t _shadowQueue;
// Root views are only mutated on the shadow queue
NSMutableSet *_rootViewTags;
NSMutableArray *_pendingUIBlocks;
NSMutableSet<NSNumber *> *_rootViewTags;
NSMutableArray<dispatch_block_t> *_pendingUIBlocks;
// Animation
RCTLayoutAnimation *_nextLayoutAnimation; // RCT thread only
@@ -201,7 +201,7 @@ static UIViewAnimationOptions UIViewAnimationOptionsFromRCTAnimationType(RCTAnim
// Keyed by viewName
NSDictionary *_componentDataByName;
NSMutableSet *_bridgeTransactionListeners;
NSMutableSet<id<RCTComponent>> *_bridgeTransactionListeners;
}
@synthesize bridge = _bridge;
@@ -396,7 +396,8 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
/**
* Unregisters views from registries
*/
- (void)_purgeChildren:(NSArray *)children fromRegistry:(RCTSparseArray *)registry
- (void)_purgeChildren:(NSArray<id<RCTComponent>> *)children
fromRegistry:(RCTSparseArray *)registry
{
for (id<RCTComponent> child in children) {
RCTTraverseViewNodes(registry[child.reactTag], ^(id<RCTComponent> subview) {
@@ -442,7 +443,7 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
{
RCTAssert(![NSThread isMainThread], @"Should be called on shadow thread");
NSMutableSet *viewsWithNewFrames = [NSMutableSet setWithCapacity:1];
NSMutableSet<RCTShadowView *> *viewsWithNewFrames = [NSMutableSet setWithCapacity:1];
// This is nuanced. In the JS thread, we create a new update buffer
// `frameTags`/`frames` that is created/mutated in the JS thread. We access
@@ -452,10 +453,14 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
[rootShadowView collectRootUpdatedFrames:viewsWithNewFrames];
// Parallel arrays are built and then handed off to main thread
NSMutableArray *frameReactTags = [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray *frames = [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray *areNew = [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray *parentsAreNew = [NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray<NSNumber *> *frameReactTags =
[NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray<NSValue *> *frames =
[NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray<NSNumber *> *areNew =
[NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
NSMutableArray<NSNumber *> *parentsAreNew =
[NSMutableArray arrayWithCapacity:viewsWithNewFrames.count];
for (RCTShadowView *shadowView in viewsWithNewFrames) {
[frameReactTags addObject:shadowView.reactTag];
@@ -473,7 +478,7 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
// reactSetFrame: has been called. Note that if reactSetFrame: is not called,
// these won't be called either, so this is not a suitable place to update
// properties that aren't related to layout.
NSMutableArray *updateBlocks = [NSMutableArray new];
NSMutableArray<RCTViewManagerUIBlock> *updateBlocks = [NSMutableArray new];
for (RCTShadowView *shadowView in viewsWithNewFrames) {
RCTViewManager *manager = [_componentDataByName[shadowView.viewName] manager];
RCTViewManagerUIBlock block = [manager uiBlockToAmendWithShadowView:shadowView];
@@ -583,7 +588,7 @@ extern NSString *RCTBridgeModuleNameForClass(Class cls);
- (void)_amendPendingUIBlocksWithStylePropagationUpdateForRootView:(RCTShadowView *)topView
{
NSMutableSet *applierBlocks = [NSMutableSet setWithCapacity:1];
NSMutableSet<RCTApplierBlock> *applierBlocks = [NSMutableSet setWithCapacity:1];
[topView collectUpdatedProperties:applierBlocks parentProperties:@{}];
if (applierBlocks.count) {
@@ -605,7 +610,7 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(nonnull NSNumber *)containe
RCTAssert(container != nil, @"container view (for ID %@) not found", containerID);
NSUInteger subviewsCount = [container reactSubviews].count;
NSMutableArray *indices = [[NSMutableArray alloc] initWithCapacity:subviewsCount];
NSMutableArray<NSNumber *> *indices = [[NSMutableArray alloc] initWithCapacity:subviewsCount];
for (NSUInteger childIndex = 0; childIndex < subviewsCount; childIndex++) {
[indices addObject:@(childIndex)];
}
@@ -624,8 +629,8 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(nonnull NSNumber *)containe
*
* @returns Array of removed items.
*/
- (NSArray *)_childrenToRemoveFromContainer:(id<RCTComponent>)container
atIndices:(NSArray *)atIndices
- (NSArray<id<RCTComponent>> *)_childrenToRemoveFromContainer:(id<RCTComponent>)container
atIndices:(NSArray<NSNumber *> *)atIndices
{
// If there are no indices to move or the container has no subviews don't bother
// We support parents with nil subviews so long as they're all nil so this allows for this behavior
@@ -633,7 +638,7 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(nonnull NSNumber *)containe
return nil;
}
// Construction of removed children must be done "up front", before indices are disturbed by removals.
NSMutableArray *removedChildren = [NSMutableArray arrayWithCapacity:atIndices.count];
NSMutableArray<id<RCTComponent>> *removedChildren = [NSMutableArray arrayWithCapacity:atIndices.count];
RCTAssert(container != nil, @"container view (for ID %@) not found", container);
for (NSNumber *indexNumber in atIndices) {
NSUInteger index = indexNumber.unsignedIntegerValue;
@@ -648,9 +653,10 @@ RCT_EXPORT_METHOD(removeSubviewsFromContainerWithID:(nonnull NSNumber *)containe
return removedChildren;
}
- (void)_removeChildren:(NSArray *)children fromContainer:(id<RCTComponent>)container
- (void)_removeChildren:(NSArray<id<RCTComponent>> *)children
fromContainer:(id<RCTComponent>)container
{
for (id removedChild in children) {
for (id<RCTComponent> removedChild in children) {
[container removeReactSubview:removedChild];
}
}
@@ -659,14 +665,14 @@ RCT_EXPORT_METHOD(removeRootView:(nonnull NSNumber *)rootReactTag)
{
RCTShadowView *rootShadowView = _shadowViewRegistry[rootReactTag];
RCTAssert(rootShadowView.superview == nil, @"root view cannot have superview (ID %@)", rootReactTag);
[self _purgeChildren:rootShadowView.reactSubviews fromRegistry:_shadowViewRegistry];
[self _purgeChildren:(NSArray<id<RCTComponent>> *)rootShadowView.reactSubviews fromRegistry:_shadowViewRegistry];
_shadowViewRegistry[rootReactTag] = nil;
[_rootViewTags removeObject:rootReactTag];
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
RCTAssertMainThread();
UIView *rootView = viewRegistry[rootReactTag];
[uiManager _purgeChildren:rootView.reactSubviews fromRegistry:viewRegistry];
[uiManager _purgeChildren:(NSArray<id<RCTComponent>> *)rootView.reactSubviews fromRegistry:viewRegistry];
viewRegistry[rootReactTag] = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUIManagerDidRemoveRootViewNotification
@@ -675,7 +681,8 @@ RCT_EXPORT_METHOD(removeRootView:(nonnull NSNumber *)rootReactTag)
}];
}
RCT_EXPORT_METHOD(replaceExistingNonRootView:(nonnull NSNumber *)reactTag withView:(nonnull NSNumber *)newReactTag)
RCT_EXPORT_METHOD(replaceExistingNonRootView:(nonnull NSNumber *)reactTag
withView:(nonnull NSNumber *)newReactTag)
{
RCTShadowView *shadowView = _shadowViewRegistry[reactTag];
RCTAssert(shadowView != nil, @"shadowView (for ID %@) not found", reactTag);
@@ -685,8 +692,8 @@ RCT_EXPORT_METHOD(replaceExistingNonRootView:(nonnull NSNumber *)reactTag withVi
NSUInteger indexOfView = [superShadowView.reactSubviews indexOfObject:shadowView];
RCTAssert(indexOfView != NSNotFound, @"View's superview doesn't claim it as subview (id %@)", reactTag);
NSArray *removeAtIndices = @[@(indexOfView)];
NSArray *addTags = @[newReactTag];
NSArray<NSNumber *> *removeAtIndices = @[@(indexOfView)];
NSArray<NSNumber *> *addTags = @[newReactTag];
[self manageChildren:superShadowView.reactTag
moveFromIndices:nil
moveToIndices:nil
@@ -696,11 +703,11 @@ RCT_EXPORT_METHOD(replaceExistingNonRootView:(nonnull NSNumber *)reactTag withVi
}
RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
moveFromIndices:(NSArray *)moveFromIndices
moveToIndices:(NSArray *)moveToIndices
addChildReactTags:(NSArray *)addChildReactTags
addAtIndices:(NSArray *)addAtIndices
removeAtIndices:(NSArray *)removeAtIndices)
moveFromIndices:(NSNumberArray *)moveFromIndices
moveToIndices:(NSNumberArray *)moveToIndices
addChildReactTags:(NSNumberArray *)addChildReactTags
addAtIndices:(NSNumberArray *)addAtIndices
removeAtIndices:(NSNumberArray *)removeAtIndices)
{
[self _manageChildren:containerReactTag
moveFromIndices:moveFromIndices
@@ -722,11 +729,11 @@ RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
}
- (void)_manageChildren:(NSNumber *)containerReactTag
moveFromIndices:(NSArray *)moveFromIndices
moveToIndices:(NSArray *)moveToIndices
addChildReactTags:(NSArray *)addChildReactTags
addAtIndices:(NSArray *)addAtIndices
removeAtIndices:(NSArray *)removeAtIndices
moveFromIndices:(NSArray<NSNumber *> *)moveFromIndices
moveToIndices:(NSArray<NSNumber *> *)moveToIndices
addChildReactTags:(NSArray<NSNumber *> *)addChildReactTags
addAtIndices:(NSArray<NSNumber *> *)addAtIndices
removeAtIndices:(NSArray<NSNumber *> *)removeAtIndices
registry:(RCTSparseArray *)registry
{
id<RCTComponent> container = registry[containerReactTag];
@@ -734,8 +741,10 @@ RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
RCTAssert(addChildReactTags.count == addAtIndices.count, @"there should be at least one React child to add");
// Removes (both permanent and temporary moves) are using "before" indices
NSArray *permanentlyRemovedChildren = [self _childrenToRemoveFromContainer:container atIndices:removeAtIndices];
NSArray *temporarilyRemovedChildren = [self _childrenToRemoveFromContainer:container atIndices:moveFromIndices];
NSArray<id<RCTComponent>> *permanentlyRemovedChildren =
[self _childrenToRemoveFromContainer:container atIndices:removeAtIndices];
NSArray<id<RCTComponent>> *temporarilyRemovedChildren =
[self _childrenToRemoveFromContainer:container atIndices:moveFromIndices];
[self _removeChildren:permanentlyRemovedChildren fromContainer:container];
[self _removeChildren:temporarilyRemovedChildren fromContainer:container];
@@ -749,15 +758,17 @@ RCT_EXPORT_METHOD(manageChildren:(nonnull NSNumber *)containerReactTag
destinationsToChildrenToAdd[moveToIndices[index]] = temporarilyRemovedChildren[index];
}
for (NSInteger index = 0, length = addAtIndices.count; index < length; index++) {
id view = registry[addChildReactTags[index]];
id<RCTComponent> view = registry[addChildReactTags[index]];
if (view) {
destinationsToChildrenToAdd[addAtIndices[index]] = view;
}
}
NSArray *sortedIndices = [destinationsToChildrenToAdd.allKeys sortedArrayUsingSelector:@selector(compare:)];
NSArray<NSNumber *> *sortedIndices =
[destinationsToChildrenToAdd.allKeys sortedArrayUsingSelector:@selector(compare:)];
for (NSNumber *reactIndex in sortedIndices) {
[container insertReactSubview:destinationsToChildrenToAdd[reactIndex] atIndex:reactIndex.integerValue];
[container insertReactSubview:destinationsToChildrenToAdd[reactIndex]
atIndex:reactIndex.integerValue];
}
}
@@ -894,7 +905,7 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po
// First copy the previous blocks into a temporary variable, then reset the
// pending blocks to a new array. This guards against mutation while
// processing the pending blocks in another thread.
NSArray *previousPendingUIBlocks = _pendingUIBlocks;
NSArray<dispatch_block_t> *previousPendingUIBlocks = _pendingUIBlocks;
_pendingUIBlocks = [NSMutableArray new];
if (previousPendingUIBlocks.count) {
@@ -1036,8 +1047,9 @@ RCT_EXPORT_METHOD(measureViewsInRect:(CGRect)rect
RCTLogError(@"Attempting to measure view that does not exist (tag #%@)", reactTag);
return;
}
NSArray *childShadowViews = [shadowView reactSubviews];
NSMutableArray *results = [[NSMutableArray alloc] initWithCapacity:childShadowViews.count];
NSArray<RCTShadowView *> *childShadowViews = [shadowView reactSubviews];
NSMutableArray<NSDictionary *> *results =
[[NSMutableArray alloc] initWithCapacity:childShadowViews.count];
[childShadowViews enumerateObjectsUsingBlock:
^(RCTShadowView *childShadowView, NSUInteger idx, __unused BOOL *stop) {