답변:
그렇습니다 당신은 그것을 할 수 있습니다.
Swift에서는 Apple 문서에 따라 여전히 "# if / # else / # endif"전 처리기 매크로를 사용할 수 있습니다 (더 제한적 임) . 예를 들면 다음과 같습니다.
#if DEBUG
let a = 2
#else
let a = 3
#endif
이제 "DEBUG"기호를 다른 곳에 설정해야합니다. "Swift Compiler-Custom Flags"섹션, "Other Swift Flags"라인에서 설정하십시오. -D DEBUG
항목 과 함께 DEBUG 기호를 추가합니다 .
일반적으로 디버그 또는 릴리스시 다른 값을 설정할 수 있습니다.
실제 코드로 테스트했으며 작동합니다. 운동장에서는 인식되지 않는 것 같습니다.
내 원래 게시물을 여기에서 읽을 수 있습니다 .
중요 사항 : -DDEBUG=1
작동하지 않습니다. 만 -D DEBUG
작동합니다. 컴파일러가 특정 값을 가진 플래그를 무시하는 것 같습니다.
-D DEBUG
상술 한 바와 같이, 당신은 또한 정의 할 필요가 DEBUG=1
에서 Apple LLVM 6.0 - Preprocessing
-> Preprocessor Macros
.
-DDEBUG
이 답변 의 형식을 stackoverflow.com/a/24112024/747369 로 변경하기 전까지는이 작업을 수행 할 수 없었습니다 .
DEBUG=1
할 필요 Preprocessor Macros
가 없습니다.
Apple Docs에 명시된 바와 같이
Swift 컴파일러에는 전처리 기가 포함되어 있지 않습니다. 대신 컴파일 타임 속성, 빌드 구성 및 언어 기능을 활용하여 동일한 기능을 수행합니다. 이러한 이유로 전 처리기 지시문은 Swift에서 가져 오지 않습니다.
사용자 정의 빌드 구성을 사용하여 원하는 것을 달성했습니다.
대상을 확인하는 방법은 다음과 같습니다.
#if BANANA
print("We have a banana")
#elseif MELONA
print("Melona")
#else
print("Kiwi")
#endif
Swift 2.2를 사용하여 테스트
-DLOCAL
내 사용자 지정 플래그를 설정하면 내 섹션 #if LOCAl #else #endif
에 해당 #else
합니다. 원래 대상을 복제 AppTarget
하고 이름을 바꾸고 AppTargetLocal
맞춤 플래그를 설정했습니다.
#if LOCAL
시뮬레이터로 실행할 때 의도 한 결과에 도달하고 #else
테스트 중에 빠진다는 것을 알고 있습니다 . #if LOCAL
테스트 중에도 빠지기를 원합니다 .
많은 상황에서 실제로 조건부 컴파일 이 필요하지 않습니다 . 켜고 끌 수있는 조건부 동작 만 있으면 됩니다. 이를 위해 환경 변수를 사용할 수 있습니다. 이것은 실제로 다시 컴파일 할 필요가 없다는 큰 이점이 있습니다.
체계 편집기에서 환경 변수를 설정하고 쉽게 켜거나 끌 수 있습니다.
NSProcessInfo를 사용하여 환경 변수를 검색 할 수 있습니다.
let dic = NSProcessInfo.processInfo().environment
if dic["TRIPLE"] != nil {
// ... do secret stuff here ...
}
실제 예는 다음과 같습니다. 내 앱은 시뮬레이터에없는 음악 라이브러리를 사용하기 때문에 기기에서만 실행됩니다. 그렇다면 내가 소유하지 않은 장치의 시뮬레이터에서 스크린 샷을 찍는 방법은 무엇입니까? 스크린 샷이 없으면 AppStore에 제출할 수 없습니다.
가짜 데이터 와 다른 처리 방법이 필요 합니다 . 두 가지 환경 변수가 있습니다. 하나는 켜면 앱이 기기에서 실행되는 동안 실제 데이터에서 가짜 데이터를 생성하도록 지시합니다. 다른 하나는 스위치를 켤 때 시뮬레이터에서 실행되는 동안 누락 된 음악 라이브러리가 아닌 가짜 데이터를 사용합니다. Scheme 편집기의 환경 변수 체크 박스 덕분에 각 특수 모드를 쉽게 켜고 끌 수 있습니다. 그리고 아카이빙에는 환경 변수가 없기 때문에 실수로 App Store 빌드에서 사용할 수 없다는 것이 보너스입니다.
의 주요 변화 ifdef
교체의 엑스 코드 (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 값만 새 설정에 전달하면됩니다. 모든 조건부 컴파일 값을 이동할 시간입니다!
Xcode 8의 Swift Build Settings 기능에 대한 자세한 내용은 아래 링크를 참조하십시오 .
Swift 4.1부터는 디버그 또는 릴리스 구성으로 코드를 빌드했는지 여부 만 확인하면 내장 기능을 사용할 수 있습니다.
_isDebugAssertConfiguration()
(최적화가로 설정된 경우 true -Onone
)_isReleaseAssertConfiguration()
(최적화가로 설정된 경우 true -O
)_isFastAssertConfiguration()
(최적화가로 설정된 경우 true -Ounchecked
)예 :
func obtain() -> AbstractThing {
if _isDebugAssertConfiguration() {
return DecoratedThingWithDebugInformation(Thing())
} else {
return Thing()
}
}
전 처리기 매크로와 비교할 때
-D DEBUG
사용하기 위해 커스텀 플래그를 정의 할 필요가 없습니다.document 문서화되지 않음-모든 업데이트에서 함수를 제거 할 수 있음을 의미합니다 (그러나 옵티마이 저가이를 상수로 변환하므로 AppStore 안전해야 함).
@testable
, 미래의 스위프트에서는 운명이 불확실했습니다.if if / else를 사용하면 항상 "실행되지 않습니다"경고가 발생합니다.
if _isDebugAssertConfiguration()
평가되며 디버그 모드입니다. if false
if true
스위프트 전처리 기가 없습니다. (무엇이든 임의의 코드 대체는 유형 및 메모리 안전성을 손상시킵니다.)
Swift에는 빌드 타임 구성 옵션이 포함되어 있으므로 특정 플랫폼 또는 빌드 스타일에 대한 코드를 조건부로 포함하거나 -D
컴파일러 인수로 정의한 플래그에 응답 할 수 있습니다 . 그러나 C와 달리 조건부로 컴파일 된 코드 섹션은 구문 상 완전해야합니다. Cocoa 및 Objective-C와 함께 Swift 사용에 이에 대한 섹션이 있습니다.
예를 들면 다음과 같습니다.
#if os(iOS)
let color = UIColor.redColor()
#else
let color = NSColor.redColor()
#endif
INT_CONST
되는 모든 위치에 넣을 수 있습니다 float
. 스위프트는 이것을 허용하지 않을 것입니다. 또한 var floatVal = INT_CONST
필연적으로 할 수 있다면 컴파일러가 나중에 예상 Int
하지만 어딘가에 Float
(유형 floatVal
은으로 추론됩니다 Int
) 어딘가에 고장이 발생합니다 . 10 캐스팅 후 매크로를 제거하기 위해 더 깨끗합니다 ...
#if
코드베이스 전체에 조건을 적용 하지 않고 함수에 전달할 수있는 부울을 초래하는 또 다른 더 간단한 솔루션은 DEBUG
프로젝트 빌드 대상 중 하나로 정의 Active Compilation Conditions
하고 다음을 포함하는 것입니다 (전역 상수로 정의).
#if DEBUG
let isDebug = true
#else
let isDebug = false
#endif
이 개념은 kennyTM의 답변을 기반으로합니다.
kennyTM와 비교할 때 주요 이점은 개인 또는 문서화되지 않은 방법에 의존하지 않는다는 것입니다.
에서 스위프트 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
사용하기 위해 커스텀 플래그를 정의 할 필요가 없습니다.✓ 문서화 됨 : 함수가 정상적인 API 릴리스 / 비추천 패턴을 따릅니다.
✓ if / else를 사용해도 "실행되지 않습니다"경고가 발생 하지 않습니다 .
Moignans는 여기에서 대답 합니다. 도움이 될만한 정보의 또 다른 평화가 있습니다.
#if DEBUG
let a = 2
#else
let a = 3
#endif
아래와 같이 매크로를 부정 할 수 있습니다.
#if !RELEASE
let a = 2
#else
let a = 3
#endif
Xcode 버전 9.4.1, Swift 4.1로 작성된 Swift 프로젝트에서
#if DEBUG
#endif
전 처리기 매크로에서 DEBUG = 1이 Xcode에 의해 이미 설정되어 있기 때문에 기본적으로 작동합니다.
따라서 #if DEBUG "out of box"를 사용할 수 있습니다.
그런데 조건 컴파일 블록을 일반적으로 사용하는 방법은 Apple의 책 Swift Programming Language 4.1 (컴파일러 제어 명령문 섹션)에 작성되어 있으며 컴파일 플래그를 작성하는 방법과 Swift의 C 매크로에 대응하는 내용은 다음과 같습니다. 다른 Apple의 책 Cocoa 및 Objective C에서 Swift 사용하기 (전 처리기 지시문 섹션에 있음)
앞으로 애플은 더 자세한 내용과 책에 대한 색인을 작성할 것입니다.
빌드 설정 DEBUG=1
에서 설정 한 후이 GCC_PREPROCESSOR_DEFINITIONS
호출을 수행하는 기능을 선호합니다.
func executeInProduction(_ block: () -> Void)
{
#if !DEBUG
block()
#endif
}
그런 다음 디버그 빌드에서 생략하려는 블록을이 함수에 넣습니다.
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
컴파일러가 내 코드의 구문을 확인하므로 구문이 정확하고 빌드되어 있는지 확인합니다.
! [Xcode 8 이상에서 빌드 설정으로 이동-> 사용자 정의 플래그 검색] 1
코드에서
#if Live
print("Live")
#else
print("debug")
#endif
func inDebugBuilds(_ code: () -> Void) {
assert({ code(); return true }())
}
@inlinable
앞에 추가하면 func
Swift에서 가장 우아하고 관용적 인 방법입니다. 릴리스 빌드에서는 code()
블록이 완전히 최적화되고 제거됩니다. Apple의 자체 NIO 프레임 워크에서도 비슷한 기능이 사용됩니다.
이것은 디버그에 대해서만 실행되는 assert에 의존하는 Jon Willis의 답변을 기반으로합니다 .
func Log(_ str: String) {
assert(DebugLog(str))
}
func DebugLog(_ str: String) -> Bool {
print(str)
return true
}
내 유스 케이스는 인쇄 진술을 기록하는 것입니다. 다음은 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가 함수 호출을 완전히 제거하는 것처럼 보입니다.