Условная проверка компиляции для фреймворка перед импортом - PullRequest
14 голосов
/ 07 сентября 2011


Я ищу способ проверить, существует ли фреймворк и / или определены ли его классы, прежде чем импортировать и использовать этот фреймворк. В частности, это библиотека ресурсов.

В настоящее время я могу сделать это с платформой 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

... но не повезло.
Компилятор сообщает мне, что «токен не является допустимым двоичным оператором в подвыражении препроцессора».


Любая помощь всегда ценится.

Ответы [ 3 ]

4 голосов
/ 07 сентября 2011

Если вы знаете, какой класс должен быть импортирован с фреймворком, вы можете проверить, загружен ли он:

BOOL isFrameworkLoaded = (NSClassFromString(@"MyClassNameFromTheFramework") != nil);
1 голос
/ 19 мая 2013

У меня есть несколько хитростей для такого рода вещей ... Хотя то, что следует, может НЕ ТОЧНО решить проблемы, которые вы подробно описали, это может помочь в поиске вашего окончательного решения ... Первая «стратегия» может быть вызвана в «Script BuildФаза».Это можно использовать по-разному, но в этом примере он ИСПЫТЫВАЕТ, что Framework действительна (в соответствии с 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

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 закончится.

1 голос
/ 07 сентября 2011

То, что вы делаете здесь, очень неправильно. _COREDATADEFINES_H определяет, что вы видите в CoreDataDefines.h, известен как часовое значение, старый метод C, чтобы избежать множественных включений одного и того же заголовочного файла.

Вы, конечно, не должны использовать это в своем собственном коде, и присутствие часового только говорит вам, что заголовок уже был включен где-то еще. Если часовой не определен, это просто означает, что заголовок содержит , а не , а не то, что сам фреймворк не существует.

Я не уверен, что именно вы пытаетесь сделать, но похоже, что вы хотите использовать макросы для выбора между кодом, использующим каркас, и кодом, который не использует каркас. Если вы хотите сделать это во время компиляции, ваш единственный выбор - определить свои собственные макросы и настроить их в своей цели с некоторыми опциями компилятора. Например, чтобы включить код, использующий библиотеку ресурсов, вы можете определить это в параметре сборки «Другие флаги C»:

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