- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我遇到了一些我无法弄清楚的问题。如果我有一个带有 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/
我的 blockly.js 文件中有以下代码 Blockly.Blocks['account_number'] = { // Other type. init: function() {
首先抱歉我的英语不好,我正在开发 Image Splitter 应用程序并且已经完成,但是现在的要求是当图像被分割(分成几 block /chunks)那么图像 block 的每一 block (ch
#value: 消息的返回值,当发送到一个 block 时,是该 block 中最后一句话的值。所以 [ 1 + 2. 3 + 4. ] value 计算结果为 7。我发现有时很难使用。有没有办法显式
我想构建一个包含 3 div 的响应式导航栏相同的 width和 height . 我申请了 inline-block到每个 block ,我得到一个我不理解的行为。 问题是,第三 block 由 2
我希望使用 Blockly 来允许非技术人员用户指定测试脚本。 它的一部分需要一个文件选择器,但是,我看不到 Blockly 有一个。是吗? 实际上,我找不到完整的标准 block 列表。谁有网址?
仅当您位于父 block 内部时,父 block 的 props.isSelected 才为 true,但当您在该 block 的 innerBlocks 内进行编辑时则不然。 如何从父 block
仅当您位于父 block 内部时,父 block 的 props.isSelected 才为 true,但当您在该 block 的 innerBlocks 内进行编辑时则不然。 如何从父 block
我想创建一个具有不同背景颜色 block 和不同悬停颜色 block 的导航栏 block 。我可以分别创建不同的悬停颜色 block 或不同的背景颜色 block ,但不能一起创建。所以请告诉我如何
我正在使用看到的代码 here定期执行代码: #define DELAY_IN_MS 1000 __block dispatch_time_t next = dispatch_time(DISPATC
为什么 block 必须被复制而不是保留?两者在引擎盖下有什么区别?在什么情况下不需要复制 block (如果有)? 最佳答案 通常,当您分配一个类的实例时,它会进入堆并一直存在,直到它被释放。但是,
我想弄清楚我这样做是否正确: 如果我有一个 block ,我会这样做: __weak MyClass *weakSelf = self; [self performBlock:^{
我想制作一个 4 block 导航菜单,虽然我已经显示了一个 block ,然后单击打开第二个 block ,从第二个开始选择并再次单击出现第三个 block ,第四个 block 相同...这是我的
例如,这样更好吗? try { synchronized (bean) { // Write something } } catch (Int
我想让一只乌龟检查前方小块的颜色并决定移动到哪里。如果前面的补丁不是白色的,那么乌龟向左或向右旋转并移动。我的 If 决策结构中出现错误,显示“此处应为 TRUE?FALSE,而不是 block 列表
我想创建一个 block 对角矩阵,其中对角 block 重复一定次数,非对角 block 都是零矩阵。例如,假设我们从一个矩阵开始: > diag.matrix [,1] [,2] [
我是区 block 链新手。突然我有一个问题,我们是否可以通过区 block 号来访问以太坊区 block 链上之前的区 block 数据。 例如我创建了一个block1、block2。 block
我是区 block 链新手。突然我有一个问题,我们是否可以通过区 block 号来访问以太坊区 block 链上之前的区 block 数据。 例如我创建了一个block1、block2。 block
我创建了一个等距环境,全部使用 Javascript 和 HTML5 (2D Canvas),大部分情况下工作正常。我面临的问题是使用不同高度的图 block ,然后对图 block 上的对象索引进行
这是令我困惑的代码: public Integer getInteger(BlockingQueue queue) { boolean interrupted = false; try
我有一个基于 TPL 数据流的应用程序,它仅使用批处理 block 和操作 block 就可以正常工作。 我已经添加了一个 TransformBlock 以尝试在发布到批处理 block 之前从源中转
我是一名优秀的程序员,十分优秀!