Skip to content

Commit c2819b3

Browse files
committed
Merge pull request #3 from thomasvl/process_updates
Misc cleanups so we can cut a release and push the podspec.
2 parents 42bb995 + a12294b commit c2819b3

File tree

8 files changed

+93
-70
lines changed

8 files changed

+93
-70
lines changed

.travis.sh

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,29 @@ readonly BUILD_MODE="$1"
1111
readonly BUILD_CFG="$2"
1212

1313
# Default to "build", based on BUILD_MODE below.
14-
XCTOOL_ACTION="build"
14+
XCODEBUILD_ACTION="build"
1515

1616
# Report then run the build
17-
RunXCTool() {
18-
echo xctool "$@"
19-
xctool "$@"
17+
RunXcodeBuild() {
18+
echo xcodebuild "$@"
19+
xcodebuild "$@"
2020
}
2121

22-
CMD_BUILDER=(
23-
# Always use -reporter plain to avoid escape codes in output (makes travis
24-
# logs easier to read).
25-
-reporter plain
26-
)
27-
2822
case "${BUILD_MODE}" in
2923
iOSCore)
3024
CMD_BUILDER+=(
3125
-project Source/GTLRCore.xcodeproj
3226
-scheme "iOS Framework and Tests"
33-
-sdk iphonesimulator
27+
-destination "platform=iOS Simulator,name=iPhone 6,OS=latest"
3428
)
35-
XCTOOL_ACTION="test"
29+
XCODEBUILD_ACTION="test"
3630
;;
3731
OSXCore)
3832
CMD_BUILDER+=(
3933
-project Source/GTLRCore.xcodeproj
4034
-scheme "OS X Framework and Tests"
4135
)
42-
XCTOOL_ACTION="test"
36+
XCODEBUILD_ACTION="test"
4337
;;
4438
Example_*)
4539
EXAMPLE_NAME="${BUILD_MODE/Example_/}"
@@ -56,11 +50,11 @@ esac
5650

5751
case "${BUILD_CFG}" in
5852
Debug|Release)
59-
RunXCTool "${CMD_BUILDER[@]}" -configuration "${BUILD_CFG}" "${XCTOOL_ACTION}"
53+
RunXcodeBuild "${CMD_BUILDER[@]}" -configuration "${BUILD_CFG}" "${XCODEBUILD_ACTION}"
6054
;;
6155
Both)
62-
RunXCTool "${CMD_BUILDER[@]}" -configuration Debug "${XCTOOL_ACTION}"
63-
RunXCTool "${CMD_BUILDER[@]}" -configuration Release "${XCTOOL_ACTION}"
56+
RunXcodeBuild "${CMD_BUILDER[@]}" -configuration Debug "${XCODEBUILD_ACTION}"
57+
RunXcodeBuild "${CMD_BUILDER[@]}" -configuration Release "${XCODEBUILD_ACTION}"
6458
;;
6559
*)
6660
echo "Unknown BUILD_CFG: ${BUILD_CFG}"

.travis.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
language: objective-c
2-
osx_image: xcode7.2
2+
osx_image: xcode7.3
33
env:
44
- MODE=OSXCore CFG=Debug
55
- MODE=OSXCore CFG=Release
@@ -11,9 +11,5 @@ env:
1111
- MODE=Example_StorageSample CFG=Both
1212
script:
1313
- ./.travis.sh "${MODE}" "${CFG}"
14-
before_install:
15-
# Ensure xctool is up to date.
16-
- brew update
17-
- brew outdated xctool || brew upgrade xctool
1814
notifications:
1915
email: false

GoogleAPIClientForREST.podspec

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@ Pod::Spec.new do |s|
1010
s.description = <<-DESC
1111
Written by Google, this library is a flexible and efficient Objective-C
1212
framework for accessing JSON REST APIs. This is the recommended library
13-
for accessing JSON-based Google APIs for iOS and Mac OS X applications.
13+
for accessing JSON-based Google APIs for iOS, OS X, and tvOS applications.
1414
15-
This version can be used with iOS ≥ 7.0 or OS X ≥ 10.9.
15+
This version can be used with iOS ≥ 7.0, OS X ≥ 10.9, tvOS ≥ 9.0.
1616
DESC
1717
s.ios.deployment_target = '7.0'
1818
s.osx.deployment_target = '10.9'
19+
s.tvos.deployment_target = '9.0'
1920

2021
s.user_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GTLR_USE_FRAMEWORK_IMPORTS=1' }
2122
s.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GTLR_HAS_SESSION_UPLOAD_FETCHER_IMPORT=1' }
22-
s.dependency 'GTMSessionFetcher', '~> 1.1'
23+
24+
# Require atleast 1.1.3 of the SessionFetcher so it has the backgroundTask
25+
# Testing support.
26+
s.dependency 'GTMSessionFetcher', '~> 1.1', '>= 1.1.3'
2327

2428
s.subspec 'Core' do |sp|
2529
sp.source_files = 'Source/GTLRDefines.h',

Source/GTLRCore.xcodeproj/xcshareddata/xcschemes/OS X Framework and Tests.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
</MacroExpansion>
9292
</ProfileAction>
9393
<AnalyzeAction
94-
buildConfiguration = "Debug">
94+
buildConfiguration = "Release">
9595
</AnalyzeAction>
9696
<ArchiveAction
9797
buildConfiguration = "Release"

Source/GTLRCore.xcodeproj/xcshareddata/xcschemes/iOS Framework and Tests.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
</MacroExpansion>
106106
</ProfileAction>
107107
<AnalyzeAction
108-
buildConfiguration = "Debug">
108+
buildConfiguration = "Release">
109109
</AnalyzeAction>
110110
<ArchiveAction
111111
buildConfiguration = "Release"

Source/Objects/GTLRService.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ typedef void (^GTLRServiceTestBlock)(GTLRServiceTicket *testTicket,
571571
* @param ticket The ticket being executed.
572572
* @param timeoutInSeconds Maximum duration to wait.
573573
*
574-
* @return YES if the ticket completed; NO if the wait timed out.
574+
* @return YES if the ticket completed or was cancelled; NO if the wait timed out.
575575
*/
576576
- (BOOL)waitForTicket:(GTLRServiceTicket *)ticket
577577
timeout:(NSTimeInterval)timeoutInSeconds;

Source/Objects/GTLRService.m

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,21 @@ - (instancetype)initWithService:(GTLRService *)service
121121
@property(nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
122122
#endif // GTM_BACKGROUND_TASK_FETCHING
123123

124+
// Dispatch group enabling waitForTicket: to delay until async callbacks and notifications
125+
// related to the ticket have completed.
126+
@property(nonatomic, readonly) dispatch_group_t callbackGroup;
127+
124128
// startBackgroundTask and endBackgroundTask do nothing if !GTM_BACKGROUND_TASK_FETCHING
125129
- (void)startBackgroundTask;
126130
- (void)endBackgroundTask;
127131

128132
- (void)notifyStarting:(BOOL)isStarting;
129133
- (void)releaseTicketCallbacks;
130134

135+
// Posts a notification on the main queue using the ticket's dispatch group.
136+
- (void)postNotificationOnMainThreadWithName:(NSString *)name
137+
object:(id)object
138+
userInfo:(NSDictionary *)userInfo;
131139
@end
132140

133141
#if !defined(GTLR_HAS_SESSION_UPLOAD_FETCHER_IMPORT)
@@ -502,19 +510,23 @@ - (GTLRServiceTicket *)fetchObjectWithURL:(NSURL *)targetURL
502510

503511
if (uploadParams.shouldUploadWithSingleRequest) {
504512
NSData *uploadData = uploadParams.data;
513+
NSString *uploadMIMEType = uploadParams.MIMEType;
505514
if (!uploadData) {
506515
GTLR_DEBUG_ASSERT(0, @"Uploading with a single request requires bytes to upload as NSData");
507516
} else {
508517
if (uploadParams.shouldSendUploadOnly) {
509-
contentType = uploadParams.MIMEType;
510-
dataToPost = uploadParams.data;
518+
contentType = uploadMIMEType;
519+
dataToPost = uploadData;
511520
contentLength = @(dataToPost.length).stringValue;
512521
} else {
513522
GTMMIMEDocument *mimeDoc = [GTMMIMEDocument MIMEDocument];
514-
[mimeDoc addPartWithHeaders:@{ @"Content-Type" : contentType }
515-
body:dataToPost];
516-
[mimeDoc addPartWithHeaders:@{ @"Content-Type" : uploadParams.MIMEType }
517-
body:uploadParams.data];
523+
if (dataToPost) {
524+
// Include the object as metadata with the upload.
525+
[mimeDoc addPartWithHeaders:@{ @"Content-Type" : contentType }
526+
body:dataToPost];
527+
}
528+
[mimeDoc addPartWithHeaders:@{ @"Content-Type" : uploadMIMEType }
529+
body:uploadData];
518530

519531
dispatch_data_t mimeDispatchData;
520532
unsigned long long mimeLength;
@@ -607,7 +619,7 @@ - (GTLRServiceTicket *)fetchObjectWithURL:(NSURL *)targetURL
607619
if (!retryBlock) {
608620
response(suggestedWillRetry);
609621
} else {
610-
dispatch_async(ticket.callbackQueue, ^{
622+
dispatch_group_async(ticket.callbackGroup, ticket.callbackQueue, ^{
611623
if (ticket.cancelled) {
612624
response(NO);
613625
return;
@@ -1015,7 +1027,7 @@ - (void)invokeProgressCallbackForTicket:(GTLRServiceTicket *)ticket
10151027

10161028
GTLRServiceUploadProgressBlock block = ticket.uploadProgressBlock;
10171029
if (block) {
1018-
dispatch_async(ticket.callbackQueue, ^{
1030+
dispatch_group_async(ticket.callbackGroup, ticket.callbackQueue, ^{
10191031
if (ticket.cancelled) return;
10201032

10211033
block(ticket, numReadSoFar, total);
@@ -1040,9 +1052,9 @@ - (void)prepareToParseObjectForFetcher:(GTMSessionFetcher *)fetcher
10401052
completionHandler:(GTLRServiceCompletionHandler)completionHandler {
10411053
GTLR_ASSERT_CURRENT_QUEUE_DEBUG(self.parseQueue);
10421054

1043-
[[self class] postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStartedNotification
1044-
object:ticket
1045-
userInfo:nil];
1055+
[ticket postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStartedNotification
1056+
object:ticket
1057+
userInfo:nil];
10461058

10471059
// For unit tests to cancel during parsing, we need a synchronous notification posted.
10481060
// Because this notification is intended only for unit tests, there is no public symbol
@@ -1194,9 +1206,9 @@ - (void)handleParsedObjectForFetcher:(GTMSessionFetcher *)fetcher
11941206

11951207
if (hasSentParsingStartNotification) {
11961208
// we want to always balance the start and stop notifications
1197-
[[self class] postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStoppedNotification
1198-
object:ticket
1199-
userInfo:nil];
1209+
[ticket postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStoppedNotification
1210+
object:ticket
1211+
userInfo:nil];
12001212
}
12011213

12021214
BOOL shouldCallCallbacks = YES;
@@ -1280,7 +1292,7 @@ - (void)handleParsedObjectForFetcher:(GTMSessionFetcher *)fetcher
12801292
if (!shouldCallCallbacks) {
12811293
// More fetches are happening.
12821294
} else {
1283-
dispatch_async(ticket.callbackQueue, ^{
1295+
dispatch_group_async(ticket.callbackGroup, ticket.callbackQueue, ^{
12841296
// First, call query-specific callback blocks. We do this before the
12851297
// fetch callback to let applications do any final clean-up (or update
12861298
// their UI) in the fetch callback.
@@ -1309,7 +1321,7 @@ - (void)handleParsedObjectForFetcher:(GTMSessionFetcher *)fetcher
13091321
[ticket releaseTicketCallbacks];
13101322
[ticket endBackgroundTask];
13111323

1312-
// Even if the ticket has been canceled, it should notify that it's stopped.
1324+
// Even if the ticket has been cancelled, it should notify that it's stopped.
13131325
[ticket notifyStarting:NO];
13141326

13151327
// Release query callback blocks.
@@ -1597,7 +1609,7 @@ - (void)simulateFetchWithTicket:(GTLRServiceTicket *)ticket
15971609
ticket.executingQuery = originalQuery;
15981610

15991611
testBlock(ticket, ^(id testObject, NSError *testError) {
1600-
dispatch_async(ticket.callbackQueue, ^{
1612+
dispatch_group_async(ticket.callbackGroup, ticket.callbackQueue, ^{
16011613
if (testError) {
16021614
// During simulation, we invoke any retry block, but ignore the result.
16031615
const BOOL willRetry = NO;
@@ -1622,12 +1634,12 @@ - (void)simulateFetchWithTicket:(GTLRServiceTicket *)ticket
16221634
deliveredBytes:(unsigned long long)totalSentSoFar
16231635
totalBytes:(unsigned long long)uploadLength];
16241636
}
1625-
[[self class] postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStartedNotification
1626-
object:ticket
1627-
userInfo:nil];
1628-
[[self class] postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStoppedNotification
1629-
object:ticket
1630-
userInfo:nil];
1637+
[ticket postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStartedNotification
1638+
object:ticket
1639+
userInfo:nil];
1640+
[ticket postNotificationOnMainThreadWithName:kGTLRServiceTicketParsingStoppedNotification
1641+
object:ticket
1642+
userInfo:nil];
16311643
}
16321644
}
16331645

@@ -1657,7 +1669,7 @@ - (void)simulateFetchWithTicket:(GTLRServiceTicket *)ticket
16571669
[ticket notifyStarting:NO];
16581670

16591671
[originalQuery invalidateQuery];
1660-
}); // dispatch_async
1672+
}); // dispatch_group_async
16611673
}); // testBlock
16621674
}
16631675

@@ -2113,17 +2125,6 @@ - (void)setUserAgent:(NSString *)userAgent {
21132125
[self setExactUserAgent:str];
21142126
}
21152127

2116-
+ (void)postNotificationOnMainThreadWithName:(NSString *)name
2117-
object:(id)object
2118-
userInfo:(NSDictionary *)userInfo {
2119-
// We always post these async to ensure they remain in order.
2120-
dispatch_async(dispatch_get_main_queue(), ^{
2121-
[[NSNotificationCenter defaultCenter] postNotificationName:name
2122-
object:object
2123-
userInfo:userInfo];
2124-
});
2125-
}
2126-
21272128
#pragma mark -
21282129

21292130
+ (NSDictionary<NSString *, Class> *)kindStringToClassMap {
@@ -2241,17 +2242,32 @@ + (instancetype)mockServiceWithFakedObject:(id)objectOrNil
22412242

22422243
- (BOOL)waitForTicket:(GTLRServiceTicket *)ticket
22432244
timeout:(NSTimeInterval)timeoutInSeconds {
2244-
// Loop until the fetch completes with an object or an error,
2245-
// or until the timeout has expired.
2245+
// Loop until the fetch completes or is cancelled, or until the timeout has expired.
22462246
NSDate *giveUpDate = [NSDate dateWithTimeIntervalSinceNow:timeoutInSeconds];
22472247

2248-
while (!ticket.hasCalledCallback && giveUpDate.timeIntervalSinceNow > 0) {
2248+
BOOL hasTimedOut = NO;
2249+
while (1) {
2250+
int64_t delta = (int64_t)(100 * NSEC_PER_MSEC); // 100 ms
2251+
BOOL areCallbacksPending =
2252+
(dispatch_group_wait(ticket.callbackGroup, dispatch_time(DISPATCH_TIME_NOW, delta)) != 0);
2253+
2254+
if (!areCallbacksPending && (ticket.hasCalledCallback || ticket.cancelled)) break;
2255+
2256+
hasTimedOut = (giveUpDate.timeIntervalSinceNow <= 0);
2257+
if (hasTimedOut) {
2258+
if (areCallbacksPending) {
2259+
// A timeout while waiting for the dispatch group to finish is seriously unexpected.
2260+
GTLR_DEBUG_LOG(@"%s timed out while waiting for the dispatch group", __PRETTY_FUNCTION__);
2261+
}
2262+
break;
2263+
}
2264+
22492265
// Run the current run loop 1/1000 of a second to give the networking
22502266
// code a chance to work.
22512267
NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001];
22522268
[[NSRunLoop currentRunLoop] runUntilDate:stopDate];
22532269
}
2254-
return ticket.hasCalledCallback;
2270+
return !hasTimedOut;
22552271
}
22562272

22572273
@end
@@ -2267,6 +2283,7 @@ @implementation GTLRServiceTicket {
22672283
allowInsecureQueries = _allowInsecureQueries,
22682284
authorizer = _authorizer,
22692285
cancelled = _cancelled,
2286+
callbackGroup = _callbackGroup,
22702287
callbackQueue = _callbackQueue,
22712288
creationDate = _creationDate,
22722289
executingQuery = _executingQuery,
@@ -2338,6 +2355,7 @@ - (instancetype)initWithService:(GTLRService *)service
23382355
_testBlock = params.testBlock ?: service.testBlock;
23392356

23402357
_callbackQueue = ((_Nonnull dispatch_queue_t)params.callbackQueue) ?: service.callbackQueue;
2358+
_callbackGroup = dispatch_group_create();
23412359

23422360
_apiKey = [service.APIKey copy];
23432361
_allowInsecureQueries = service.allowInsecureQueries;
@@ -2367,6 +2385,17 @@ - (NSString *)description {
23672385
[self class], self, _service, devKeyInfo, authorizerInfo, _objectFetcher];
23682386
}
23692387

2388+
- (void)postNotificationOnMainThreadWithName:(NSString *)name
2389+
object:(id)object
2390+
userInfo:(NSDictionary *)userInfo {
2391+
// We always post these async to ensure they remain in order.
2392+
dispatch_group_async(self.callbackGroup, dispatch_get_main_queue(), ^{
2393+
[[NSNotificationCenter defaultCenter] postNotificationName:name
2394+
object:object
2395+
userInfo:userInfo];
2396+
});
2397+
}
2398+
23702399
- (void)pauseUpload {
23712400
GTMSessionFetcher *fetcher = self.objectFetcher;
23722401
BOOL canPause = [fetcher respondsToSelector:@selector(pauseFetching)];
@@ -2507,9 +2536,9 @@ - (void)notifyStarting:(BOOL)isStarting {
25072536
name = kGTLRServiceTicketStoppedNotification;
25082537
_needsStopNotification = NO;
25092538
}
2510-
[GTLRService postNotificationOnMainThreadWithName:name
2511-
object:self
2512-
userInfo:nil];
2539+
[self postNotificationOnMainThreadWithName:name
2540+
object:self
2541+
userInfo:nil];
25132542
}
25142543

25152544
- (id)service {

0 commit comments

Comments
 (0)