objective-c - 在Xcode中组织大型Cocoa应用程序源代码的最佳方法是什么?

标签 objective-c xcode cocoa modularity

这是我在寻找的东西:

我想将功能片段分成某种模块或组件,以限制其他类的可见性,以防止每个类都可以访问其他每个类,这随着时间的流逝会导致产生意粉代码。

例如,在Java和Eclipse中,我将使用软件包并将每个软件包放入具有明确定义的依赖关系结构的单独项目中。

我考虑过的事情:

  • 使用单独的文件夹作为源文件,并在Xcode中使用组:
  • 优点:操作简单,几乎不需要Xcode配置
  • 缺点:没有功能上的编译时分离,即访问所有内容仅是一个#import语句而已
  • 使用框架:
  • 优点:框架代码无法访问框架外部的访问类。这将强制执行封装,并将各事物分开
  • 缺点:如果您同时在多个Framework上工作,则代码管理会很麻烦。每个框架都是一个单独的Xcode项目,带有一个单独的窗口
  • 使用插件:
  • 优点:与框架类似,插件代码无法访问其他插件的代码。在编译时进行干净的分离。插件源可以是同一Xcode项目的一部分。
  • 缺点:不确定。这可能是要走的路...

  • 根据您的经验,在能够编辑同一项目中的所有源代码的同时,您会选择什么使它们分开?

    编辑:
  • 我的目标是Mac OS X
  • 我真的在寻找一种在编译时强制分离的解决方案
  • 所谓的插件是指 cocoa 捆绑包(http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/LoadingCode/Concepts/Plugins.html)
  • 最佳答案

    我已经处理了一些大型Mac项目(在90个xcodeproj文件中的最后一个中,> 2M SLOC),这是我对它们进行管理的想法:

  • 除非您实际上在组之间共享二进制文件,否则避免使用诸如Frameworks,Bundle或dylib之类的动态负载。这些往往会导致复杂性超出我的经验所能解决的。另外,它们不容易移植到iOS,这意味着需要维护多种方法。最糟糕的是,拥有大量动态库会增加两次包含相同符号的可能性,从而导致各种疯狂的错误。当您直接在多个库中直接包含一些“帮助”类时,就会发生这种情况。如果它包含一个全局变量,那么由于不同的线程使用了全局变量的不同实例,这些错误就很糟糕。
  • 在很多情况下(即使不是大多数情况),静态库也是最佳选择。它们在构建时解决了所有问题,从而允许在C/C++中剥离代码以及进行动态库中无法进行的其他优化。他们摆脱了“嘿,它加载到我的系统上,而不加载到我的系统上”(当您为框架路径使用错误的值时)。从崩溃堆栈计算行号时,无需处理幻灯片。它们在构建时捕获重复的符号,从而节省了许多小时的调试工作。
  • 将主要组件分离为单独的xcodeproj。不过,请真正考虑一下“主要”的含义。我的90个项目的产品太多了。仅进行依赖项检查可能会成为一项非常重要的工作。 (Xcode 4可以改善这一点,但是我在能够获得Xcode 4可靠地构建它之前就离开了该项目,所以我不知道最终效果如何。)
  • 将public和private header 分开。您可以像使用Framework一样使用静态库来执行此操作。将公共(public)头文件放在其他目录中。我建议每个组件为此都有自己的公共(public)include目录。
  • 不要复制标题。直接从组件的公共(public)include目录中包含它们。将 header 复制到共享树中似乎是个好主意,除非您这样做。然后,您发现您正在编辑副本而不是真实副本,或者您正在编辑真实副本,但并未实际复制它。无论如何,它使发展令人头疼。
  • Use xcconfig files, not the build pane.构建 Pane 将使您对这类大项目感到疯狂。我的行往往像这样:

  • common="../../common"
    foo="$(common)/foo"
    HEADER_SEARCH_PATHS = $(inherited) $(foo)/include
    

  • 在公共(public) header 路径中,包括您自己的捆绑包名称。在上面的示例中,主 header 的路径为common/foo/include/foo/foo.h。额外的关卡似乎很痛苦,但是当您导入时,这是一个真正的胜利。然后,您总是像这样导入:#import <foo/foo.h>。保持一切都很干净。不要使用双引号导入公共(public) header 。仅使用双引号将私有(private) header 导入您自己的组件中。
  • 我尚未决定Xcode 4的最佳方法,但在Xcode 3中,应始终通过将项目添加为子项目并将“.a”目标拖动到链接步骤中来链接自己的静态库。以这种方式进行操作可确保您将链接为当前平台和配置构建的版本。我非常庞大的项目还无法转换为Xcode 4,因此对于目前的最佳方法,我还没有强烈的意见。
  • 避免搜索自定义库(链接步骤中的-L-l标志)。如果您将库作为项目的一部分进行构建,请使用上面的建议。如果您预先构建它,则在LD_FLAGS中添加完整路径。搜索库包括一些令人惊讶的算法,这使整个事情变得难以理解。切勿将预先构建的库放到链接步骤中。如果将预先构建的libssl.a放到链接步骤中,它实际上为路径添加了-L参数,然后添加了-lssl。在默认搜索规则下,即使您在构建 Pane 中显示libssl.a,您实际上仍将链接到系统libssl.so。删除库将删除-l,但不会删除-L,因此您可能会发现奇怪的搜索路径。 (我讨厌构建 Pane 。)相反,在xcconfig中这样做:

  • LD_FLAGS = "$(openssl)/lib/libssl.a"
    

  • 如果您有在几个项目之间共享的稳定代码,并且在开发这些项目时永远不会弄乱该代码(并且不希望获得源代码),那么使用Framework是一种合理的方法。如果您需要插件来避免加载大量不必要的代码(并且在大多数情况下确实不会加载该代码),则捆绑软件可能是合理的。但是在大多数情况下,对于应用程序开发人员来说,将静态库链接在一起的一个大型可执行文件是IMO的最佳方法。共享库和框架只有在运行时实际共享时才有意义。
  • 关于objective-c - 在Xcode中组织大型Cocoa应用程序源代码的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6625399/

    相关文章:

    iphone - 将 RSA key 导入 iPhone 钥匙串(keychain)?

    ios - Xcode 5.1 打破了一些测试

    swift - 节点联系时收到错误

    ios - 如何从核心数据中的字符串获取处理后的字符串

    objective-c - 将 NSTextField 的 Enabled 属性绑定(bind)到 BOOL 属性

    objective-c - 如何让 NSTimer 在调整 timeInterval 时继续 - iOS

    objective-c - Cocos2D : Gap in scrolling background

    cocoa - 在 Cocoa 程序中访问 Swift REPL

    objective-c - 像 Objective-C 中的 Python 那样的原始字符串

    xcode - 由于错误,Scheme 加载失败