【问题标题】:How does XCode handle #import header statements in with multiple targets?XCode 如何处理带有多个目标的#import 标头语句?
【发布时间】:2010-11-06 08:43:26
【问题描述】:

我有一个包含 2 个目标的 XCode 项目(两者都是 iPhone 应用程序共享 95% 的相同代码)。 但是,一个模块不是“可共享的”;实现太不同了。

我的解决方案(不起作用)是在我的项目目录中的 Classes/ 文件夹中添加 2 个子目录 - 每个目标一个。在每个目录中,我放置了一个视图控制器类,称为ExampleSentencesViewController。当然,每个文件都被编译为仅一个目标的一部分——我正在寻找一个“自动切换”,根据目标使用哪个实现。

在每个目标的设置中,我将每个目录添加到“标题搜索路径”设置(每个目标的每个路径)。

奇怪的是,它只为原始目标编译。我后来添加的目标不会编译,声称我已经包含了两次相同的标题(公平地说,有两个文件)。如何让 XCode 忘记原始标头??

我尝试从我的项目中删除 .h 文件,但这似乎没有帮助。

感谢任何帮助。

【问题讨论】:

    标签: iphone xcode ios import header


    【解决方案1】:

    根据您定义的搜索目录之一,完全限定单独实施文件中的标头路径:

    #include <MONProject/Source/ExampleSentencesViewController.h>

    #include <MONSecondProject/Source/ExampleSentencesViewController.h>

    根据澄清更新:

    理想情况下,您应该为共享代码创建一个静态库。

    对于一个简单的案例...您可以通过在项目的根目录中填充一个名为 ExampleSentencesViewController.h 的标题并像这样填充它来采用直接方法:

    /* you must define either MON_BUILD_MON_FIRST_PROJECT or MON_BUILD_MON_SECOND_PROJECT at the target level */
    
    #if (defined(MON_BUILD_MON_FIRST_PROJECT) && defined(MON_BUILD_MON_SECOND_PROJECT))
    #error invalid configuration: you cannot specify both projects to be compiled
    #elif defined(MON_BUILD_MON_FIRST_PROJECT)
    /* some fully qualified path: */
    #include <MONFirstProject/ExampleSentencesViewController.h>
    #elif defined(MON_BUILD_MON_SECOND_PROJECT)
    /* some other fully qualified path: */
    #include <MONSecondProject/ExampleSentencesViewController.h>
    #else
    #error uh... which project are you trying to build?
    #endif
    

    或者您可以使用这些定义有条件地启用/禁用具有重复名称的类的接口和实现(然后将它们都包含在项目的声明中:

    /* MONFirstProject/ExampleSentencesViewController.h> */
    
    #if defined(MON_BUILD_MON_FIRST_PROJECT)
    @interface ExampleSentencesViewController : NSViewController
    /* ... */
    @end
    #endif
    

    ...但这需要在您的分发中包含两个标头(如果适用)。

    包含的一些更详细的细节可能会有所不同,具体取决于您声明搜索路径的方式(例如,它们是否递归?)以及您是否在 xcodeproj 中使用复制标头构建阶段。如果您在包含指令、发现选项、预处理器声明(条件编译/可见性)和/或构建配置方面过于放松,那么维护共享代码的两个项目可能会变得混乱......这就是为什么我推荐一个共享库的原因位。这种有条件的东西(在前面的两个例子中)很容易出错,并且不能很好地发展或扩展。这样做也是混淆开发工具包中其他工具的好方法。

    事实上,我更喜欢这个而不是预处理器(假设你能够分发这两个类):

    - (UIViewController *)newViewControllerForMyAwesomeView {
        if (IsAppMONFirstProject) {
            return [[MONFirstProjectViewController alloc] init...];
        }
        else if (IsAppMONSecondProject) {
            return [[MONSecondProjectViewController alloc] init...];
        }
        else {
            assert(0 && "definitely break up your code, now that it is referenced by 3 or more projects");
            return 0;
        }
    }
    

    如果您只是维护同一个标题的两个版本,那么做法会大不相同。

    无论如何...这应该足以解决您的问题 - 您只需要确定较小的邪恶。

    【讨论】:

    • 如果问题出在 ExampleSentencesViewController.m 实现文件中,这将起作用。不幸的是,错误发生在另一个 VC 中,即 LOADS ExampleSentencesViewController 的那个 - 因此问题 - 我希望所有其他代码不知道它正在加载哪个 VC;我希望在编译时由目标决定。
    • 贾斯汀 - 我会赞成你如此彻底并给我考虑的要点 - 也许我应该在我的问题中更清楚。我确实使用您建议的方法让它工作 - 将标题包装在#ifdef 块中。我希望对于这类问题有一些优雅、性感的解决方案。无论如何,我将保持这个问题的开放性,希望有人能提供一个关于在这种情况下“应该”如何设置它的想法——甚至可能以不同的方式编码?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-08
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 2015-08-21
    相关资源
    最近更新 更多