Objective-C에서는 매크로를 사용하여 장치 또는 시뮬레이터 용으로 앱을 빌드 중인지 알 수 있습니다.
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
컴파일 타임 매크로이며 런타임에는 사용할 수 없습니다.
Swift에서 어떻게 동일한 결과를 얻을 수 있습니까?
Objective-C에서는 매크로를 사용하여 장치 또는 시뮬레이터 용으로 앱을 빌드 중인지 알 수 있습니다.
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
컴파일 타임 매크로이며 런타임에는 사용할 수 없습니다.
Swift에서 어떻게 동일한 결과를 얻을 수 있습니까?
답변:
이 답변은 효과가 있지만 정적 검사에 권장되는 솔루션은 여러 Apple 엔지니어가 명시한 것처럼 iOS 시뮬레이터를 대상으로하는 사용자 지정 컴파일러 플래그를 정의하는 것입니다. 자세한 방법은 @ mbelsky 's answer을 참조하십시오 .
정적 검사가 필요한 경우 (예 : 런타임 if / else가 아닌 경우) 시뮬레이터를 직접 감지 할 수 없지만 다음과 같은 데스크탑 아키텍처에서 iOS를 감지 할 수 있습니다.
#if (arch(i386) || arch(x86_64)) && os(iOS)
...
#endif
스위프트 4.1 버전 이후
모든 유형의 시뮬레이터에 대해 하나의 조건에서 모두 직접 사용하는 최신 사용은 하나의 조건 만 적용하면됩니다.
#if targetEnvironment(simulator)
// your simulator code
#else
// your real device code
#endif
자세한 설명을 보려면 Swift 제안서 SE-0190을 확인하십시오.
이전 버전의 경우 -
분명히 이것은 장치에서 거짓이지만 설명서에 지정된대로 iOS 시뮬레이터의 경우 true를 반환합니다 .
arch (i386) 빌드 구성은 코드가 32 비트 iOS 시뮬레이터 용으로 컴파일 될 때 true를 리턴합니다.
iOS 이외의 시뮬레이터를 개발하는 경우 os
매개 변수를 간단히 변경할 수 있습니다 . 예 :
watchOS 시뮬레이터 감지
#if (arch(i386) || arch(x86_64)) && os(watchOS)
...
#endif
tvOS 시뮬레이터 감지
#if (arch(i386) || arch(x86_64)) && os(tvOS)
...
#endif
또는 시뮬레이터를 감지 해도
#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(watchOS) || os(tvOS))
...
#endif
런타임 검사에 문제 가 없다면 시뮬레이터에서 TARGET_OS_SIMULATOR
변수 인 변수 (또는 TARGET_IPHONE_SIMULATOR
iOS 8 이하)를 검사 할 수 있습니다 .
이것은 전 처리기 플래그를 사용하는 것과는 다르고 약간 더 제한적입니다. 예를 들어, if/else
구문 상 유효하지 않은 위치 (예 : 함수 범위 외부) 에서는 사용할 수 없습니다 .
예를 들어, 장치와 시뮬레이터에서 다른 가져 오기를 원한다고 가정하십시오. 동적 검사에서는 불가능하지만 정적 검사에서는 쉽지 않습니다.
#if (arch(i386) || arch(x86_64)) && os(iOS)
import Foo
#else
import Bar
#endif
또한 플래그는 빠른 전처리기에 의해 a 0
또는 a 로 대체 1
되므로 if/else
식에서 직접 사용 하면 컴파일러는 도달 할 수없는 코드에 대한 경고를 발생시킵니다.
이 경고를 해결하려면 다른 답변 중 하나를 참조하십시오.
arch(i386) && os(iOS)
.
#if targetEnvironment(simulator)
:) ( github.com/apple/swift-evolution/blob/master/proposals/… )
SWIFT의 구식 4.1. #if targetEnvironment(simulator)
대신 사용하십시오 . 출처
Swift에서 시뮬레이터를 감지하려면 빌드 구성을 사용할 수 있습니다.
이제이 문장을 사용하여 시뮬레이터를 감지 할 수 있습니다.
#if IOS_SIMULATOR
print("It's an iOS Simulator")
#else
print("It's a device")
#endif
또한 UIDevice 클래스를 확장 할 수 있습니다.
extension UIDevice {
var isSimulator: Bool {
#if IOS_SIMULATOR
return true
#else
return false
#endif
}
}
// Example of usage: UIDevice.current.isSimulator
xcconfig
사용 하여 재정 의하여 파일 에서이를 설정할 수도 있습니다 . OTHER_SWIFT_FLAGS = TARGET_OS_EMBEDDED
OTHER_SWIFT_FLAGS[sdk=embeddedsimulator*] = TARGET_OS_SIMULATOR
2018 년 2 월 20 일 현재 정보 업데이트
@russbishop은 오랫동안 작동하는 것처럼 보이지만이 답변을 "잘못된"것으로 만드는 정식 답변을 가지고있는 것 같습니다.
Swift에서 장치 또는 시뮬레이터 용 앱이 빌드 중인지 감지
이전 답변
@WZW의 답변과 @Pang의 의견을 바탕으로 간단한 유틸리티 구조체를 만들었습니다. 이 솔루션은 @WZW의 답변으로 생성되는 경고를 피합니다.
import Foundation
struct Platform {
static var isSimulator: Bool {
return TARGET_OS_SIMULATOR != 0
}
}
사용법 예 :
if Platform.isSimulator {
print("Running on Simulator")
}
public let IS_SIMULATOR = (TARGET_OS_SIMULATOR != 0)
... ... 같은 일, 단순화되었습니다. +1 감사합니다
TARGET_OS_SIMULATOR != 0
가 이미 답변에 있습니다. Daniel이 제공 한 솔루션입니다. 자유 변수에 다시 추가 할 필요가 없습니다. 이미 있습니다. 구조체에 포함시키는 것이 좋지 않다고 생각하고 자유 변수에 넣는 것이 더 낫다면 이것에 대한 의견을 게시하거나 직접 답하십시오. 감사.
Xcode 9.3에서
#if targetEnvironment(simulator)
Swift는 유효한 단일 인수 시뮬레이터를 사용하여 새로운 플랫폼 조건 targetEnvironment를 지원합니다. '#if targetEnvironment (simulator)'형식의 조건부 컴파일을 사용하여 빌드 대상이 시뮬레이터 인 경우를 감지 할 수 있습니다. Swift 컴파일러는 기존 os () 및 arch () 플랫폼 조건을 통해 시뮬레이터 환경을 간접적으로 테스트하는 것으로 보이는 플랫폼 조건을 평가할 때 targetEnvironment (simulator) 사용을 감지, 경고 및 제안하려고 시도합니다. (SE-0190)
iOS 9 이상 :
extension UIDevice {
static var isSimulator: Bool {
return NSProcessInfo.processInfo().environment["SIMULATOR_DEVICE_NAME"] != nil
}
}
스위프트 3 :
extension UIDevice {
static var isSimulator: Bool {
return ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
}
}
iOS 9 이전 :
extension UIDevice {
static var isSimulator: Bool {
return UIDevice.currentDevice().model == "iPhone Simulator"
}
}
목표 -C :
@interface UIDevice (Additions)
- (BOOL)isSimulator;
@end
@implementation UIDevice (Additions)
- (BOOL)isSimulator {
if([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){9, 0, 0}]) {
return [NSProcessInfo processInfo].environment[@"SIMULATOR_DEVICE_NAME"] != nil;
} else {
return [[self model] isEqualToString:@"iPhone Simulator"];
}
}
@end
will never be executed
경고를 생성하지 않습니다
이제 targetEnvironment(simulator)
인수로 사용할 수 있습니다 .
#if targetEnvironment(simulator)
// Simulator
#else
// Device
#endif
Xcode 9.3 용으로 업데이트
여기에 몇 가지 사항을 설명하겠습니다.
TARGET_OS_SIMULATOR
많은 경우 스위프트 코드에서 설정되지 않습니다. 브리징 헤더로 인해 실수로 가져 오는 경우가 있지만 취하기 어렵고 지원되지 않습니다. 프레임 워크에서도 가능하지 않습니다. 이것이 일부 사람들이 이것이 스위프트에서 작동하는지 혼란 스럽습니다.동적 검사를 수행하려면
확인 ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
은 완벽합니다.
다음 SIMULATOR_MODEL_IDENTIFIER
과 같은 문자열을 반환하는지 확인하여 기본 모델을 시뮬레이션 할 수도 있습니다 iPhone10,3
.
정적 점검을 수행하려면 다음을 수행하십시오.
Xcode 9.2 및 이전 버전 : 다른 답변에 표시된 것처럼 자체 Swift 컴파일 플래그를 정의하십시오.
Xcode 9.3+는 새로운 targetEnvironment 조건을 사용합니다 :
#if targetEnvironment(simulator)
// for sim only
#else
// for device
#endif
targetEnvironment
는 Xcode 9.3에 착륙했습니다. 최신 버전의 Xcode가 필요합니다.
런타임이지만 다른 대부분의 솔루션보다 간단합니다.
if TARGET_OS_SIMULATOR != 0 {
// target is current running in the simulator
}
또는 전 처리기 매크로를 사용하는 부울을 리턴하는 Objective-C 헬퍼 함수를 호출 할 수 있습니다 (특히 프로젝트에서 이미 혼합중인 경우).
편집 : 특히 Xcode 9.3에서 가장 좋은 해결책은 아닙니다. 참조 HotJard의 답변을
== 0
대신 사용할 때 경고 만 표시 됩니다 != 0
. 심지어와, 상기 기록으로 사용 else
후 블록 스위프트 4 엑스 코드 버전 9.2 (9C40b)에서 경고 발생하지 않는다
TARGET_IPHONE_SIMULATOR
iOS 9에서는 더 이상 사용되지 않습니다 TARGET_OS_SIMULATOR
. 대체입니다. 또한 TARGET_OS_EMBEDDED
사용할 수 있습니다.
에서 TargetConditionals.h :
#if defined(__GNUC__) && ( defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__) ) . . . #define TARGET_OS_SIMULATOR 0 #define TARGET_OS_EMBEDDED 1 #define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */ #define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */
이 확장 기능이 도움이 되길 바랍니다.
extension UIDevice {
static var isSimulator: Bool = {
#if targetEnvironment(simulator)
return true
#else
return false
#endif
}()
}
용법:
if UIDevice.isSimulator {
print("running on simulator")
}
Xcode 7.2 (및 그 이전 버전에서는 테스트 한 적이 없음)에서 "모든 iOS 시뮬레이터"에 대해 플랫폼 별 빌드 플래그 "-D TARGET_IPHONE_SIMULATOR"를 설정할 수 있습니다.
"Swift Compiler-Customer Flags"의 프로젝트 빌드 설정을 확인한 다음 "Other Swift Flags"에서 플래그를 설정하십시오. 빌드 구성 위로 마우스를 가져 가면 '더하기'아이콘을 클릭하여 플랫폼 별 플래그를 설정할 수 있습니다.
이 방법으로 몇 가지 장점이 있습니다. 1) Swift 및 Objective-C 코드에서 동일한 조건부 테스트 ( "# if TARGET_IPHONE_SIMULATOR")를 사용할 수 있습니다. 2) 각 빌드에만 적용되는 변수를 컴파일 할 수 있습니다.
Darwin.TargetConditionals : https://github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/Base.subproj/SwiftRuntime/TargetConditionals.h에 설명되어 있습니다 .
TARGET_OS_SIMULATOR - Generated code will run under a simulator
현재 ProcessInfo 클래스 를 사용하여 장치가 시뮬레이터인지, 어떤 종류의 장치 를 사용하고 있는지 알고 싶습니다.
if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
print("yes is a simulator :\(simModelCode)")
}
그러나 아시다시피, simModelCode
어떤 종류의 시뮬레이터가 출시되었는지 즉시 이해하기에 편안한 코드는 아닙니다. 필요한 경우이 다른 답변 을보고 현재 iPhone / 장치 모델을 결정하고보다 인간적이어야합니다. 읽을 수있는 문자열.
위 의 HotJard의 멋진 답변을 기반으로 한 Xcode 11 Swift 예제 는 Bool을 추가하고 이름 대신 사용 합니다. 변수 할당은 각 줄에서 수행되므로 원하는 경우 디버거에서보다 쉽게 검사 할 수 있습니다.isDevice
SIMULATOR_UDID
import Foundation
// Extensions to UIDevice based on ProcessInfo.processInfo.environment keys
// to determine if the app is running on an actual device or the Simulator.
@objc extension UIDevice {
static var isSimulator: Bool {
let environment = ProcessInfo.processInfo.environment
let isSimulator = environment["SIMULATOR_UDID"] != nil
return isSimulator
}
static var isDevice: Bool {
let environment = ProcessInfo.processInfo.environment
let isDevice = environment["SIMULATOR_UDID"] == nil
return isDevice
}
}
또한 DTPlatformName
포함해야하는 사전 항목 이 있습니다 simulator
.