Настройка условного кода в подпроекте - PullRequest
2 голосов
/ 27 августа 2010

У меня есть проект с библиотечным подпроектом, который импортируется.У меня есть доступ к исходному коду основного проекта и подпроекта.

В подпроекте используется Core Text.Поскольку подпроект должен использоваться в приложениях до и после версии 3.2, Core Text слабо связан, и весь связанный с Core Text код обернут в логику:

#if defined(__CORETEXT__) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2

Идея этой строки кода заключается в том, чтоесли CoreText не связан, код пропускается.Если версия iPhone меньше 3.2;CoreText не связан с.

Причина этой цели заключается в том, что основной (ые) проект (ы) не все используют Core Text, а если нет, то без 'определенные (*)1008 * CORETEXT ) `, они не будут компилироваться.

Этот кажется работает нормально, и все компилируется без ошибок в проектах, использующих Core Text.Однако при выполнении код не найден, и во время выполнения появляется ошибка «NSString не отвечает на XXXX» (часть кода относится к категории NSString).

Кто-нибудь сталкивался с этим?Мой вопрос, частично расплывчатый, из-за того, что он работает с клиентом, понятен?

В идеале я хочу настроить это так, чтобы подпроект не нужно было изменять, когда основной проект использует Core Text, а когда нет.

Обратите внимание, что __CORETEXT__ определено в заголовке платформы Core Text.

Обновление по проблеме

Я попробовал предложенные предложения, и они неэффективны,Возможно, немного больше кода поможет обрисовать проблему.У меня есть категория со следующим заголовком:

@interface NSString (Internal)

- (NSString *)stringByUnescapingEntities;
- (NSString *)flattenHTML;
- (NSString *)flattenHTMLAndParseParagraphBreaks:(BOOL)parseBreaks;
- (NSString *)stringByEscapingForURL;
- (NSString *)stringByEscapingForJSON;

#if defined(__CORETEXT__) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
- (CFAttributedStringRef)attributedStringFromHTML;
- (CFAttributedStringRef)attributedStringFromHTMLWithBaseAttributes:(NSDictionary*)baseAttributes;
#endif

@end

Положительный тест

Все методы за пределами блока #if работают отлично.Все методы внутри #if компилируют отлично, без предупреждений.

Отрицательный тест

Если я изменю __CORETEXT__ на что-то вроде __THIS_IS_NOT_REAL__, я получу ошибку компиляции для методов внутри блока.Поэтому я знаю, по крайней мере, во время компиляции, что флаг __CORETEXT__ определен и полностью функционален.

Проблема времени выполнения

Однако, когда я обращаюсь к одному из объявленных методоввнутри блока #if я получаю следующую ошибку во время выполнения:

- [NSCFString attribuStStringFromHTMLWithBaseAttributes:]: нераспознанный селектор, отправленный экземпляру 0x689c000

Экземпляр 0x689c000будучи NSString.

Если я уберу проверку логики __CORETEXT__, то все будет работать, пока главный проект использует Core Text.Если мастер-проект не использует Core Text, появляются ошибки компиляции с отсутствующими компоновщиками.

Надеемся, что это решает проблему.

ПРИМЕЧАНИЕ: Все проекты используют -all_load флаг;как это было необходимо для TouchXML уже.

Я создал тестовый проект, который демонстрирует проблему.

Тестовый проект

Ответы [ 7 ]

2 голосов
/ 27 августа 2010

Тот факт, что вы говорите, что по крайней мере одна вещь, которая в конечном итоге отсутствует, является методом категории для NSString, заставляет меня думать, что вы столкнулись с прекрасной проблемой, которая, возможно, является возможной ошибкой в ​​компоновщике.

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

Во-вторых, в некоторых моих отношениях с использованием библиотеки Three20для iPhone стало необходимо также использовать этот странный «хак», который применяется, если, например, ваша категория NSString является единственной вещью в файле .m, где она реализована.

//CategoryBugHack.h
#define FIX_CATEGORY_BUG(name) @interface FIX_CATEGORY_BUG##name @end @implementation FIX_CATEGORY_BUG##name @end

Затем категория.h / .m ...

//NSStringCategory.h
@interface NSString (MyAdditions)
// etc, etc
@end

//NSStringCategory.m
#import "CategoryBugHack.h"
FIX_CATEGORY_BUG(NSString_MyAdditions)
@implementation NSString (MyAdditions)
// etc, etc
@end

В принципе, существует дополнительная проблема, связанная со статическими библиотеками, где файл реализации содержит ТОЛЬКО реализации методов категорий.Макрос FIX_CATEGORY_BUG в основном просто расширяется, чтобы определить интерфейс и реализацию этого интерфейса без каких-либо методов, просто чтобы вставить что-то в файл .m, который не является категорией.

1 голос
/ 27 августа 2010

Вы могли бы сделать [NSObject responsedsToSelector:] проверки, чтобы видеть, доступен ли метод категории.

Редактировать: Я думаю, что я не полностью прочитал вопрос в первый раз.Вот еще пара вещей, которые я видел.

Это #if, вероятно, не будет работать.Это потому, что все это проверяется во время компиляции, а не во время выполнения.Я не совсем уверен в том, что включается при слабом связывании, но, насколько я понимаю, заголовок слабосвязанного фреймворка будет обрабатываться во время компиляции.Это означает, что символы для прототипов методов будут доступны при сборке, поэтому нет ошибок или предупреждений при сборке.

Я также на 99% уверен, что проверка iOS не будет работать.Это только проверяет максимально допустимую версию, которая устанавливается во время компиляции.Если вы не делаете разные сборки с разными настройками для каждой iOS (что, как я полагаю, нет), это почти всегда будет одинаковым значением независимо от того, на каком устройстве вы работаете.

Вам определенно понадобятся проверки во время выполнения (например, вышеупомянутый RespondsToSelector).Проверка версии устройства iOS также может быть выполнена только во время выполнения.

0 голосов
/ 13 декабря 2011

Ответ в двух частях:

  • CoreText.h импортируется в файл PCH вашего приложения, но нигде в библиотеке (PCH не каскадируются). Поэтому в библиотеке код __CORETEXT__ всегда выводится #ifdef. Однако, когда экспортированный заголовок из библиотеки компилируется в приложении, включается прототип метода #ifdef 'd , и поэтому вы не получаете время компиляции предупреждений для этого метода на NSString.

    Быстрое решение проблемы - буквальное выражение

    #import <CoreText/CoreText.h>
    

    в файле PCH вашей библиотеки. Что, конечно, побеждает цель того, что вы пытаетесь сделать.

    Исправление - это еще одна тема, но я подозреваю, что вам лучше использовать свой собственный -D или #define, а затем пытаться каскадировать этот подпроект, хотя я пока не знаю, как это сделать сам.

  • Один хороший способ временно проверить, компилируется ли ваш код #ifdef, - поставить условные выражения #error, например,

    #ifdef WHEE
         // compile-time error will happen here
         #error
    #endif
    
0 голосов
/ 28 августа 2010

Я полагаю, что недавно обнаружил похожую ситуацию, и, как я уже говорил вам в твиттере, вам нужно установить -ObjC в дополнение к -all_load, как описано здесь: http://developer.apple.com/mac/library/qa/qa2006/qa1490.html

0 голосов
/ 27 августа 2010

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

Редактировать: Значит, подпроект может быть настроен на компиляцию в соответствии с 3.1.3 и возможно никогда не соответствует вашей логике?

0 голосов
/ 27 августа 2010

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

if ([theReceiver respondToSelector:@selector(mySelector:)]){
   objc_msgSend(theReceiver, @selector(mySelector:), param1);
}else{
   // do it other way here.
}

Не самый красивый код, который я написал, и я не пытался раньше, но, возможно, возможно добавить ваши методы и ivars с функциями времени выполнения, такими как class_addIvar, class_addMethod и т. Д.*

0 голосов
/ 27 августа 2010

Может быть, вы должны превратить условное в

#if defined(__CORETEXT__) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2)

В конце концов, остальная часть ссылочного проекта связана, верно? Проблема должна быть условной препроцессора.

...