使用C ++获取包中文件的路径(CFBundleGetMainBundle)

时间:2017-03-20 20:01:09

标签: c++ ios objective-c objective-c++

我正在编写一个包含C ++组件的iOS应用程序。为了获得主要包,许多其他答案建议使用:

CFBundleRef mainBundle = CFBundleGetMainBundle();

这很好,但似乎我必须包含类似

的内容
#include <UIKit/UIKit.h>

位于我的文件顶部。但这样做会引发一系列错误,如:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.2.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:494:9: Unknown type name 'NSString'

我认为这与我的C ++代码有关。我想知道是否还有其他我可以包含哪些内容并不会引发此错误?如果没有,在C ++代码中访问文件路径的正确方法是什么?

4 个答案:

答案 0 :(得分:2)

您可以尝试仅包含CoreFoundation

#include <CoreFoundation/CoreFoundation.h>

或者甚至只有CFBundle

#include <CoreFoundation/CFBundle.h>

答案 1 :(得分:0)

关键是 - 当您尝试#include时 - 它认为代码是Native C或C ++。如果是这样,您需要告诉预处理器仅在#ifndef ...包含它一次。

如果您计划混合使用C ++和Objective C代码 - 请使用#import代替#include,并且您需要使用此类从.m.mm重命名所有文件延期。

最后一个。我确信NSString是必须导入的NSFoundationCoreFoundation的一部分 - UIKit不对NSObject个对象负责。

答案 2 :(得分:0)

这是由于C&#34;编译单元&#34;的概念。基本上,您在源文件中包含的所有标头都必须使用该文件的语言编写。由于Objective C和C ++都是(大致)C的超集,因此可以在C ++和Objective-C源文件中包含C头(如CoreFoundation)。

但是,C ++编译器不知道如何读取Objective-C文件,而Objective-C编译器不知道如何读取C ++文件,所以如果你从C ++中包含像UIKit这样的Objective-C头文件文件,C ++编译器会给你很多错误信息。

要避免此问题,您应该查找CFBundle的文档。事实证明,CFBundle是CoreFoundation的一部分,它是一个C API,因此可以很容易地从C ++文件调用,你只需要包含正确的标题。

虽然包含UIKit可能也有效,但这只是UIKit的某些部分基于CoreFoundation并使用它的事实的副作用,因此包括CoreFoundation。

但是,并非所有API都可用作C版本。如果你想从UIKit或AVFoundation左右调用某些东西,你可能需要创建一个C&#34;包装函数&#34;做你想做的事情,内部是在Objective C中实现的。只要你确保只有.m实现文件包含Objective-C,并且头文件只暴露函数和标准C数据类型比如int或bool,你可以从C ++应用程序中调用函数,就像你使用任何其他普通的C函数一样(可能需要像使用常规C一样使用extern "C")。

还有一些名为&#34; Objective-C ++&#34; (文件后缀.mm),这是一种&#34;伪语言&#34;这使得你可以在实现文件中混合使用Objective-C和C ++,但即使这样,你也必须注意不要在头文件中暴露任何Objective-C,以便能够从普通的C ++文件中调用它。

答案 3 :(得分:0)

出于某种原因,CFBundleRef 不是 C++ 中的完整类型,我是这样做的:

#include <CoreFoundation/CFBundle.h>

std::string get_resources_dir()
{

  CFURLRef resourceURL = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
  char resourcePath[PATH_MAX];
  if (CFURLGetFileSystemRepresentation(resourceURL, true,
                                       (UInt8 *)resourcePath,
                                       PATH_MAX))
  {
    if (resourceURL != NULL)
    {
      CFRelease(resourceURL);
    }
    return resourcePath;
  }
}