gpt4 book ai didi

ios - 在同一线程上运行 block

转载 作者:可可西里 更新时间:2023-11-01 06:08:47 25 4
gpt4 key购买 nike

我遇到了一些我无法弄清楚的问题。如果我有一个带有 Block 参数的方法签名,其中有一个回调,并且在我的方法中我使用了一个有另一个 Block 的 API,API 执行 async 并且我的代码继续并调用我的回调方法.这让我的 View Controller 知道一切都已完成,而实际上通常不是因为 API block 。

由于我的方法总是调用回调方法(并且异步运行),我可以强制使用 block 的 API 调用同步运行吗?

View Controller

[self.tagRepo sync:^(BOOL finished) {
if (finished) {
NSLog(@"Sync completed.");
if (self.tagRepo.isSyncing)
NSLog(@"Syncing continues...");
}
}];

[tagRepo 同步]

- (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; // Block calling the call back when we begin the listTagsWithSuccess async.
self.clientTags = [[self fetchAll] mutableCopy];
[[EvernoteNoteStore noteStore] listTagsWithSuccess:^(NSArray *tags) {
self.serverTags = [tags mutableCopy];
[self processClientTags]; // Only need to make sure client sends any new tags to the server.

// invoke call back.
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 方法调用发生在另一个 block 中,因此当前线程上的完成 block 继续进行并被调用。

我是否在不正确的庄园中使用 block ,或者是否有一种典型的方法来处理其中包含嵌套 block 的回调。我是否应该尝试通过一些 GCD 调度在当前线程上运行辅助 block ?设置KVO?我在尝试 KVO 时遇到的问题是,在 sync 过程中使用的 API(Evernote)中的 block 数会有所不同,具体取决于发生的变化。因此很难确定 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 异步 block 在运行。

- (void)processSync:(EDAMSyncState *)syncState {
BOOL fullSync = NO;
// If we have never updated, perform full sync.
if (!self.lastUpdateCount)
fullSync = YES;

[[EvernoteNoteStore noteStore] getSyncChunkAfterUSN:self.currentChunkUSN maxEntries:200 fullSyncOnly:NO success:^(EDAMSyncChunk *syncChunk) {
// Loop, re-grabbing the next chunk
if (syncChunk.chunkHighUSN < syncChunk.updateCount) {
// Cache the current sync chunk. Since only so much is handed to us
// during this hand-shake, we cache and go get more.
[self cacheSyncChunk:syncChunk];
self.currentChunkUSN = syncChunk.chunkHighUSN;

// Fetch more sync chunks.
[self processSync:syncState];
} else {
// Retrieved the last sync chunk, cache it and begin processing.
[self cacheSyncChunk:syncChunk];
self.currentChunkUSN = syncChunk.chunkHighUSN;

// Build list of server tags
[self processTags];

// Time stamp ourselves so we know when we last updated.
self.lastSyncTime = [NSDate endateFromEDAMTimestamp:syncState.currentTime];
self.lastUpdateCount = syncState.updateCount;
}
} failure:^(NSError *error) {
NSLog(@"Failed to process full sync.");
}];
}

- (void)processTags {

// Process the tags found on the server first. We bring down any new tags from the server and cache them.
// Handles any naming conflicts or duplicate conflicts that come up.
self.clientTags = [[self fetchAll] mutableCopy];
[self processServerTags];

// Process client tags. We check if the client has tags that do not exist on the server and send them.
[self processClientTags];

// Delete any expunged tags that we still have cached.
[self expungeTags];

NSLog(@"Completed syncing tags.");
}

- (void)processClientTags {
NSLog(@"Processing client tags - Ensuring server is current with client tags.");
// Now we compare our local cache to the server, in the event new tags were created.
// TODO: Test this.
for (Tag *clientTag in self.clientTags) {
// Predicate for comparing all client tags against server tags.
// We compare GUID's and Names. Since we can't have duplicate's of either, we check.
// It is possible that the client created a Tag (GUID #1) and created it on the server externally (GUID #2) but share the same name.
// In this case, we have to rename them.
NSPredicate *compareGuidPredicate = [NSPredicate predicateWithFormat:@"guid == %@", clientTag.guid];

//Check if this note exists already on the server.
if (![[self.serverTags filteredArrayUsingPredicate:compareGuidPredicate] count]) {
// If not, we make sure it was never expunged.
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];

// Check which is newer. If the server is newer, update the client, if the client is newer
// do nothing. It will be handled later under the processClientTags method.
[[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.");
}

阅读 Rob 的回答后,我似乎需要对源代码进行一些重新架构,这对我来说不是什么大问题。对于其中运行异步代码的每个方法,方法签名都需要包含一个回调 block 。异步代码将在完成后调用该回调 block 。

最佳答案

如果您看到传递给 sync 的 block 在 processSync 方法完成之前被调用,那么这表明 processSync 是, 本身必须执行一些异步操作。 (您已经用该代码更新了您的问题,这似乎是这种情况。)如果确实如此,那么您想要 (a) 更改 processSync 方法自己获取一个完成 block 参数,并且 (b) 让 sync 方法将对它自己的 completed() 的调用移动到您传递给 processSync< 的 block 。这样,您可以确保 completed() 在真正完成之前不会被调用。

因此,它可能看起来像:

- (void)sync:(void(^)(BOOL finished))completed {
if (self.isSyncing)
return;

NSLog(@"Synchronizing tags...");
self.isSyncing = YES;

[[EvernoteNoteStore noteStore] getSyncStateWithSuccess:^(EDAMSyncState *syncState) {
if (syncState.fullSyncBefore > lastSyncTime || syncState.updateCount > self.lastUpdateCount) {
[self processSync:syncState completionHandler:^(BOOL finished){
self.isSyncing = NO;
if (completed)
completed(finished);
}];
} else {
self.clientTags = [[self fetchAll] mutableCopy];
[[EvernoteNoteStore noteStore] listTagsWithSuccess:^(NSArray *tags) {
self.serverTags = [tags mutableCopy];
[self processClientTags]; // Only need to make sure client sends any new tags to the server.

// invoke call back.
self.isSyncing = NO;
if (completed)
completed(YES);
} failure:^(NSError *error) {
self.isSyncing = NO;
NSLog(@"Failed to list tags.");
if (completed)
completed(NO);
}];
}

// self.isSyncing = NO;
// if (completed && performCallback)
// completed(YES);
} failure:^(NSError *error) {
self.isSyncing = NO;
NSLog(@"Failed to process a sync.");

if (completed)
completed(NO);
}];
}

请注意,这消除了 performCallback bool 值,因为我们只是确保所有路径都调用回调,而在 processSync 的情况下,回调的调用被推迟直到 processSync 首先完成其异步过程。

这显然假设您将重构 processSync 以获取自己的完成处理程序。

最重要的是,您只想在 (a) 最终异步进程成功完成时调用完成 block ; (b) 失败了。但是在异步过程完成之前不要调用完成 block ,必要时嵌套它,如上所示。

关于ios - 在同一线程上运行 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21505990/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com