使用 C++ (CFBundleGetMainBundle) 获取包中文件的路径
Get path to a file in a bundle with C++ (CFBundleGetMainBundle)
我正在编写一个具有 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++ 代码中访问文件路径的正确方法是什么?
您可以尝试只包含 CoreFoundation
#include <CoreFoundation/CoreFoundation.h>
或者甚至可能只有 CFBundle
#include <CoreFoundation/CFBundle.h>
重点是 - 当您尝试 #include
- 它认为代码是本机 C 或 C++。如果是这样,您需要通过 #ifndef ...
.
告诉预处理器只包含一次它
如果您打算混合使用 C++ 和 Objective C 代码 - 使用 #import
而不是 #include
并且您需要重命名所有文件,使用 class 来自 .m
到 .mm
扩展名。
最后一个。我确信 NSString
是必须导入的 NSFoundation
或 CoreFoundation
的一部分 - UIKit
不对 NSObject
对象负责。
这是由于C的概念"compilation units"。基本上,您在源文件中包含的所有 header 都必须使用该文件的语言编写。由于 Objective C 和 C++ 都是(大致)C 的超集,因此您可以在 C++ 和 Objective-C 源文件中包含 C headers(如 CoreFoundation)。
但是,C++ 编译器不知道如何读取 Objective-C 文件,Objective-C 编译器也不知道如何读取 C++ 文件,因此如果包含 Objective-C header 就像 C++ 文件中的 UIKit,C++ 编译器会给你很多错误信息。
为避免此问题,您应该查阅 CFBundle 的文档。事实证明,CFBundle 是 CoreFoundation 的一部分,它是一个 C API,因此可以很容易地从 C++ 文件中调用,您只需要包含正确的 header.
虽然包含 UIKit 也可能有效,但这只是 UIKit 的某些部分基于 CoreFoundation 并使用它的事实的副作用,因此包含 CoreFoundation。
但是,并非所有 API 都可以作为 C 版本使用。如果你想从 UIKit 或 AVFoundation 左右调用一些东西,你可能必须创建一个 C "wrapper function" 来做你想做的事情,并在内部实现 Objective C。只要确保只有 .m
实现文件包含 Objective-C,而 header 文件只公开函数和标准 C 数据类型,如 int 或 bool,您就可以调用来自 C++ 应用程序的函数就像您使用任何其他纯 C 函数一样(这可能需要像使用常规 C 一样使用 extern "C"
)。
还有一个叫做"Objective-C++"(文件后缀.mm
)的东西,就是一个"pseudo-language",可以让你在一个实现文件中混合Objective-C和C++,但是即使这样,您也必须小心不要在 header 中公开任何 Objective-C 以便能够从普通 C++ 文件中调用它。
由于某些原因,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;
}
}
我正在编写一个具有 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++ 代码中访问文件路径的正确方法是什么?
您可以尝试只包含 CoreFoundation
#include <CoreFoundation/CoreFoundation.h>
或者甚至可能只有 CFBundle
#include <CoreFoundation/CFBundle.h>
重点是 - 当您尝试 #include
- 它认为代码是本机 C 或 C++。如果是这样,您需要通过 #ifndef ...
.
如果您打算混合使用 C++ 和 Objective C 代码 - 使用 #import
而不是 #include
并且您需要重命名所有文件,使用 class 来自 .m
到 .mm
扩展名。
最后一个。我确信 NSString
是必须导入的 NSFoundation
或 CoreFoundation
的一部分 - UIKit
不对 NSObject
对象负责。
这是由于C的概念"compilation units"。基本上,您在源文件中包含的所有 header 都必须使用该文件的语言编写。由于 Objective C 和 C++ 都是(大致)C 的超集,因此您可以在 C++ 和 Objective-C 源文件中包含 C headers(如 CoreFoundation)。
但是,C++ 编译器不知道如何读取 Objective-C 文件,Objective-C 编译器也不知道如何读取 C++ 文件,因此如果包含 Objective-C header 就像 C++ 文件中的 UIKit,C++ 编译器会给你很多错误信息。
为避免此问题,您应该查阅 CFBundle 的文档。事实证明,CFBundle 是 CoreFoundation 的一部分,它是一个 C API,因此可以很容易地从 C++ 文件中调用,您只需要包含正确的 header.
虽然包含 UIKit 也可能有效,但这只是 UIKit 的某些部分基于 CoreFoundation 并使用它的事实的副作用,因此包含 CoreFoundation。
但是,并非所有 API 都可以作为 C 版本使用。如果你想从 UIKit 或 AVFoundation 左右调用一些东西,你可能必须创建一个 C "wrapper function" 来做你想做的事情,并在内部实现 Objective C。只要确保只有 .m
实现文件包含 Objective-C,而 header 文件只公开函数和标准 C 数据类型,如 int 或 bool,您就可以调用来自 C++ 应用程序的函数就像您使用任何其他纯 C 函数一样(这可能需要像使用常规 C 一样使用 extern "C"
)。
还有一个叫做"Objective-C++"(文件后缀.mm
)的东西,就是一个"pseudo-language",可以让你在一个实现文件中混合Objective-C和C++,但是即使这样,您也必须小心不要在 header 中公开任何 Objective-C 以便能够从普通 C++ 文件中调用它。
由于某些原因,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;
}
}