Skip to content

Commit ead0f2e

Browse files
committed
Implemented thread control for exported methods
1 parent 2b9aaac commit ead0f2e

23 files changed

Lines changed: 383 additions & 402 deletions
-1.22 KB
Loading

Examples/UIExplorer/UIExplorerTests/UIExplorerTests.m

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,10 @@ - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
5959
return NO;
6060
}
6161

62-
// Make sure this test runs first (underscores sort early) otherwise the
63-
// other tests will tear out the rootView
64-
- (void)test__RootViewLoadsAndRenders
62+
// Make sure this test runs first because the other tests will tear out the rootView
63+
- (void)testAAA_RootViewLoadsAndRenders
6564
{
66-
UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
65+
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
6766
RCTAssert([vc.view isKindOfClass:[RCTRootView class]], @"This test must run first.");
6867
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
6968
BOOL foundElement = NO;
@@ -72,10 +71,8 @@ - (void)test__RootViewLoadsAndRenders
7271
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
7372
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
7473
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:date];
75-
7674
redboxError = [[RCTRedBox sharedInstance] currentErrorMessage];
77-
78-
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
75+
foundElement = [self findSubviewInView:vc.view matching:^(UIView *view) {
7976
if ([view respondsToSelector:@selector(attributedText)]) {
8077
NSString *text = [(id)view attributedText].string;
8178
if ([text isEqualToString:@"<View>"]) {
@@ -120,6 +117,7 @@ - (void)testTabBarExampleSnapshot
120117
[_runner runTest:_cmd module:@"TabBarExample"];
121118
}
122119

120+
// Make sure this test runs last
123121
- (void)testZZZ_NotInRecordMode
124122
{
125123
RCTAssert(_runner.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");

Libraries/ActionSheetIOS/RCTActionSheetManager.m

Lines changed: 58 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -34,92 +34,88 @@ - (instancetype)init
3434
failureCallback:(RCTResponseSenderBlock)failureCallback
3535
successCallback:(RCTResponseSenderBlock)successCallback)
3636
{
37-
dispatch_async(dispatch_get_main_queue(), ^{
38-
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
37+
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
3938

40-
actionSheet.title = options[@"title"];
39+
actionSheet.title = options[@"title"];
4140

42-
for (NSString *option in options[@"options"]) {
43-
[actionSheet addButtonWithTitle:option];
44-
}
41+
for (NSString *option in options[@"options"]) {
42+
[actionSheet addButtonWithTitle:option];
43+
}
4544

46-
if (options[@"destructiveButtonIndex"]) {
47-
actionSheet.destructiveButtonIndex = [options[@"destructiveButtonIndex"] integerValue];
48-
}
49-
if (options[@"cancelButtonIndex"]) {
50-
actionSheet.cancelButtonIndex = [options[@"cancelButtonIndex"] integerValue];
51-
}
45+
if (options[@"destructiveButtonIndex"]) {
46+
actionSheet.destructiveButtonIndex = [options[@"destructiveButtonIndex"] integerValue];
47+
}
48+
if (options[@"cancelButtonIndex"]) {
49+
actionSheet.cancelButtonIndex = [options[@"cancelButtonIndex"] integerValue];
50+
}
5251

53-
actionSheet.delegate = self;
52+
actionSheet.delegate = self;
5453

55-
_callbacks[keyForInstance(actionSheet)] = successCallback;
54+
_callbacks[RCTKeyForInstance(actionSheet)] = successCallback;
5655

57-
UIWindow *appWindow = [[[UIApplication sharedApplication] delegate] window];
58-
if (appWindow == nil) {
59-
RCTLogError(@"Tried to display action sheet but there is no application window. options: %@", options);
60-
return;
61-
}
62-
[actionSheet showInView:appWindow];
63-
});
56+
UIWindow *appWindow = [[[UIApplication sharedApplication] delegate] window];
57+
if (appWindow == nil) {
58+
RCTLogError(@"Tried to display action sheet but there is no application window. options: %@", options);
59+
return;
60+
}
61+
[actionSheet showInView:appWindow];
6462
}
6563

6664
RCT_EXPORT_METHOD(showShareActionSheetWithOptions:(NSDictionary *)options
6765
failureCallback:(RCTResponseSenderBlock)failureCallback
6866
successCallback:(RCTResponseSenderBlock)successCallback)
6967
{
70-
dispatch_async(dispatch_get_main_queue(), ^{
71-
NSMutableArray *items = [NSMutableArray array];
72-
id message = options[@"message"];
73-
id url = options[@"url"];
74-
if ([message isKindOfClass:[NSString class]]) {
75-
[items addObject:message];
76-
}
77-
if ([url isKindOfClass:[NSString class]]) {
78-
[items addObject:[NSURL URLWithString:url]];
79-
}
80-
if ([items count] == 0) {
81-
failureCallback(@[@"No `url` or `message` to share"]);
82-
return;
83-
}
84-
UIActivityViewController *share = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
85-
UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
86-
if ([share respondsToSelector:@selector(setCompletionWithItemsHandler:)]) {
87-
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
88-
if (activityError) {
89-
failureCallback(@[[activityError localizedDescription]]);
90-
} else {
91-
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
92-
}
93-
};
94-
} else {
68+
NSMutableArray *items = [NSMutableArray array];
69+
id message = options[@"message"];
70+
id url = options[@"url"];
71+
if ([message isKindOfClass:[NSString class]]) {
72+
[items addObject:message];
73+
}
74+
if ([url isKindOfClass:[NSString class]]) {
75+
[items addObject:[NSURL URLWithString:url]];
76+
}
77+
if ([items count] == 0) {
78+
failureCallback(@[@"No `url` or `message` to share"]);
79+
return;
80+
}
81+
UIActivityViewController *share = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
82+
UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
83+
if ([share respondsToSelector:@selector(setCompletionWithItemsHandler:)]) {
84+
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
85+
if (activityError) {
86+
failureCallback(@[[activityError localizedDescription]]);
87+
} else {
88+
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
89+
}
90+
};
91+
} else {
9592

9693
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
9794

98-
if (![UIActivityViewController instancesRespondToSelector:@selector(completionWithItemsHandler)]) {
99-
// Legacy iOS 7 implementation
100-
share.completionHandler = ^(NSString *activityType, BOOL completed) {
101-
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
102-
};
103-
} else
95+
if (![UIActivityViewController instancesRespondToSelector:@selector(completionWithItemsHandler)]) {
96+
// Legacy iOS 7 implementation
97+
share.completionHandler = ^(NSString *activityType, BOOL completed) {
98+
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
99+
};
100+
} else
104101

105102
#endif
106103

107-
{
108-
// iOS 8 version
109-
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
110-
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
111-
};
112-
}
104+
{
105+
// iOS 8 version
106+
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
107+
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
108+
};
113109
}
114-
[ctrl presentViewController:share animated:YES completion:nil];
115-
});
110+
}
111+
[ctrl presentViewController:share animated:YES completion:nil];
116112
}
117113

118114
#pragma mark UIActionSheetDelegate Methods
119115

120116
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
121117
{
122-
NSString *key = keyForInstance(actionSheet);
118+
NSString *key = RCTKeyForInstance(actionSheet);
123119
RCTResponseSenderBlock callback = _callbacks[key];
124120
if (callback) {
125121
callback(@[@(buttonIndex)]);
@@ -133,7 +129,7 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger
133129

134130
#pragma mark Private
135131

136-
NS_INLINE NSString *keyForInstance(id instance)
132+
static NSString *RCTKeyForInstance(id instance)
137133
{
138134
return [NSString stringWithFormat:@"%p", instance];
139135
}

Libraries/Animation/RCTAnimationExperimentalManager.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ - (instancetype)init
6868
return self;
6969
}
7070

71+
- (dispatch_queue_t)methodQueue
72+
{
73+
return _bridge.uiManager.methodQueue;
74+
}
75+
7176
- (id (^)(CGFloat))interpolateFrom:(CGFloat[])fromArray to:(CGFloat[])toArray count:(NSUInteger)count typeName:(const char *)typeName
7277
{
7378
if (count == 1) {

Libraries/Geolocation/RCTLocationObserver.m

Lines changed: 59 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ typedef NS_ENUM(NSInteger, RCTPositionErrorCode) {
3333
CLLocationAccuracy accuracy;
3434
} RCTLocationOptions;
3535

36-
static RCTLocationOptions RCTLocationOptionsWithJSON(id json)
36+
@implementation RCTConvert (RCTLocationOptions)
37+
38+
+ (RCTLocationOptions)RCTLocationOptions:(id)json
3739
{
3840
NSDictionary *options = [RCTConvert NSDictionary:json];
3941
return (RCTLocationOptions){
@@ -43,6 +45,8 @@ static RCTLocationOptions RCTLocationOptionsWithJSON(id json)
4345
};
4446
}
4547

48+
@end
49+
4650
static NSDictionary *RCTPositionError(RCTPositionErrorCode code, NSString *msg /* nil for default */)
4751
{
4852
if (!msg) {
@@ -121,6 +125,7 @@ - (instancetype)init
121125
- (void)dealloc
122126
{
123127
[_locationManager stopUpdatingLocation];
128+
_locationManager.delegate = nil;
124129
}
125130

126131
#pragma mark - Private API
@@ -153,41 +158,33 @@ - (void)timeout:(NSTimer *)timer
153158

154159
#pragma mark - Public API
155160

156-
RCT_EXPORT_METHOD(startObserving:(NSDictionary *)optionsJSON)
161+
RCT_EXPORT_METHOD(startObserving:(RCTLocationOptions)options)
157162
{
158163
[self checkLocationConfig];
159164

160-
dispatch_async(dispatch_get_main_queue(), ^{
161-
162-
// Select best options
163-
_observerOptions = RCTLocationOptionsWithJSON(optionsJSON);
164-
for (RCTLocationRequest *request in _pendingRequests) {
165-
_observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
166-
}
167-
168-
_locationManager.desiredAccuracy = _observerOptions.accuracy;
169-
[self beginLocationUpdates];
170-
_observingLocation = YES;
165+
// Select best options
166+
_observerOptions = options;
167+
for (RCTLocationRequest *request in _pendingRequests) {
168+
_observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
169+
}
171170

172-
});
171+
_locationManager.desiredAccuracy = _observerOptions.accuracy;
172+
[self beginLocationUpdates];
173+
_observingLocation = YES;
173174
}
174175

175176
RCT_EXPORT_METHOD(stopObserving)
176177
{
177-
dispatch_async(dispatch_get_main_queue(), ^{
178-
179-
// Stop observing
180-
_observingLocation = NO;
178+
// Stop observing
179+
_observingLocation = NO;
181180

182-
// Stop updating if no pending requests
183-
if (_pendingRequests.count == 0) {
184-
[_locationManager stopUpdatingLocation];
185-
}
186-
187-
});
181+
// Stop updating if no pending requests
182+
if (_pendingRequests.count == 0) {
183+
[_locationManager stopUpdatingLocation];
184+
}
188185
}
189186

190-
RCT_EXPORT_METHOD(getCurrentPosition:(NSDictionary *)optionsJSON
187+
RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
191188
withSuccessCallback:(RCTResponseSenderBlock)successBlock
192189
errorCallback:(RCTResponseSenderBlock)errorBlock)
193190
{
@@ -198,56 +195,49 @@ - (void)timeout:(NSTimer *)timer
198195
return;
199196
}
200197

201-
dispatch_async(dispatch_get_main_queue(), ^{
202-
203-
if (![CLLocationManager locationServicesEnabled]) {
204-
if (errorBlock) {
205-
errorBlock(@[
206-
RCTPositionError(RCTPositionErrorUnavailable, @"Location services disabled.")
207-
]);
208-
return;
209-
}
198+
if (![CLLocationManager locationServicesEnabled]) {
199+
if (errorBlock) {
200+
errorBlock(@[
201+
RCTPositionError(RCTPositionErrorUnavailable, @"Location services disabled.")
202+
]);
203+
return;
210204
}
205+
}
211206

212-
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
213-
if (errorBlock) {
214-
errorBlock(@[
215-
RCTPositionError(RCTPositionErrorDenied, nil)
216-
]);
217-
return;
218-
}
207+
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
208+
if (errorBlock) {
209+
errorBlock(@[
210+
RCTPositionError(RCTPositionErrorDenied, nil)
211+
]);
212+
return;
219213
}
214+
}
220215

221-
// Get options
222-
RCTLocationOptions options = RCTLocationOptionsWithJSON(optionsJSON);
223-
224-
// Check if previous recorded location exists and is good enough
225-
if (_lastLocationEvent &&
226-
CFAbsoluteTimeGetCurrent() - [RCTConvert NSTimeInterval:_lastLocationEvent[@"timestamp"]] < options.maximumAge &&
227-
[_lastLocationEvent[@"coords"][@"accuracy"] doubleValue] >= options.accuracy) {
216+
// Check if previous recorded location exists and is good enough
217+
if (_lastLocationEvent &&
218+
CFAbsoluteTimeGetCurrent() - [RCTConvert NSTimeInterval:_lastLocationEvent[@"timestamp"]] < options.maximumAge &&
219+
[_lastLocationEvent[@"coords"][@"accuracy"] doubleValue] >= options.accuracy) {
228220

229-
// Call success block with most recent known location
230-
successBlock(@[_lastLocationEvent]);
231-
return;
232-
}
221+
// Call success block with most recent known location
222+
successBlock(@[_lastLocationEvent]);
223+
return;
224+
}
233225

234-
// Create request
235-
RCTLocationRequest *request = [[RCTLocationRequest alloc] init];
236-
request.successBlock = successBlock;
237-
request.errorBlock = errorBlock ?: ^(NSArray *args){};
238-
request.options = options;
239-
request.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:options.timeout
240-
target:self
241-
selector:@selector(timeout:)
242-
userInfo:request
243-
repeats:NO];
244-
[_pendingRequests addObject:request];
245-
246-
// Configure location manager and begin updating location
247-
_locationManager.desiredAccuracy = MIN(_locationManager.desiredAccuracy, options.accuracy);
248-
[self beginLocationUpdates];
249-
250-
});
226+
// Create request
227+
RCTLocationRequest *request = [[RCTLocationRequest alloc] init];
228+
request.successBlock = successBlock;
229+
request.errorBlock = errorBlock ?: ^(NSArray *args){};
230+
request.options = options;
231+
request.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:options.timeout
232+
target:self
233+
selector:@selector(timeout:)
234+
userInfo:request
235+
repeats:NO];
236+
[_pendingRequests addObject:request];
237+
238+
// Configure location manager and begin updating location
239+
_locationManager.desiredAccuracy = MIN(_locationManager.desiredAccuracy, options.accuracy);
240+
[self beginLocationUpdates];
251241
}
252242

253243
#pragma mark - CLLocationManagerDelegate

Libraries/LinkingIOS/RCTLinkingManager.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,10 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
6262
RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
6363
callback:(RCTResponseSenderBlock)callback)
6464
{
65-
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:URL];
66-
callback(@[@(canOpen)]);
65+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
66+
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:URL];
67+
callback(@[@(canOpen)]);
68+
});
6769
}
6870

6971
- (NSDictionary *)constantsToExport

0 commit comments

Comments
 (0)