是否可以使用 AppName -Prefix.pch文件导入除一个以外的所有源文件中的给定头文件?
问题:
我遵循了这里描述的方法:https://stackoverflow.com/a/617559/1062572来覆盖C函数调用,即GCD dispatch_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
而heres是我的实施文件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
如何在所有源代码中导入头文件,实现文件是唯一的例外?我希望无需手动在每个源文件中插入import语句即可完成。 并且没有编写脚本来执行此操作。 ;)
让我更加困惑的一件事是:实际上我在编译库(Testing.a)中有实现文件,为什么导入头文件?
更多信息: 我正在编写一个测试框架,等待所有异步任务完成后再检查结果。这就是为什么我重写dispatch_async。欢迎任何其他建议。 :)
我也注意到了这个答案:https://stackoverflow.com/a/617606/1062572然而,这似乎不适用于OSX,因此iOS不是我的目标。
所有这些方法只会覆盖我自己的源代码中的函数调用。实际上我希望它到处覆盖它。但是对于这个问题,我很满意它是否适用于我自己的源代码。
答案 0 :(得分:1)
不幸的是,它不可能。在编译期间,前缀头被编译,缓存并包含在每个文件中。您无法分辨哪些文件会被忽略。 但是,如果已经包含Intercept.h,则可以忽略它。方法如下:
1-从Prefix.pch中移除#import "Intercept.h"
周围的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。
希望它有所帮助。
答案 1 :(得分: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.");
}
但是如果你不知道正在使用什么队列怎么办?好吧,只要你控制完成块,那也没关系。 (见Waiting on Groups of Queued Tasks。)
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);
当然你也可以这样做with a semaphore。如果您只想将单个操作从异步转换为同步,那么这有时会更容易。
我建议使用这些方法而不是试图劫持dispatch_async本身。