Skip to content

Commit

Permalink
Implemented thread control for exported methods
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Apr 18, 2015
1 parent 2b9aaac commit ead0f2e
Show file tree
Hide file tree
Showing 23 changed files with 383 additions and 402 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 5 additions & 7 deletions Examples/UIExplorer/UIExplorerTests/UIExplorerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,10 @@ - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
return NO;
}

// Make sure this test runs first (underscores sort early) otherwise the
// other tests will tear out the rootView
- (void)test__RootViewLoadsAndRenders
// Make sure this test runs first because the other tests will tear out the rootView
- (void)testAAA_RootViewLoadsAndRenders
{
UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController;
RCTAssert([vc.view isKindOfClass:[RCTRootView class]], @"This test must run first.");
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
BOOL foundElement = NO;
Expand All @@ -72,10 +71,8 @@ - (void)test__RootViewLoadsAndRenders
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:date];

redboxError = [[RCTRedBox sharedInstance] currentErrorMessage];

foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
foundElement = [self findSubviewInView:vc.view matching:^(UIView *view) {
if ([view respondsToSelector:@selector(attributedText)]) {
NSString *text = [(id)view attributedText].string;
if ([text isEqualToString:@"<View>"]) {
Expand Down Expand Up @@ -120,6 +117,7 @@ - (void)testTabBarExampleSnapshot
[_runner runTest:_cmd module:@"TabBarExample"];
}

// Make sure this test runs last
- (void)testZZZ_NotInRecordMode
{
RCTAssert(_runner.recordMode == NO, @"Don't forget to turn record mode back to NO before commit.");
Expand Down
120 changes: 58 additions & 62 deletions Libraries/ActionSheetIOS/RCTActionSheetManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,92 +34,88 @@ - (instancetype)init
failureCallback:(RCTResponseSenderBlock)failureCallback
successCallback:(RCTResponseSenderBlock)successCallback)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];

actionSheet.title = options[@"title"];
actionSheet.title = options[@"title"];

for (NSString *option in options[@"options"]) {
[actionSheet addButtonWithTitle:option];
}
for (NSString *option in options[@"options"]) {
[actionSheet addButtonWithTitle:option];
}

if (options[@"destructiveButtonIndex"]) {
actionSheet.destructiveButtonIndex = [options[@"destructiveButtonIndex"] integerValue];
}
if (options[@"cancelButtonIndex"]) {
actionSheet.cancelButtonIndex = [options[@"cancelButtonIndex"] integerValue];
}
if (options[@"destructiveButtonIndex"]) {
actionSheet.destructiveButtonIndex = [options[@"destructiveButtonIndex"] integerValue];
}
if (options[@"cancelButtonIndex"]) {
actionSheet.cancelButtonIndex = [options[@"cancelButtonIndex"] integerValue];
}

actionSheet.delegate = self;
actionSheet.delegate = self;

_callbacks[keyForInstance(actionSheet)] = successCallback;
_callbacks[RCTKeyForInstance(actionSheet)] = successCallback;

UIWindow *appWindow = [[[UIApplication sharedApplication] delegate] window];
if (appWindow == nil) {
RCTLogError(@"Tried to display action sheet but there is no application window. options: %@", options);
return;
}
[actionSheet showInView:appWindow];
});
UIWindow *appWindow = [[[UIApplication sharedApplication] delegate] window];
if (appWindow == nil) {
RCTLogError(@"Tried to display action sheet but there is no application window. options: %@", options);
return;
}
[actionSheet showInView:appWindow];
}

RCT_EXPORT_METHOD(showShareActionSheetWithOptions:(NSDictionary *)options
failureCallback:(RCTResponseSenderBlock)failureCallback
successCallback:(RCTResponseSenderBlock)successCallback)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray *items = [NSMutableArray array];
id message = options[@"message"];
id url = options[@"url"];
if ([message isKindOfClass:[NSString class]]) {
[items addObject:message];
}
if ([url isKindOfClass:[NSString class]]) {
[items addObject:[NSURL URLWithString:url]];
}
if ([items count] == 0) {
failureCallback(@[@"No `url` or `message` to share"]);
return;
}
UIActivityViewController *share = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
if ([share respondsToSelector:@selector(setCompletionWithItemsHandler:)]) {
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if (activityError) {
failureCallback(@[[activityError localizedDescription]]);
} else {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
}
};
} else {
NSMutableArray *items = [NSMutableArray array];
id message = options[@"message"];
id url = options[@"url"];
if ([message isKindOfClass:[NSString class]]) {
[items addObject:message];
}
if ([url isKindOfClass:[NSString class]]) {
[items addObject:[NSURL URLWithString:url]];
}
if ([items count] == 0) {
failureCallback(@[@"No `url` or `message` to share"]);
return;
}
UIActivityViewController *share = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
if ([share respondsToSelector:@selector(setCompletionWithItemsHandler:)]) {
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if (activityError) {
failureCallback(@[[activityError localizedDescription]]);
} else {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
}
};
} else {

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

if (![UIActivityViewController instancesRespondToSelector:@selector(completionWithItemsHandler)]) {
// Legacy iOS 7 implementation
share.completionHandler = ^(NSString *activityType, BOOL completed) {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
};
} else
if (![UIActivityViewController instancesRespondToSelector:@selector(completionWithItemsHandler)]) {
// Legacy iOS 7 implementation
share.completionHandler = ^(NSString *activityType, BOOL completed) {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
};
} else

#endif

{
// iOS 8 version
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
};
}
{
// iOS 8 version
share.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
successCallback(@[@(completed), (activityType ?: [NSNull null])]);
};
}
[ctrl presentViewController:share animated:YES completion:nil];
});
}
[ctrl presentViewController:share animated:YES completion:nil];
}

#pragma mark UIActionSheetDelegate Methods

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *key = keyForInstance(actionSheet);
NSString *key = RCTKeyForInstance(actionSheet);
RCTResponseSenderBlock callback = _callbacks[key];
if (callback) {
callback(@[@(buttonIndex)]);
Expand All @@ -133,7 +129,7 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger

#pragma mark Private

NS_INLINE NSString *keyForInstance(id instance)
static NSString *RCTKeyForInstance(id instance)
{
return [NSString stringWithFormat:@"%p", instance];
}
Expand Down
5 changes: 5 additions & 0 deletions Libraries/Animation/RCTAnimationExperimentalManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ - (instancetype)init
return self;
}

- (dispatch_queue_t)methodQueue
{
return _bridge.uiManager.methodQueue;
}

- (id (^)(CGFloat))interpolateFrom:(CGFloat[])fromArray to:(CGFloat[])toArray count:(NSUInteger)count typeName:(const char *)typeName
{
if (count == 1) {
Expand Down
128 changes: 59 additions & 69 deletions Libraries/Geolocation/RCTLocationObserver.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ typedef NS_ENUM(NSInteger, RCTPositionErrorCode) {
CLLocationAccuracy accuracy;
} RCTLocationOptions;

static RCTLocationOptions RCTLocationOptionsWithJSON(id json)
@implementation RCTConvert (RCTLocationOptions)

+ (RCTLocationOptions)RCTLocationOptions:(id)json
{
NSDictionary *options = [RCTConvert NSDictionary:json];
return (RCTLocationOptions){
Expand All @@ -43,6 +45,8 @@ static RCTLocationOptions RCTLocationOptionsWithJSON(id json)
};
}

@end

static NSDictionary *RCTPositionError(RCTPositionErrorCode code, NSString *msg /* nil for default */)
{
if (!msg) {
Expand Down Expand Up @@ -121,6 +125,7 @@ - (instancetype)init
- (void)dealloc
{
[_locationManager stopUpdatingLocation];
_locationManager.delegate = nil;
}

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

#pragma mark - Public API

RCT_EXPORT_METHOD(startObserving:(NSDictionary *)optionsJSON)
RCT_EXPORT_METHOD(startObserving:(RCTLocationOptions)options)
{
[self checkLocationConfig];

dispatch_async(dispatch_get_main_queue(), ^{

// Select best options
_observerOptions = RCTLocationOptionsWithJSON(optionsJSON);
for (RCTLocationRequest *request in _pendingRequests) {
_observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
}

_locationManager.desiredAccuracy = _observerOptions.accuracy;
[self beginLocationUpdates];
_observingLocation = YES;
// Select best options
_observerOptions = options;
for (RCTLocationRequest *request in _pendingRequests) {
_observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
}

});
_locationManager.desiredAccuracy = _observerOptions.accuracy;
[self beginLocationUpdates];
_observingLocation = YES;
}

RCT_EXPORT_METHOD(stopObserving)
{
dispatch_async(dispatch_get_main_queue(), ^{

// Stop observing
_observingLocation = NO;
// Stop observing
_observingLocation = NO;

// Stop updating if no pending requests
if (_pendingRequests.count == 0) {
[_locationManager stopUpdatingLocation];
}

});
// Stop updating if no pending requests
if (_pendingRequests.count == 0) {
[_locationManager stopUpdatingLocation];
}
}

RCT_EXPORT_METHOD(getCurrentPosition:(NSDictionary *)optionsJSON
RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
withSuccessCallback:(RCTResponseSenderBlock)successBlock
errorCallback:(RCTResponseSenderBlock)errorBlock)
{
Expand All @@ -198,56 +195,49 @@ - (void)timeout:(NSTimer *)timer
return;
}

dispatch_async(dispatch_get_main_queue(), ^{

if (![CLLocationManager locationServicesEnabled]) {
if (errorBlock) {
errorBlock(@[
RCTPositionError(RCTPositionErrorUnavailable, @"Location services disabled.")
]);
return;
}
if (![CLLocationManager locationServicesEnabled]) {
if (errorBlock) {
errorBlock(@[
RCTPositionError(RCTPositionErrorUnavailable, @"Location services disabled.")
]);
return;
}
}

if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
if (errorBlock) {
errorBlock(@[
RCTPositionError(RCTPositionErrorDenied, nil)
]);
return;
}
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
if (errorBlock) {
errorBlock(@[
RCTPositionError(RCTPositionErrorDenied, nil)
]);
return;
}
}

// Get options
RCTLocationOptions options = RCTLocationOptionsWithJSON(optionsJSON);

// Check if previous recorded location exists and is good enough
if (_lastLocationEvent &&
CFAbsoluteTimeGetCurrent() - [RCTConvert NSTimeInterval:_lastLocationEvent[@"timestamp"]] < options.maximumAge &&
[_lastLocationEvent[@"coords"][@"accuracy"] doubleValue] >= options.accuracy) {
// Check if previous recorded location exists and is good enough
if (_lastLocationEvent &&
CFAbsoluteTimeGetCurrent() - [RCTConvert NSTimeInterval:_lastLocationEvent[@"timestamp"]] < options.maximumAge &&
[_lastLocationEvent[@"coords"][@"accuracy"] doubleValue] >= options.accuracy) {

// Call success block with most recent known location
successBlock(@[_lastLocationEvent]);
return;
}
// Call success block with most recent known location
successBlock(@[_lastLocationEvent]);
return;
}

// Create request
RCTLocationRequest *request = [[RCTLocationRequest alloc] init];
request.successBlock = successBlock;
request.errorBlock = errorBlock ?: ^(NSArray *args){};
request.options = options;
request.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:options.timeout
target:self
selector:@selector(timeout:)
userInfo:request
repeats:NO];
[_pendingRequests addObject:request];

// Configure location manager and begin updating location
_locationManager.desiredAccuracy = MIN(_locationManager.desiredAccuracy, options.accuracy);
[self beginLocationUpdates];

});
// Create request
RCTLocationRequest *request = [[RCTLocationRequest alloc] init];
request.successBlock = successBlock;
request.errorBlock = errorBlock ?: ^(NSArray *args){};
request.options = options;
request.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:options.timeout
target:self
selector:@selector(timeout:)
userInfo:request
repeats:NO];
[_pendingRequests addObject:request];

// Configure location manager and begin updating location
_locationManager.desiredAccuracy = MIN(_locationManager.desiredAccuracy, options.accuracy);
[self beginLocationUpdates];
}

#pragma mark - CLLocationManagerDelegate
Expand Down
6 changes: 4 additions & 2 deletions Libraries/LinkingIOS/RCTLinkingManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ - (void)handleOpenURLNotification:(NSNotification *)notification
RCT_EXPORT_METHOD(canOpenURL:(NSURL *)URL
callback:(RCTResponseSenderBlock)callback)
{
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:URL];
callback(@[@(canOpen)]);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:URL];
callback(@[@(canOpen)]);
});
}

- (NSDictionary *)constantsToExport
Expand Down
Loading

0 comments on commit ead0f2e

Please sign in to comment.