0

是否可以使用AppName -Prefix.pch 文件在除一个之外的所有源文件中导入给定的头文件?

问题: 我已经按照此处描述的方法:https ://stackoverflow.com/a/617559/1062572覆盖了一个 C 函数调用,即 GCDdispatch_async函数。

现在我需要intercept.h在所有源文件中导入头文件,为此我尝试使用AppName -Prefix.pch 文件。但是,这也会在我的实现文件中导入头文件intercept.m。这会导致一个无休止的调用循环,因为我尝试dispatch_async在那里调用原件。

这是我的头文件intercept.h

#ifdef INTERCEPT
#define dispatch_async(queue, block) my_dispatch_async(queue, block)
#endif

这是我的实现文件intercept.m

void my_dispatch_async(dispatch_queue_t queue, dispatch_block_t block) {
NSLog(@"\nBlock is enqueued!\n");
dispatch_async(queue, ^{
    NSLog(@"\nBlock is dequeued!\n");
    block();
    NSLog(@"\nBlock has executed!\n");
});
}

这是我的 Prefix.pch 文件:

#ifdef INTERCEPT
#import "Intercept.h"
#endif

如何在我的所有源中导入头文件,实现文件是唯一的例外?我希望无需在每个源文件中手动插入导入语句即可完成。并且无需编写脚本即可。;)

更让我困惑的一件事是:实际上我在编译库(Testing.a)中有实现文件,那么为什么要在其中导入头文件?

更多信息: 我正在编写一个测试框架,等待所有异步任务完成后再检查结果。这就是我重写 dispatch_async 的原因。欢迎任何其他建议。:)

我也注意到了这个答案:https ://stackoverflow.com/a/617606/1062572但是这似乎不适用于 OSX,因此不是我的目标 iOS。

所有这些方法只会覆盖我自己的源代码中的函数调用。实际上我希望它在任何地方都覆盖它。但是对于这个问题,如果它适用于我自己的源代码,我很满意。

4

2 回答 2

1

不幸的是,这是不可能的。前缀头在编译期间被编译、缓存并包含在每个文件中。您无法确定要忽略哪些文件。但是,如果您已经包含了 Intercept.h,则可以忽略它。就是这样:

#import "Intercept.h"1-从 Prefix.pch 中删除 ifdef INTERCEPT 条件。你在那里不需要它。

2-将您的 Intercept.h 更新为:

#ifndef INTERCEPT_H
#define INTERCEPT_H
#define dispatch_async(queue, block) my_dispatch_async(queue, block)
#endif

这里发生的是您首先检查当前定义中是否已经包含/定义了 INTERCEPT_H,如果没有,则在下一行中定义它,然后定义您的宏。现在,如果#ifndef INTERCEPT_H条件已经将其内容包含在同一上下文中,它将返回 false。

希望能帮助到你。

于 2013-10-20T19:07:07.927 回答
1

更多信息:我正在编写一个测试框架,等待所有异步任务完成后再检查结果。这就是我重写 dispatch_async 的原因。欢迎任何其他建议。:)

根据您的情况,这可能会以更好的方式解决。只要您可以访问正在使用的队列,这非常简单。考虑这个 API,您在其中传递要使用的队列:

[object doSomethingAsyncWithCompletion:block1 queue:myQueue];
[object doSomethingElseAsyncWithCompletion:block2 queue:myQueue];
[object doMoreAsyncWithCompletion:block3 queue:myQueue];

现在,您想等到所有这些都完成。假设这是一个自定义并发队列(不是全局队列之一),只需使用屏障:

dispatch_barrier_sync(myQueue, ^{
  NSLog(@"This will not run until everything else before it on the queue finishes.");
}

但是,如果您不知道正在使用什么队列怎么办?好吧,只要您控制完成块,也可以。(请参阅等待队列任务组。)

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_block_t doneBlock = ^{
  dispatch_group_leave(group);
}

dispatch_group_enter(group);
[object doSomethingAsyncWithCompletion:doneBlock queue:myQueue];
dispatch_group_enter(group);
[object doSomethingElseAsyncWithCompletion:doneBlock queue:myQueue];
dispatch_group_enter(group);
[object doMoreAsyncWithCompletion:doneBlock queue:myQueue];

// Wait for all the doneBlocks to fire
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

当然,您也可以使用 semaphore来做到这一点。如果您只想将单个操作从异步转换为同步,这有时会更容易。

我会推荐这些方法,而不是试图劫持 dispatch_async 本身。

于 2013-10-20T19:33:34.123 回答