Aby obsługiwać starsze wydania macOS, kompiluj aplikację za pomocą SDK zawierającego deklaracje nowszych interfejsów API, ustaw obsługiwaną minimalną wersję systemu i osłaniaj nowsze wywołania sprawdzaniem dostępności oraz działającymi rozwiązaniami zastępczymi. Ten przewodnik pozwala korzystać z małego natywnego okna notatek w macOS 12, jednocześnie wprowadzając widok z macOS 14.
Które ustawienia zgodności muszą być ze sobą zgodne?
Dla programisty aplikacji na Maca konkretne zadanie polega na utworzeniu jednej aplikacji, która uruchamia się w najstarszym obsługiwanym wydaniu systemu i korzysta z nowszych funkcji, gdy są dostępne. Zacznij od rozdzielenia trzech elementów: kompilator rozumie język źródłowy, SDK udostępnia deklaracje interfejsów API, a docelowa wersja wdrożenia wskazuje najstarsze środowisko wykonawcze, które ma być obsługiwane. Dokumentacja ustawień kompilacji Apple definiuje SDKROOT jako SDK, którego nagłówki i biblioteki biorą udział w kompilacji. Dokumentacja ustawień kompilacji
Nowsze SDK może współpracować ze starszą docelową wersją wdrożenia. Clang wprost dokumentuje możliwość kompilowania z użyciem najnowszego SDK przy jednoczesnym wybraniu wcześniejszej minimalnej wersji macOS za pomocą -mmacos-version-min=. Takie połączenie nadal wymaga sprawdzania dostępności wokół interfejsów API wprowadzonych po minimalnej wersji. Rozszerzenia języka Clang
Wybierz minimalną wersję obsługiwaną przez używaną wersję Xcode. Tabela zgodności Apple rozróżnia wersję macOS wymaganą do uruchomienia Xcode od docelowych wersji wdrożenia, dla których można kompilować. Jeśli żądana minimalna wersja wykracza poza zakres obsługiwany przez dany łańcuch narzędzi, wybierz odpowiedni obsługiwany łańcuch narzędzi albo zmień minimalną wersję aplikacji, zanim zaimplementujesz rozwiązania zastępcze. SDK i wymagania systemowe
W tym przykładowym scenariuszu wymagane jest macOS 12 lub nowszy, SDK zawierające interfejsy API z macOS 14 oraz okno notatek z dwoma stanami: pustą kolekcją i jedną przykładową notatką. Nowsza prezentacja pustego stanu jest opcjonalna; wyświetlanie notatki jest dostępne już w bazowej wersji systemu.
Ustaw minimalną wersję w obu konfiguracjach kompilacji
W ustawieniach Build Settings celu aplikacji ustaw MACOSX_DEPLOYMENT_TARGET na 12.0 zarówno dla Debug, jak i Release. Jeśli zarządzasz ustawieniami w plikach konfiguracyjnych, poniższy fragment jest kompletną konfiguracją, a nie programem:
MACOSX_DEPLOYMENT_TARGET = 12.0
Na karcie Info projektu przypisz plik konfiguracyjny do odpowiednich konfiguracji. Następnie sprawdź końcową wartość celu: Apple dokumentuje, że ustawienia celu mogą zastępować wartości podane w przypisanym pliku konfiguracyjnym. Samo dodanie pliku do projektu nie oznacza, że jego ustawienia zaczną obowiązywać. Dodawanie pliku konfiguracji kompilacji do projektu
Jak dodać nowszy interfejs API bez podnoszenia minimalnej wersji aplikacji?
Swiftowe if #available sprawdza dostępność w czasie działania i informuje kompilator, których interfejsów API można używać w danej gałęzi. Umieść rozwiązanie zastępcze w tej samej strukturze warunkowej, aby starszy system miał kompletną implementację. Wymagany symbol * obejmuje platformy, których nie wymieniono wprost; nie sprawia on, że wskazany interfejs API macOS staje się dostępny we wcześniejszych wydaniach. Sterowanie przepływem — sprawdzanie dostępności interfejsów API
Element ContentUnavailableView firmy Apple jest dostępny od macOS 14 i obsługuje prezentacje pustej zawartości. Tutaj mały VStack zapewnia odpowiednią prezentację w macOS 12 i 13. Obie gałęzie wskazują tę samą kolejną czynność. ContentUnavailableView
Kompletna przykładowa aplikacja SwiftUI
Utwórz projekt aplikacji macOS o nazwie CompatibilityNotes, wybierz Swift i SwiftUI oraz ustaw docelową wersję wdrożenia na 12.0. Użyj SDK zawierającego interfejsy API z macOS 14. Zastąp wygenerowane deklaracje aplikacji i widoku zawartości poniższym pojedynczym plikiem, upewniając się, że cel zawiera tylko jedną deklarację @main. Nie są wymagane zasoby, pakiety ani pliki wejściowe.
import SwiftUI
@main
struct CompatibilityNotesApp: App {
var body: some Scene {
WindowGroup {
NotesView()
}
}
}
struct NotesView: View {
@State private var notes: [String] = []
var body: some View {
VStack(spacing: 16) {
if notes.isEmpty {
emptyState
} else {
List(notes, id: \.self) { note in
Text(note)
}
}
Button(notes.isEmpty ? "Add sample note" : "Reset sample") {
if notes.isEmpty {
notes = ["Sample note: arrange the blue shapes."]
} else {
notes = []
}
}
}
.padding()
.frame(minWidth: 360, minHeight: 240)
}
@ViewBuilder
private var emptyState: some View {
if #available(macOS 14.0, *) {
ModernEmptyState()
} else {
VStack(spacing: 8) {
Text("No notes")
.font(.headline)
Text("Add a sample note to begin.")
}
}
}
}
@available(macOS 14.0, *)
private struct ModernEmptyState: View {
var body: some View {
ContentUnavailableView {
Label("No notes", systemImage: "note.text")
} description: {
Text("Add a sample note to begin.")
}
}
}
Zamierzone działanie jest proste: w macOS 12 i 13 wyświetlany jest tekstowy widok zastępczy, a w macOS 14 i nowszych — ContentUnavailableView. Wybranie Add sample note wyświetla przykładową notatkę. Wybranie Reset sample przywraca pusty stan. Ta demonstracja przechowuje dane w pamięci i nie zapisuje notatek między uruchomieniami.
Adnotacja @available ogranicza użycie pomocniczego elementu do macOS 14 i nowszych. Warunek #available w miejscu wywołania spełnia to ograniczenie. Adnotacja opisuje dostępność deklaracji; nie zapewnia starszej implementacji. Atrybuty — available
Ten przykład sprawdzono na podstawie pobranej dokumentacji, ale go nie skompilowano ani nie uruchomiono: dostępne środowisko wykonawcze działało pod Linuksem i nie miało zainstalowanego ani Swifta, ani Clanga. Nadal konieczne są testy kompilacji i działania w macOS.
Jak sprawdzanie dostępności pomaga podczas linkowania?
Gałąź warunkowa wykonywana w czasie działania jest przydatna tylko wtedy, gdy da się załadować plik wykonywalny. Clang dokumentuje, że deklaracje z adnotacją dostępności, wprowadzone po docelowej wersji wdrożenia, można zwykle linkować słabo. Słabe odwołanie pozwala, by deklaracji brakowało w czasie działania; aplikacja nadal musi unikać jej użycia, gdy jest niedostępna. Dlatego oprócz samej gałęzi znaczenie mają docelowa wersja wdrożenia i deklaracje widoczne podczas kompilacji. Atrybuty w Clang — dostępność
W tym przykładzie pozostaw SwiftUI połączone w zwykły sposób: ten framework jest już obecny w bazowym macOS 12. Granicę zgodności wyznacza nowszy widok. Jeśli całkiem nowego frameworka brakuje w bazowej wersji systemu, oceń samą zależność od frameworka; osłonięcie jednego wywołania nie rozwiązuje wszystkich wymagań dotyczących ładowania. Przewodnik Apple dotyczący słabego linkowania wyjaśnia różnicę między dopuszczeniem braku symbolu a faktycznym użyciem tego symbolu. Frameworki i słabe linkowanie
Używaj składni sprawdzania dostępności właściwej dla języka źródłowego:
| Język źródłowy | Warunek dostępności w czasie działania |
|---|---|
| Swift | if #available(macOS 14.0, *) |
| Objective-C lub Objective-C++ | if (@available(macOS 14.0, *)) |
| C lub C++ z obsługą platform Apple w Clang | if (__builtin_available(macOS 14.0, *)) |
Clang dokumentuje zapis dla Objective-C oraz wbudowaną funkcję dla C/C++, a także ostrzeżenie -Wunguarded-availability. Włącz diagnostykę dostępności dla kodu w rodzinie C i sprawdź ostrzeżenia, zanim uznasz, że starsza docelowa wersja wdrożenia jest obsługiwana. Rozszerzenia języka Clang
Co zrobić, jeśli SDK używane do kompilacji nie zawiera interfejsu API?
Sprawdzenie w czasie działania nie dostarczy deklaracji, której brakuje w SDK. Jeśli kompilator nie rozpoznaje ContentUnavailableView, użyj SDK, które go zawiera. Jeśli projekt musi się też kompilować ze starszymi SDK, zastosuj przemyślany układ warunkowy kodu źródłowego, który wyklucza nieobsługiwane odwołania z tych kompilacji.
Swiftowe #if compiler(...) sprawdza wersję kompilatora, a #if canImport(...) sprawdza, czy można zaimportować moduł. Żaden z tych warunków nie określa, czy dany element istniejącego modułu jest dostępny na uruchomionym Macu. Używaj tych warunków kompilacji zgodnie z ich udokumentowanym przeznaczeniem, a tam, gdzie to potrzebne, stosuj sprawdzanie dostępności w czasie działania. Instrukcje — blok kompilacji warunkowej
Kiedy stabilność ABI Swifta i ograniczenia bibliotek C++ zmieniają odpowiedź?
Stabilność ABI Swifta nie oznacza, że każda nowsza funkcja biblioteki standardowej lub środowiska wykonawczego jest dostępna w starszych systemach. Wyjaśnienie dotyczące Swifta rozróżnia tryb języka od obsługi środowiska wykonawczego: zmiana trybu języka jest wyborem na etapie kompilacji, natomiast funkcje wymagające nowej funkcjonalności środowiska wykonawczego mogą mieć wymagania dotyczące systemu operacyjnego. Sprawdź dostępność konkretnej używanej funkcji. Ewolucja Swifta na platformach Apple po stabilizacji ABI
W C++ występuje podobny podział między obsługą w kompilatorze a obsługą w bibliotece. Apple dostarcza Apple Clang przez Xcode, a środowisko wykonawcze libc++ za pośrednictwem SDK i systemów operacyjnych. Tabela funkcji wskazuje wymagania, które mogą zależeć od współdzielonej biblioteki udostępnianej przez system operacyjny. Wybranie -std=c++17 lub -std=c++20 nie instaluje tej funkcjonalności środowiska wykonawczego na Macu użytkownika. Obsługa języka C++
Dobrym przykładem jest konwersja liczb: Apple podaje macOS 10.15 jako minimalną wersję dla całkowitoliczbowych wersji std::to_chars i std::from_chars, ale macOS 13.3 dla ich wersji zmiennoprzecinkowych. Aplikacja działająca w macOS 12 potrzebuje więc zgodnej implementacji konwersji, jeśli w przeciwnym razie wymagałaby tych wersji zmiennoprzecinkowych. Sprawdź dokładny przeciążony wariant, a nie tylko nagłówek lub wersję standardu C++. Obsługa języka C++
Nie zakładaj, że objęcie każdego wywołania biblioteki C++ warunkiem __builtin_available wystarczy. Atrybuty dostępności Clanga obejmują wariant strict, który odrzuca użycie przy kompilowaniu na starszą platformę, a libc++ używa oznaczeń dostępności, by podczas kompilacji diagnozować brak obsługi w środowisku wykonawczym. Jeśli używane nagłówki odrzucają daną operację, zastosuj implementację zgodną z bazową wersją systemu albo podnieś minimalną wersję. Atrybuty w Clang — dostępność, Dokumentacja dostawcy — oznaczenia dostępności
Zachowaj konfigurację ABI biblioteki we wszystkich zależnościach. LLVM opisuje zarówno konkretne gwarancje ABI, jak i ich ograniczenia, w tym fakt, że kod skompilowany z nowszymi nagłówkami libc++ może nie działać ze starszą biblioteką. Flagi konfiguracji zmieniające ABI są ustawieniami dostawcy. Zmiana ich w kodzie aplikacji nie zastąpi zgodnego środowiska wykonawczego. Gwarancje ABI libc++
Jak diagnozować i weryfikować gotową kompilację?
Wybierz kolejny krok na podstawie etapu, na którym wystąpił błąd. Ta pomoc decyzyjna uwzględnia opisane wcześniej granice kompilatora, dostępności i środowiska wykonawczego; to sekwencja diagnostyczna, a nie twierdzenie, że próbka przeszła testy.
| Objaw | Najpierw sprawdź | Praktyczny następny krok |
|---|---|---|
| Nieznana nazwa nowego interfejsu API | Deklaracje SDK | Wybierz SDK zawierające ten interfejs API. |
| Interfejs API jest nowszy niż docelowa wersja wdrożenia | Użycie bez osłony | Dodaj obsługiwaną granicę dostępności i rozwiązanie zastępcze. |
| Operacja biblioteki C++ nadal jest odrzucana | Dokładny wariant przeciążony i wymagania biblioteki | Użyj zgodnej implementacji albo zmień minimalną wersję. |
| Aplikacja ulega awarii, zanim pojawi się jej okno | Wymagania ładowania i zależności | Sprawdź zgłoszoną brakującą bibliotekę lub symbol. |
| Nie działa tylko nowsza funkcja | Operacje wykonywane poza osłoniętą gałęzią | Sprawdź tworzenie, inicjalizację i wywołania pomocnicze. |
| Kompilacja działa tylko na jednej rodzinie procesorów | Architektury pliku wykonywalnego i zależności | Zbuduj i przetestuj wymagane warianty architektury. |
Obsługa architektur to dodatkowe wymaganie. Wytyczne Apple dotyczące plików uniwersalnych omawiają arm64 i x86_64, w tym skompilowane biblioteki i frameworki. Sprawdź zależności, a także plik wykonywalny aplikacji; pomyślna kompilacja na używanym Macu potwierdza zgodność tylko tej kompilacji. Tworzenie uniwersalnego pliku binarnego macOS
W przypadku tej próbki skompiluj konfigurację wydania i przetestuj wynikową aplikację w macOS 12, macOS 13 oraz macOS 14 lub nowszym, na obsługiwanym sprzęcie. W każdym systemie uruchom aplikację z pustą kolekcją, dodaj przykładową notatkę i zresetuj ją. Starsze wydania powinny zachować pełną interakcję dzięki rozwiązaniu zastępczemu. Przetestuj każdą architekturę, którą zamierzasz obsługiwać.
W miarę rozwoju aplikacji utrzymuj wyraźną granicę obsługi: obsługiwaną docelową wersję wdrożenia, deklaracje z odpowiedniego SDK, osłoniętą nowszą funkcjonalność i użyteczną implementację bazową. Każdy kolejny interfejs API lub zależność powinny spełniać te same warunki, zanim staną się częścią kompilacji.
Źródła
- SDK i wymagania systemowe — Apple.
- Dokumentacja ustawień kompilacji — Apple.
- Dodawanie pliku konfiguracji kompilacji do projektu — Apple.
- ContentUnavailableView — Apple.
- Sterowanie przepływem — The Swift Programming Language, projekt Swift.
- Atrybuty — The Swift Programming Language, projekt Swift.
- Instrukcje — The Swift Programming Language, projekt Swift.
- Rozszerzenia języka Clang — projekt LLVM.
- Atrybuty w Clang — projekt LLVM.
- Frameworki i słabe linkowanie — Apple, dokumentacja archiwalna.
- Ewolucja Swifta na platformach Apple po stabilizacji ABI — Swift.org.
- Obsługa języka C++ — Apple.
- Dokumentacja dostawcy — projekt LLVM.
- Gwarancje ABI libc++ — projekt LLVM.
- Tworzenie uniwersalnego pliku binarnego macOS — Apple.