W Objective-C możemy wiedzieć, czy aplikacja jest budowana na urządzenie lub symulator przy użyciu makr:
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
Są to makra czasu kompilacji i niedostępne w czasie wykonywania.
Jak mogę to samo osiągnąć w Swift?
Odpowiedzi:
Aktualizacja 30/01/19
Chociaż ta odpowiedź może zadziałać, zalecanym rozwiązaniem dla kontroli statycznej (wyjaśnione przez kilku inżynierów Apple) jest zdefiniowanie niestandardowej flagi kompilatora ukierunkowanej na symulatory iOS. Aby uzyskać szczegółowe instrukcje, jak to zrobić, zobacz odpowiedź @ mbelsky'ego .
Oryginalna odpowiedź
Jeśli potrzebujesz sprawdzenia statycznego (np. Nie środowiska wykonawczego, jeśli / else), nie możesz bezpośrednio wykryć symulatora, ale możesz wykryć iOS na architekturze pulpitu, jak poniżej
Po wersji Swift 4.1
Aby uzyskać więcej wyjaśnień, możesz sprawdzić propozycję Swift SE-0190
Oczywiście jest to fałsz na urządzeniu, ale zwraca wartość true dla symulatora iOS, jak określono w dokumentacji :
Jeśli opracowujesz symulator inny niż iOS, możesz po prostu zmienić
os
parametr: npWykryj symulator watchOS
Wykryj symulator tvOS
Lub nawet wykryj dowolny symulator
Jeśli zamiast tego masz rację sprawdzania czasu wykonywania, możesz sprawdzić
TARGET_OS_SIMULATOR
zmienną (lubTARGET_IPHONE_SIMULATOR
w iOS 8 i niższych), co jest prawdą w symulatorze.Zauważ, że jest to inne i nieco bardziej ograniczone niż użycie flagi preprocesora. Na przykład nie będziesz mógł używać go w miejscu, w którym a
if/else
jest składniowo niepoprawny (np. Poza zakresem funkcji).Powiedz na przykład, że chcesz mieć różne importy na urządzeniu i na symulatorze. Jest to niemożliwe przy kontroli dynamicznej, podczas gdy jest trywialne przy kontroli statycznej.
Ponadto, ponieważ flaga jest zastąpiona przez a
0
lub a1
przez szybki preprocesor, jeśli używasz go bezpośrednio wif/else
wyrażeniu, kompilator wyświetli ostrzeżenie o nieosiągalnym kodzie.Aby obejść to ostrzeżenie, zobacz jedną z pozostałych odpowiedzi.
źródło
arch(i386) && os(iOS)
.#if targetEnvironment(simulator)
:) ( github.com/apple/swift-evolution/blob/master/propozycje/... )NIEAKTUALIZOWANE DLA SWIFT 4.1. Użyj
#if targetEnvironment(simulator)
zamiast tego. ŹródłoAby wykryć symulator w Swift, możesz użyć konfiguracji kompilacji:
Teraz możesz użyć tej instrukcji do wykrycia symulatora:
Możesz także rozszerzyć klasę UIDevice:
źródło
xcconfig
plikach, używającOTHER_SWIFT_FLAGS = TARGET_OS_EMBEDDED
iOTHER_SWIFT_FLAGS[sdk=embeddedsimulator*] = TARGET_OS_SIMULATOR
by zastąpić Symulator.Zaktualizowano informacje na dzień 20 lutego 2018 r
Wygląda na to, że @ russbishop ma autorytatywną odpowiedź, która czyni tę odpowiedź „niepoprawną” - mimo że wydawała się działać przez długi czas.
Wykryj, czy aplikacja Swift tworzy aplikację na urządzenie lub symulator
Poprzednia odpowiedź
Na podstawie odpowiedzi @ WZW i komentarzy @ Panga stworzyłem prostą strukturę narzędzia. To rozwiązanie pozwala uniknąć ostrzeżeń generowanych przez odpowiedź @ WZW.
Przykładowe użycie:
źródło
public let IS_SIMULATOR = (TARGET_OS_SIMULATOR != 0)
... to samo, uproszczone. +1 dziękiTARGET_OS_SIMULATOR != 0
jest już w odpowiedzi . To rozwiązanie podane przez Daniela. Nie ma potrzeby dodawania go ponownie w wolnej zmiennej, już tam jest. Jeśli uważasz, że posiadanie go w strukturze jest złe, a posiadanie go w wolnej zmiennej jest lepsze, opublikuj komentarz na ten temat lub stwórz własną odpowiedź. Dzięki.Z Xcode 9.3
iOS 9+:
Swift 3:
Przed iOS 9:
Cel C:
źródło
will never be executed
ostrzeżeniaSzybki 4
Możesz teraz użyć
targetEnvironment(simulator)
jako argumentu.Zaktualizowano dla Xcode 9.3
źródło
Pozwól mi wyjaśnić kilka rzeczy tutaj:
TARGET_OS_SIMULATOR
w wielu przypadkach nie jest ustawiony w kodzie Swift; możesz przypadkowo go zaimportować z powodu mostkowego nagłówka, ale jest on łamliwy i nie jest obsługiwany. Nie jest to nawet możliwe w ramach. To dlatego niektórzy ludzie są zdezorientowani, czy to działa w Swift.Aby wykonać kontrole dynamiczne:
Sprawdzanie
ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] != nil
jest w porządku.Można również uzyskać symulację modelu bazowego, sprawdzając,
SIMULATOR_MODEL_IDENTIFIER
które zwracają łańcuchy takie jakiPhone10,3
.Aby wykonać kontrolę statyczną:
Xcode 9.2 i wcześniejsze: zdefiniuj własną flagę kompilacji Swift (jak pokazano w innych odpowiedziach).
Xcode 9.3+ korzysta z nowego celu Warunek środowiskowy:
źródło
targetEnvironment
wylądował w Xcode 9.3. Potrzebujesz nowszej wersji Xcode.Co działa dla mnie, odkąd Swift 1.0 sprawdza architekturę inną niż arm:
źródło
Środowisko wykonawcze, ale prostsze niż większość innych rozwiązań tutaj:
Alternatywnie możesz po prostu wywołać funkcję pomocniczą Objective-C, która zwraca wartość logiczną, która używa makra preprocesora (szczególnie jeśli już miksujesz w swoim projekcie).
Edycja: Nie najlepsze rozwiązanie, szczególnie od Xcode 9.3. Zobacz odpowiedź HotJard
źródło
== 0
zamiast!= 0
. Użyciem tak jak powyżej, nawet w przypadkuelse
bloku po, nie daje ostrzeżenia w Swift 4 Xcode wersja 9.2 (9C40b)W nowoczesnych systemach:
To proste.
źródło
TARGET_IPHONE_SIMULATOR
jest przestarzałe w iOS 9.TARGET_OS_SIMULATOR
jest zamiennikiem.TARGET_OS_EMBEDDED
Jest również dostępny.From TargetConditionals.h :
źródło
Mam nadzieję, że to rozszerzenie się przyda.
Stosowanie:
źródło
W Xcode 7.2 (i wcześniejszych, ale wcześniej nie testowałem), możesz ustawić flagę kompilacji specyficzną dla platformy „-D TARGET_IPHONE_SIMULATOR” dla „Any iOS Simulator”.
Sprawdź ustawienia kompilacji projektu w „Kompilatorze Swift - Flagi klienta”, a następnie ustaw flagę w „Innych flagach Swift”. Możesz ustawić flagę specyficzną dla platformy, klikając ikonę „plus” po najechaniu kursorem na konfigurację kompilacji.
Jest kilka zalet robienia tego w ten sposób: 1) Możesz użyć tego samego testu warunkowego („#if TARGET_IPHONE_SIMULATOR”) w kodzie Swift i Objective-C. 2) Możesz skompilować zmienne, które dotyczą tylko każdej kompilacji.
Zrzut ekranu ustawień kompilacji Xcode
źródło
Wszystko opisane tutaj 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
źródło
Użyłem tego kodu poniżej w Swift 3
źródło
Swift 4:
Obecnie wolę używać klasy ProcessInfo, aby wiedzieć, czy urządzenie jest symulatorem i jakiego rodzaju urządzenia jest używane:
Ale, jak wiesz,
simModelCode
nie jest wygodnym kodem do natychmiastowego zrozumienia, który rodzaj symulatora został uruchomiony, więc jeśli potrzebujesz, możesz spróbować zobaczyć inną odpowiedź SO, aby określić aktualny model iPhone / urządzenia i mieć bardziej ludzki charakter czytelny ciąg.źródło
Oto przykład Xcode 11 Swift oparty na świetnej odpowiedzi HotJarda powyżej , to także dodaje
isDevice
Bool i używaSIMULATOR_UDID
zamiast nazwy. W każdym wierszu wykonywane są zmienne przypisania, dzięki czemu można łatwiej sprawdzić je w debuggerze, jeśli zdecydujesz.Jest też wpis słownikowy,
DTPlatformName
który powinien zawieraćsimulator
.źródło
Użyj tego kodu poniżej:
Działa dla
Swift 4
iXcode 9.4.1
źródło
Xcode 11, Swift 5
źródło
Oprócz innych odpowiedzi.
W Objective-c, upewnij się, że podałeś TargetConditionals .
#include <TargetConditionals.h>
przed użyciem
TARGET_OS_SIMULATOR
.źródło