I am facing a problem that I cannot understand. If I have a method signature with a Block parameter with a callback in it, and in my method I use an API that has another block, the API executes asyncand my code continues and calls my callback method. This allows my view controller to know that everything is complete when, in fact, often this is not due to an API block.
Since my method always calls the callback method (and async starts), can I force the API call to use the block to run synchronously?
View controller
[self.tagRepo sync:^(BOOL finished) {
if (finished) {
NSLog(@"Sync completed.");
if (self.tagRepo.isSyncing)
NSLog(@"Syncing continues...");
}
}];
[tagRepo Sync]
- (void)sync:(void(^)(BOOL finished))completed {
if (self.isSyncing)
return;
NSLog(@"Synchronizing tags...");
self.isSyncing = YES;
[[EvernoteNoteStore noteStore] getSyncStateWithSuccess:^(EDAMSyncState *syncState) {
BOOL performCallback = YES;
if (syncState.fullSyncBefore > lastSyncTime) {
[self processSync:syncState];
} else if (syncState.updateCount > self.lastUpdateCount) {
[self processSync:syncState];
} else {
performCallback = NO;
self.clientTags = [[self fetchAll] mutableCopy];
[[EvernoteNoteStore noteStore] listTagsWithSuccess:^(NSArray *tags) {
self.serverTags = [tags mutableCopy];
[self processClientTags];
self.isSyncing = NO;
if (completed)
completed(YES);
} failure:^(NSError *error) {
self.isSyncing = NO;
NSLog(@"Failed to list tags.");
}];
}
self.isSyncing = NO;
if (completed && performCallback)
completed(YES);
} failure:^(NSError *error) {
self.isSyncing = NO;
NSLog(@"Failed to process a sync.");
if (completed)
completed(NO);
}];
}
, [sync], NSLog , processSync. , processSync , .
, . GCD? KVO? , , KVO , API (Evernote), sync, . , NSNotificationCenter, , / . , , . !
.
1
, `[[EvernoteNoteStore noteStore] ^ listTagsWithSuccess].
- (void)getSyncStateWithSuccess:(void(^)(EDAMSyncState *syncState))success
failure:(void(^)(NSError *error))failure
{
[self invokeAsyncIdBlock:^id {
return [[self currentNoteStore] getSyncState:[self authenticationToken]];
} success:success failure:failure];
}
- (void)listTagsWithSuccess:(void(^)(NSArray *tags))success
failure:(void(^)(NSError *error))failure
{
[self invokeAsyncIdBlock:^id {
return [[self currentNoteStore] listTags:[self authenticationToken]];
} success:success failure:failure];
}
- (void)invokeAsyncIdBlock:(id(^)())block
success:(void(^)(id))success
failure:(void(^)(NSError *error))failure
{
dispatch_async(self.session.queue, ^(void) {
id retVal = nil;
@try {
if (block) {
retVal = block();
dispatch_async(dispatch_get_main_queue(),
^{
if (success) {
success(retVal);
}
});
}
}
@catch (NSException *exception) {
NSError *error = [self errorFromNSException:exception];
[self processError:failure withError:error];
}
});
}
2
processSync, , . processSync Evernote SDK, processTags. processServerTags, , processClientTags, , processServerTags. , 3-4 Evernote SDK.
- (void)processSync:(EDAMSyncState *)syncState {
BOOL fullSync = NO;
if (!self.lastUpdateCount)
fullSync = YES;
[[EvernoteNoteStore noteStore] getSyncChunkAfterUSN:self.currentChunkUSN maxEntries:200 fullSyncOnly:NO success:^(EDAMSyncChunk *syncChunk) {
if (syncChunk.chunkHighUSN < syncChunk.updateCount) {
[self cacheSyncChunk:syncChunk];
self.currentChunkUSN = syncChunk.chunkHighUSN;
[self processSync:syncState];
} else {
[self cacheSyncChunk:syncChunk];
self.currentChunkUSN = syncChunk.chunkHighUSN;
[self processTags];
self.lastSyncTime = [NSDate endateFromEDAMTimestamp:syncState.currentTime];
self.lastUpdateCount = syncState.updateCount;
}
} failure:^(NSError *error) {
NSLog(@"Failed to process full sync.");
}];
}
- (void)processTags {
self.clientTags = [[self fetchAll] mutableCopy];
[self processServerTags];
[self processClientTags];
[self expungeTags];
NSLog(@"Completed syncing tags.");
}
- (void)processClientTags {
NSLog(@"Processing client tags - Ensuring server is current with client tags.");
for (Tag *clientTag in self.clientTags) {
NSPredicate *compareGuidPredicate = [NSPredicate predicateWithFormat:@"guid == %@", clientTag.guid];
if (![[self.serverTags filteredArrayUsingPredicate:compareGuidPredicate] count]) {
if ([self.expungedTags containsObject:clientTag.guid])
continue;
EDAMTag *serverTag = [[EDAMTag alloc] initWithGuid:nil name:clientTag.name parentGuid:nil updateSequenceNum:0];
serverTag = [self convertManagedTag:clientTag toEvernoteTag:serverTag convertingOnlyChangedProperties:NO];
[[EvernoteNoteStore noteStore] createTag:serverTag success:^(EDAMTag *tag) {
NSLog(@"Created new %@ tag on the server.", serverTag.name);
clientTag.guid = tag.guid;
NSLog(@"Server GUID %@ assigned to Client GUID %@", tag.guid, clientTag.guid);
[self saveAllChanges];
} failure:^(NSError *error) {
NSLog(@"Failed to create the %@ tag.\n%@", clientTag.name, [error description]);
}];
}
}
NSLog(@"Client tag processing completed.");
}
, , , . , , . , .