/ / #ifdef замяна на Swift език - swift, xcode, препроцесор, препроцесор-директива

#ifdef замяна на Swift език - swift, xcode, препроцесор, препроцесор-директива

В C / C ++ / Objective-C можете да определите макрос, използвайки препроцесори на компилатор. Освен това можете да включите / изключите някои части от кода, използвайки препроцесори на компилатор.

#ifdef DEBUG
// Debug-only code
#endif

Има ли подобно решение в Swift?

Отговори:

857 за отговор № 1

Да, можете да го направите.

В Swift все още можете да използвате макросите на препроцесора "# if / # else / # endif" (макар и по-ограничени), според Документи на Apple, Ето един пример:

#if DEBUG
let a = 2
#else
let a = 3
#endif

Сега обаче трябва да зададете символа "DEBUG" другаде. Задайте го в секцията „Swift Compiler - Персонализирани флагове“, ред „Други Swift Flags“. Добавяте символа DEBUG с -D DEBUG влизане.

Както обикновено, можете да зададете различна стойност, когато сте в Debug или когато сте в Release.

Тествах го в реален код и той работи; изглежда, че не се разпознава в детска площадка.

Можете да прочетете оригиналния ми пост тук.


ВАЖНА ЗАБЕЛЕЖКА: -DDEBUG=1 не работи. Само -D DEBUG върши работа. Изглежда компилаторът игнорира флаг с конкретна стойност.


286 за отговор № 2

Както е посочено в Apple Документи

Компилаторът Swift не включва aпредпроцесорни. Вместо това се възползва от атрибутите за компилиране, изграждане на конфигурации и езикови функции, за да постигне същата функционалност. По тази причина директивите за препроцесори не се импортират в Swift.

Успях да постигна това, което исках с помощта на персонализирани конфигурации за изграждане:

  1. Отидете на вашия проект / изберете целта си / Настройки за изграждане / потърсете персонализирани флагове
  2. За избраната от вас цел задайте персонализирания си флаг, използвайки префикс -D (без бели интервали), както за отстраняване на грешки, така и за издаване
  3. Направете по-горе стъпки за всяка цел, която имате

Ето как проверявате целта:

#if BANANA
print("We have a banana")
#elseif MELONA
print("Melona")
#else
print("Kiwi")
#endif

въведете описанието на изображението тук

Тестван с помощта на Swift 2.2


145 за отговор № 3

В много ситуации наистина нямате нужда от условно компилация; просто се нуждаете от условно поведение че можете да включите и изключите. За това можете да използвате променлива среда. Това има огромното предимство, което всъщност не трябва да прекомпилирате.

Можете да зададете променливата на средата и лесно да я включите или изключите в редактора на схеми:

въведете описанието на изображението тук

Можете да извлечете променливата на средата с NSProcessInfo:

    let dic = NSProcessInfo.processInfo().environment
if dic["TRIPLE"] != nil {
// ... do secret stuff here ...
}

Ето пример от реалния живот. Приложението ми работи само на устройството, тъй като използва музикалната библиотека, която не съществува в симулатора. Как тогава да правя снимки на екрана на симулатора за устройства, които не притежавам? Без тези снимки на екрана не мога да изпратя AppStore.

нуждая се фалшиви данни и a различен начин на обработка, Имам две променливи на средата: този, който при включване казва на приложението да генерира фалшиви данни от реалните данни, докато работи на моето устройство; другият, който при включване използва фалшиви данни (а не липсващата музикална библиотека), докато работи на симулатора. Включването / изключването на всеки един от тези специални режими е лесно благодарение на квадратчетата за променлива среда в редактора на схемата. А бонусът е, че не мога да ги използвам случайно в моята версия на App Store, тъй като архивирането няма променливи на средата.


119 за отговор № 4

Основна промяна на ifdef заместване излезе с Xcode 8. т.е. използване на Активни условия за компилация.

Препоръчай на Изграждане и свързване в Xcode 8 Бележка за освобождаване.

Нови настройки за изграждане

Нова настройка: SWIFT_ACTIVE_COMPILATION_CONDITIONS

“Active Compilation Conditions” is a new build setting for passing conditional compilation flags to the Swift compiler.

Преди това трябваше да декларираме вашите условни флагчета за компилация под OTHER_SWIFT_FLAGS, като не забравяме да добавите „-D“ към настройката. Например, за условно компилиране със стойност MYFLAG:

#if MYFLAG1
// stuff 1
#elseif MYFLAG2
// stuff 2
#else
// stuff 3
#endif

Стойността, която трябва да добавите към настройката -DMYFLAG

Сега трябва само да предадем стойността MYFLAG на новата настройка. Време е да преместите всички тези условни стойности на компилация!

Моля, направете справка по-долу за повече информация за настройките на Swift Build в Xcode 8: http://www.miqu.me/blog/2016/07/31/xcode-8-new-build-settings-and-analyzer-improvements/


73 за отговор № 5

От Swift 4.1, ако всичко, от което се нуждаете, е само да проверите дали кодът е изграден с конфигурация за отстраняване на грешки или освобождаване, можете да използвате вградените функции:

  • _isDebugAssertConfiguration() (важи, когато оптимизацията е настроена на -Onone)
  • _isReleaseAssertConfiguration() (важи, когато оптимизацията е настроена на -O) (не се предлага на Swift 3+)
  • _isFastAssertConfiguration() (важи, когато оптимизацията е настроена на -Ounchecked)

например

func obtain() -> AbstractThing {
if _isDebugAssertConfiguration() {
return DecoratedThingWithDebugInformation(Thing())
} else {
return Thing()
}
}

В сравнение с макросите на препроцесора,

  • ✓ Не е нужно да дефинирате персонализиран -D DEBUG флаг, за да го използвате
  • ~ Това всъщност е дефинирано по отношение на настройките за оптимизация, а не конфигурация за изграждане на Xcode
  • ✗ Недокументирани, което означава, че функцията може да бъде премахната при всяка актуализация (но тя трябва да е безопасна за AppStore, тъй като оптимизаторът ще ги превърне в константи)

  • ✗ Използването на if / else винаги ще генерира предупреждение "Няма да бъде изпълнено".


72 за отговор № 6

употреба Активни условия за компилация настройка в Настройки за изграждане / Swift компилатор - Персонализирани флагове.

  • Това е новата настройка за сглобяване за предаване на условни флагове за компилация към компилатора Swift.
  • Прости добавяне на знамена като този: ALPHA, BETA и т.н.

След това го проверете условия за съставяне като този:

#if ALPHA
//
#elseif BETA
//
#else
//
#endif

Съвет: Можете също да използвате #if !ALPHA и т.н.


69 за отговор № 7

Няма препроцесор Swift. (От една страна, произволното заместване на кодове нарушава безопасността на типа и паметта.)

Swift обаче включва опции за конфигуриране на време за изграждане, така че можете условно да включите код за определени платформи или стилове на изграждане или в отговор на флагове, които определяте с -D аргументи компилатор. За разлика от C обаче, условно компилиран раздел от кода ви трябва да бъде синтактично пълен. Има раздел за това в Използване на Swift с какао и Objective-C.

Например:

#if os(iOS)
let color = UIColor.redColor()
#else
let color = NSColor.redColor()
#endif

39 за отговор № 8

Двата ми цента за Xcode 8:

а) Персонализиран флаг, използващ -D префиксът работи добре, но ...

б) По-лесно използване:

В Xcode 8 има нов раздел: "Условия за активна компилация", вече с два реда, за отстраняване на грешки и освобождаване.

Просто добавете своето определение БЕЗ -D.


24 за отговор № 9

isDebug Constant Въз основа на условията за активна компилация

Друго, може би по-просто решение, което все още води до булева, която можете да преминете във функции без да пипер #if условностите във вашата кодова база е да дефинирате DEBUG като една от целите за изграждане на вашия проект Active Compilation Conditions и включвам следното (определям го като глобална константа):

#if DEBUG
let isDebug = true
#else
let isDebug = false
#endif

isDebug Constant Въз основа на настройките за оптимизация на компилатора

Тази концепция надгражда отговор на kennytm

Основното предимство при сравняване с kennytm "s е, че това не разчита на частни или недокументирани методи.

в Swift 4:

let isDebug: Bool = {
var isDebug = false
// function with a side effect and Bool return value that we can pass into assert()
func set(debug: Bool) -> Bool {
isDebug = debug
return isDebug
}
// assert:
// "Condition is only evaluated in playgrounds and -Onone builds."
// so isDebug is never changed to true in Release builds
assert(set(debug: true))
return isDebug
}()

В сравнение с макросите на препроцесора и отговор на kennytm,

  • ✓ Не е нужно да дефинирате персонализиран -D DEBUG флаг, за да го използвате
  • ~ Това всъщност е дефинирано по отношение на настройките за оптимизация, а не конфигурация за изграждане на Xcode
  • Документирана, което означава, че функцията ще следва нормални модели на освобождаване / премахване на API.

  • ✓ Използване, ако / друго ще не генерира предупреждение "Няма да бъде изпълнено"


2 за отговор № 10

След настройването DEBUG=1 във вашия GCC_PREPROCESSOR_DEFINITIONS Настройки за изграждане Предпочитам да използвам функция за извършване на тези обаждания:

func executeInProduction(_ block: () -> Void)
{
#if !DEBUG
block()
#endif
}

И след това просто включете в тази функция всеки блок, който искам да бъде пропуснат в Debug builds:

executeInProduction {
Fabric.with([Crashlytics.self]) // Compiler checks this line even in Debug
}

Предимството в сравнение с:

#if !DEBUG
Fabric.with([Crashlytics.self]) // This is not checked, may not compile in non-Debug builds
#endif

Че компилаторът проверява синтаксиса на моя код, така че съм сигурен, че синтаксисът му е правилен и се изгражда.


1 за отговор № 11

Това надгражда Джон Уилис " отговор, който разчита на твърдение, който се изпълнява само в компилациите на Debug:

func Log(_ str: String) {
assert(DebugLog(str))
}
func DebugLog(_ str: String) -> Bool {
print(str)
return true
}

Моят случай за използване е за записване на отчети за печат. Ето еталон за версията на Release на iPhone X:

let iterations = 100_000_000
let time1 = CFAbsoluteTimeGetCurrent()
for i in 0 ..< iterations {
Log ("⧉ unarchiveArray:(fileName) memoryTime:(memoryTime) count:(array.count)")
}
var time2 = CFAbsoluteTimeGetCurrent()
print ("Log: (time2-time1)" )

отпечатъци:

Log: 0.0

Изглежда, че Swift 4 напълно елиминира повикването на функцията.


0 за отговор № 12

! [В Xcode 8 и по-горе отидете да изградите настройка -> търсене на персонализирани знамена ]1

В код

 #if Live
print("Live")
#else
print("debug")
#endif