开发者

Conditional compilation check for framework before importing

I'm looking for a way to check if a framework exists and/or if it's classes are defined, before importing and using that framework. Specifically, the framework is Assets Library.

Currently, I'm able to do this with the Core Data framework, since that framework has a file called CoreDataDefines.h which provides a preprocessor directive _COREDATADEFINES_H. This allows me to simply check for that defintion like so:

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

// do something with Core Data

#else

// do something without using Core Data

#endif

Unfortunately, the Assets Library does not provide a clear definitions header file so I'm looking for a way to write my own #define statement that can check for the framework's existence before importing it, much like I have done for Core Data above.

I have tried this:

#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

... but no luck.

The compiler tells me that the "Token is not a valid binary operator in a preprocessor subexpression."

Any help is always much appreciated.


If you know what class should be imported with the framework you can check if it is loaded:

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


What you're doing here is very wrong. The _COREDATADEFINES_H define you see in CoreDataDefines.h is known as the sentinal value, an old C technique to avoid multiple inclusions of the same header file.

You should certainly not be using this in your own code, and the presence of the sentinal only tells you that the header has already been included somewhere else. If the sentinal is not defined, it simply means the header has not been included, not that the framework itself is nonexistant.

I'm not sure exactly what you are trying to do, but it looks like you want to use macros to decide between code that uses the framework, and code that doesn't use the framework. If you want to do this at compile time, your only choice is to define your own macros and set them up in your target with some compiler options. For example, to enable code that uses the assets library you might define this in the "Other C Flags" build setting:

-DUSE_ASSETS_FRAMEWORK

And then use this in your code:

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

If you want to be able to detect at runtime whether the app is linked against the framework and that the framework exists on the current iOS version, you should use the standard approach that Apple recommends which is to test the existance of any classes or functions you need:

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


I have a few tricks for this kind of thing… Though what follows may not EXACTLY solve the problems you detailed, this may well aide in finding your ultimate solution… The first "strategy" can be called upon in a "Script Build Phase". This can be used in many ways, but in this example it TESTS that the Framework is valid, (according to otool, and then does some "post-processing" accordingly.. and then tests it again.. and so on..

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

The next hand-me-down in this wisdom free-for-all is the sexy, and aptly named NSBundle method.. preflightAndReturnError

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; }

Chances are though… you'll be.. OK DOK, by the time load finishes up.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜