导入前框架的条件编译检查

Posted

技术标签:

【中文标题】导入前框架的条件编译检查【英文标题】:Conditional compilation check for framework before importing 【发布时间】:2011-11-12 00:10:44 【问题描述】:

在导入和使用该框架之前,我正在寻找一种方法来检查框架是否存在和/或它的类是否已定义。具体来说,框架就是 Assets Library。

目前,我可以使用 Core Data 框架来执行此操作,因为该框架有一个名为 CoreDataDefines.h 的文件,它提供了一个预处理器指令 _COREDATADEFINES_H。这使我可以像这样简单地检查该定义:

#ifdef _COREDATADEFINES_H
#import <CoreData/CoreData.h>

// do something with Core Data

#else

// do something without using Core Data

#endif

不幸的是,资产库没有提供清晰的定义头文件,所以我正在寻找一种方法来编写自己的 #define 语句,该语句可以在导入框架之前检查框架是否存在,就像我所做的那样对于上面的核心数据。

我试过这个:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
// import assets library if defined !
#define ASSETSLIBRARY_DEFINE    (NSClassFromString(@"ALAsset") != nil)
#if ASSETSLIBRARY_DEFINE
#import <AssetsLibrary/AssetsLibrary.h>
#endif
#endif

...但没有运气。 编译器告诉我“令牌不是预处理器子表达式中的有效二元运算符。”

我们非常感谢任何帮助。

【问题讨论】:

你考虑过使用CMake吗?它可以检查现有的 Mac OS X 框架。我不知道如何查找 ios 框架,但作为最后的手段,您可以编写自己的 cmake 模块来查找它。 这有点不对劲。 感谢@Maciek 提供的信息,但我认为 CMake 不是我想要的。基本上我只想要一个预处理器指令来检查项目包的框架中是否存在头文件。 在哪里可以找到解决方案? 【参考方案1】:

如果您知道应该使用框架导入哪个类,您可以检查它是否已加载:

BOOL isFrameworkLoaded = (NSClassFromString(@"MyClassNameFromTheFramework") != nil);

【讨论】:

【参考方案2】:

你在这里做的是非常错误的。您在 CoreDataDefines.h 中看到的 _COREDATADEFINES_H 定义被称为标记值,​​这是一种旧的 C 技术,用于避免多次包含同一头文件。

您当然不应该在自己的代码中使用它,并且哨兵的存在只会告诉您标头已经包含在其他地方。如果未定义哨兵,则仅表示标头被包含,而不是框架本身不存在。

我不确定您到底要做什么,但您似乎想使用宏来决定使用框架的代码和不使用框架的代码。如果您想在编译时执行此操作,您唯一的选择是定义自己的宏并使用一些编译器选项在您的目标中设置它们。例如,要启用使用资产库的代码,您可以在“Other C Flags”构建设置中定义:

-DUSE_ASSETS_FRAMEWORK

然后在你的代码中使用它:

#ifdef USE_ASSETS_FRAMEWORK
    #import <AssetsLibrary/AssetsLibrary.h>
    // code that uses assets framework
#else
    // code that does not use assets framework
#endif

如果您希望能够在运行时检测应用程序是否链接到框架并且该框架存在于当前 iOS 版本上,您应该使用 Apple 推荐的标准方法,即测试任何类的存在或您需要的功能:

if (NSClassFromString(@"ALAsset")) 
    // ALAsset is available 
 else 
    // ALAsset not available

【讨论】:

感谢迈克提供的信息。我正在尝试创建一个跨项目框架,当某个框架尚未导入时,该框架可以自动省略代码。这就是我所说的“不存在”的意思......即在使用我的框架的当前项目中不存在。所以,如果可能的话,我宁愿不必在每个项目中设置宏。这就是我试图避免的。我也考虑过运行时建议,但它会产生编译时错误,并在未检测到资产库框架时阻止我运行代码。【参考方案3】:

我对这种事情有一些技巧......虽然下面的内容可能无法完全解决您详述的问题,但这可能会很好地帮助您找到最终解决方案......第一个“策略”可以在“脚本构建”中调用阶段”。这可以以多种方式使用,但在此示例中,它测试框架是否有效,(根据otool,然后相应地进行一些“后处理”......然后再次对其进行测试......等等。 .

function test  "$@";   status=$?;
    if [ $status -ne 0 ]; then
       echo "error with $1"; fi 
    return $status

  PRODUCT_PATH="$BUILT_PRODUCTS_DIR/$WRAPPER_NAME"
        BINARY="$PRODUCT_PATH/$PRODUCT_NAME"
           MAC="/Library/Frameworks/"
SYSTEM_PRODUCT="$MAC/$WRAPPER_NAME"

test otool -l "$BINARY" #/Library/Frameworks/AtoZ.framework/AtoZ
if [ $status -ne 0 ]; then
   sudo rm -r "$SYSTEM_PRODUCT"
   sudo cp -r "$PRODUCT_PATH" "$SYSTEM_PRODUCT"
test otool -l "$BINARY" 
if [ $status == 0 ]; then
   cd "$PRODUCT_PATH"
   ln -sF Versions/Current/Frameworks Frameworks
fi

这种智慧的下一个传承免费是性感的,并且恰当地命名为NSBundle方法.. preflightAndReturnError p>

NSBundle *b = [NSBundle bundleWithPath:path];
NSError *e  = nil;
BOOL okdok  = [b preflightAndReturnError:&e];
if  (okdok)  
     okdok  = [b load];
if (!okdok)  [self jumpOffABridge:nil]; goto hell; 

虽然有可能......你会是..OK DOK,等load 结束。

【讨论】:

以上是关于导入前框架的条件编译检查的主要内容,如果未能解决你的问题,请参考以下文章

SDWebImage源码阅读前的准备预处理条件编译

golang项目中使用条件编译

iOS swift 条件编译语句

MSBuild 条件编译

solidity数据类型storage memory calldata modifier前置条件 继承 接口合约 导入库 using...for solc编译

预处理指令typedef条件编译多文件代码