ios-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

iOS/iPadOS/tvOS Development

iOS/iPadOS/tvOS 开发

Comprehensive guide for building native Apple platform applications.
构建原生苹果平台应用的综合指南。

Platforms Covered

涵盖的平台

PlatformMinimum TargetCurrent
iOSiOS 15.0+iOS 17+
iPadOSiPadOS 15.0+iPadOS 17+
tvOStvOS 15.0+tvOS 17+
watchOSwatchOS 8.0+watchOS 10+

平台最低适配版本当前版本
iOSiOS 15.0+iOS 17+
iPadOSiPadOS 15.0+iPadOS 17+
tvOStvOS 15.0+tvOS 17+
watchOSwatchOS 8.0+watchOS 10+

SwiftUI (Preferred for New Projects)

SwiftUI(新项目首选)

Basic Structure

基础结构

swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    @State private var count = 0

    var body: some View {
        VStack(spacing: 20) {
            Text("Count: \(count)")
                .font(.largeTitle)

            Button("Increment") {
                count += 1
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}
swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    @State private var count = 0

    var body: some View {
        VStack(spacing: 20) {
            Text("Count: \(count)")
                .font(.largeTitle)

            Button("Increment") {
                count += 1
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

State Management

状态管理

swift
// Local state
@State private var text = ""

// Binding (child components)
@Binding var isPresented: Bool

// Observable object
@StateObject private var viewModel = MyViewModel()
@ObservedObject var viewModel: MyViewModel

// Environment
@Environment(\.dismiss) private var dismiss
@Environment(\.colorScheme) private var colorScheme
@EnvironmentObject var appState: AppState

// App Storage (UserDefaults)
@AppStorage("username") private var username = ""
swift
// Local state
@State private var text = ""

// Binding (child components)
@Binding var isPresented: Bool

// Observable object
@StateObject private var viewModel = MyViewModel()
@ObservedObject var viewModel: MyViewModel

// Environment
@Environment(\.dismiss) private var dismiss
@Environment(\.colorScheme) private var colorScheme
@EnvironmentObject var appState: AppState

// App Storage (UserDefaults)
@AppStorage("username") private var username = ""

Modern Concurrency

现代并发

swift
// Async/await
func fetchData() async throws -> [Item] {
    let url = URL(string: "https://api.example.com/items")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode([Item].self, from: data)
}

// In View
.task {
    do {
        items = try await fetchData()
    } catch {
        errorMessage = error.localizedDescription
    }
}

// Main actor for UI updates
@MainActor
class ViewModel: ObservableObject {
    @Published var items: [Item] = []

    func load() async {
        items = try? await fetchData()
    }
}
swift
// Async/await
func fetchData() async throws -> [Item] {
    let url = URL(string: "https://api.example.com/items")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode([Item].self, from: data)
}

// In View
.task {
    do {
        items = try await fetchData()
    } catch {
        errorMessage = error.localizedDescription
    }
}

// Main actor for UI updates
@MainActor
class ViewModel: ObservableObject {
    @Published var items: [Item] = []

    func load() async {
        items = try? await fetchData()
    }
}

Navigation (iOS 16+)

导航(iOS 16+)

swift
// NavigationStack with typed destinations
struct ContentView: View {
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            List(items) { item in
                NavigationLink(value: item) {
                    Text(item.name)
                }
            }
            .navigationDestination(for: Item.self) { item in
                DetailView(item: item)
            }
        }
    }
}
swift
// NavigationStack with typed destinations
struct ContentView: View {
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            List(items) { item in
                NavigationLink(value: item) {
                    Text(item.name)
                }
            }
            .navigationDestination(for: Item.self) { item in
                DetailView(item: item)
            }
        }
    }
}

Lists and Grids

列表与网格

swift
// Modern List
List {
    ForEach(items) { item in
        ItemRow(item: item)
    }
    .onDelete(perform: delete)
    .onMove(perform: move)
}
.listStyle(.insetGrouped)
.searchable(text: $searchText)
.refreshable {
    await refresh()
}

// LazyVGrid
LazyVGrid(columns: [
    GridItem(.adaptive(minimum: 150))
]) {
    ForEach(items) { item in
        ItemCard(item: item)
    }
}

swift
// Modern List
List {
    ForEach(items) { item in
        ItemRow(item: item)
    }
    .onDelete(perform: delete)
    .onMove(perform: move)
}
.listStyle(.insetGrouped)
.searchable(text: $searchText)
.refreshable {
    await refresh()
}

// LazyVGrid
LazyVGrid(columns: [
    GridItem(.adaptive(minimum: 150))
]) {
    ForEach(items) { item in
        ItemCard(item: item)
    }
}

UIKit (Legacy/Complex UI)

UIKit(遗留项目/复杂UI场景)

View Controller Lifecycle

视图控制器生命周期

swift
class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // About to appear
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // Fully visible
    }
}
swift
class MyViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // About to appear
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // Fully visible
    }
}

Auto Layout

自动布局

swift
// Programmatic constraints
NSLayoutConstraint.activate([
    label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
    label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
    label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16)
])

swift
// Programmatic constraints
NSLayoutConstraint.activate([
    label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
    label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
    label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16)
])

Data Persistence

数据持久化

Core Data

Core Data

swift
// Model
@objc(Item)
public class Item: NSManagedObject {
    @NSManaged public var id: UUID
    @NSManaged public var name: String
    @NSManaged public var createdAt: Date
}

// Fetch
@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Item.createdAt, ascending: false)],
    animation: .default
)
private var items: FetchedResults<Item>
swift
// Model
@objc(Item)
public class Item: NSManagedObject {
    @NSManaged public var id: UUID
    @NSManaged public var name: String
    @NSManaged public var createdAt: Date
}

// Fetch
@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Item.createdAt, ascending: false)],
    animation: .default
)
private var items: FetchedResults<Item>

SwiftData (iOS 17+)

SwiftData(iOS 17+)

swift
@Model
class Item {
    var id: UUID
    var name: String
    var createdAt: Date

    init(name: String) {
        self.id = UUID()
        self.name = name
        self.createdAt = Date()
    }
}

// In View
@Query(sort: \Item.createdAt, order: .reverse)
private var items: [Item]

@Environment(\.modelContext) private var modelContext

func addItem() {
    let item = Item(name: "New Item")
    modelContext.insert(item)
}
swift
@Model
class Item {
    var id: UUID
    var name: String
    var createdAt: Date

    init(name: String) {
        self.id = UUID()
        self.name = name
        self.createdAt = Date()
    }
}

// In View
@Query(sort: \Item.createdAt, order: .reverse)
private var items: [Item]

@Environment(\.modelContext) private var modelContext

func addItem() {
    let item = Item(name: "New Item")
    modelContext.insert(item)
}

Keychain

钥匙串

swift
// Store sensitive data
import Security

func saveToKeychain(key: String, data: Data) throws {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: key,
        kSecValueData as String: data
    ]
    SecItemDelete(query as CFDictionary)
    let status = SecItemAdd(query as CFDictionary, nil)
    guard status == errSecSuccess else {
        throw KeychainError.saveFailed
    }
}

swift
// Store sensitive data
import Security

func saveToKeychain(key: String, data: Data) throws {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: key,
        kSecValueData as String: data
    ]
    SecItemDelete(query as CFDictionary)
    let status = SecItemAdd(query as CFDictionary, nil)
    guard status == errSecSuccess else {
        throw KeychainError.saveFailed
    }
}

Networking

网络请求

URLSession

URLSession

swift
actor NetworkService {
    func fetch<T: Decodable>(_ type: T.Type, from url: URL) async throws -> T {
        let (data, response) = try await URLSession.shared.data(from: url)

        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            throw NetworkError.invalidResponse
        }

        return try JSONDecoder().decode(T.self, from: data)
    }
}

swift
actor NetworkService {
    func fetch<T: Decodable>(_ type: T.Type, from url: URL) async throws -> T {
        let (data, response) = try await URLSession.shared.data(from: url)

        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            throw NetworkError.invalidResponse
        }

        return try JSONDecoder().decode(T.self, from: data)
    }
}

Apple Human Interface Guidelines

Apple人机界面指南

iOS Design Principles

iOS设计原则

  • Clarity: Text is legible, icons precise, adornments subtle
  • Deference: Content is paramount, UI doesn't compete
  • Depth: Visual layers and realistic motion convey hierarchy
  • 清晰性:文本易读、图标精准、装饰简洁
  • 依从性:内容至上,UI不抢焦点
  • 层次感:视觉层级与真实动效传递结构关系

Key Metrics

关键指标

ElementSize
Touch target44x44 pt minimum
Navigation bar44 pt
Tab bar49 pt
Status bar47 pt (notch) / 20 pt (legacy)
元素尺寸规格
触控目标最小44x44 pt
导航栏44 pt
标签栏49 pt
状态栏47 pt(带刘海)/ 20 pt(传统机型)

Safe Areas

安全区域

swift
.safeAreaInset(edge: .bottom) {
    BottomBar()
}

// Ignore safe area
.ignoresSafeArea(.keyboard)
.ignoresSafeArea(.container, edges: .bottom)

swift
.safeAreaInset(edge: .bottom) {
    BottomBar()
}

// Ignore safe area
.ignoresSafeArea(.keyboard)
.ignoresSafeArea(.container, edges: .bottom)

Platform-Specific

平台专属特性

iPadOS Specifics

iPadOS专属功能

swift
// Split view
NavigationSplitView {
    Sidebar()
} content: {
    ContentList()
} detail: {
    DetailView()
}

// Keyboard shortcuts
.keyboardShortcut("n", modifiers: .command)

// Hover effects
.hoverEffect(.highlight)
swift
// Split view
NavigationSplitView {
    Sidebar()
} content: {
    ContentList()
} detail: {
    DetailView()
}

// Keyboard shortcuts
.keyboardShortcut("n", modifiers: .command)

// Hover effects
.hoverEffect(.highlight)

tvOS Specifics

tvOS专属功能

swift
// Focus management
@FocusState private var isFocused: Bool

Button("Action") { }
    .focused($isFocused)
    .focusable()

// Large text for 10-foot UI
.font(.system(size: 38))

swift
// Focus management
@FocusState private var isFocused: Bool

Button("Action") { }
    .focused($isFocused)
    .focusable()

// Large text for 10-foot UI
.font(.system(size: 38))

App Store Requirements

App Store上架要求

Required Assets

必需资源

  • App icon (1024x1024)
  • Screenshots for each device size
  • Privacy policy URL
  • App description (4000 char max)
  • App图标(1024x1024)
  • 各设备尺寸的截图
  • 隐私政策URL
  • App描述(最多4000字符)

Privacy

隐私权限

xml
<!-- Info.plist -->
<key>NSCameraUsageDescription</key>
<string>We need camera access to...</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need photo access to...</string>
xml
<!-- Info.plist -->
<key>NSCameraUsageDescription</key>
<string>We need camera access to...</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need photo access to...</string>

App Transport Security

App传输安全

xml
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
</dict>

xml
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
</dict>

Testing

测试

Unit Tests

单元测试

swift
import XCTest
@testable import MyApp

final class MyTests: XCTestCase {
    func testExample() async throws {
        let sut = MyViewModel()
        await sut.load()
        XCTAssertEqual(sut.items.count, 10)
    }
}
swift
import XCTest
@testable import MyApp

final class MyTests: XCTestCase {
    func testExample() async throws {
        let sut = MyViewModel()
        await sut.load()
        XCTAssertEqual(sut.items.count, 10)
    }
}

UI Tests

UI测试

swift
import XCTest

final class MyUITests: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        continueAfterFailure = false
        app.launch()
    }

    func testNavigation() {
        app.buttons["Start"].tap()
        XCTAssertTrue(app.staticTexts["Welcome"].exists)
    }
}

swift
import XCTest

final class MyUITests: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        continueAfterFailure = false
        app.launch()
    }

    func testNavigation() {
        app.buttons["Start"].tap()
        XCTAssertTrue(app.staticTexts["Welcome"].exists)
    }
}

Project Structure

项目结构

MyApp/
├── App/
│   └── MyApp.swift
├── Features/
│   ├── Home/
│   │   ├── HomeView.swift
│   │   └── HomeViewModel.swift
│   └── Settings/
│       └── SettingsView.swift
├── Core/
│   ├── Models/
│   ├── Services/
│   └── Extensions/
├── Resources/
│   ├── Assets.xcassets
│   └── Localizable.strings
└── Tests/

MyApp/
├── App/
│   └── MyApp.swift
├── Features/
│   ├── Home/
│   │   ├── HomeView.swift
│   │   └── HomeViewModel.swift
│   └── Settings/
│       └── SettingsView.swift
├── Core/
│   ├── Models/
│   ├── Services/
│   └── Extensions/
├── Resources/
│   ├── Assets.xcassets
│   └── Localizable.strings
└── Tests/

Best Practices

最佳实践

DO:

建议:

  • Use SwiftUI for new projects
  • Support Dynamic Type for accessibility
  • Handle all device orientations
  • Implement proper error handling
  • Use Swift's type system fully
  • 新项目使用SwiftUI
  • 支持动态字体以提升可访问性
  • 适配所有设备方向
  • 实现完善的错误处理
  • 充分利用Swift的类型系统

DON'T:

避免:

  • Force unwrap optionals without validation
  • Block main thread with network calls
  • Hardcode strings (use localization)
  • Ignore memory management (retain cycles)
  • Skip accessibility labels

  • 未验证就强制解包可选类型
  • 网络请求阻塞主线程
  • 硬编码字符串(使用本地化)
  • 忽略内存管理(循环引用)
  • 跳过可访问性标签

@Observable Macro (iOS 17+, Replacing ObservableObject)

@Observable宏(iOS 17+,替代ObservableObject)

swift
import Observation

// New pattern: @Observable macro (replaces ObservableObject + @Published)
@Observable
class UserViewModel {
    var user: User?
    var isLoading = false
    var errorMessage: String?

    func load() async {
        isLoading = true
        defer { isLoading = false }
        do {
            user = try await fetchUser()
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}

// In View: no @StateObject/@ObservedObject wrappers needed
struct UserView: View {
    @State private var viewModel = UserViewModel()

    var body: some View {
        Group {
            if viewModel.isLoading {
                ProgressView()
            } else if let user = viewModel.user {
                Text(user.name)
            }
        }
        .task { await viewModel.load() }
    }
}

// @Bindable for two-way bindings
struct EditView: View {
    @Bindable var viewModel: EditViewModel

    var body: some View {
        TextField("Name", text: $viewModel.name)
    }
}
swift
import Observation

// New pattern: @Observable macro (replaces ObservableObject + @Published)
@Observable
class UserViewModel {
    var user: User?
    var isLoading = false
    var errorMessage: String?

    func load() async {
        isLoading = true
        defer { isLoading = false }
        do {
            user = try await fetchUser()
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}

// In View: no @StateObject/@ObservedObject wrappers needed
struct UserView: View {
    @State private var viewModel = UserViewModel()

    var body: some View {
        Group {
            if viewModel.isLoading {
                ProgressView()
            } else if let user = viewModel.user {
                Text(user.name)
            }
        }
        .task { await viewModel.load() }
    }
}

// @Bindable for two-way bindings
struct EditView: View {
    @Bindable var viewModel: EditViewModel

    var body: some View {
        TextField("Name", text: $viewModel.name)
    }
}

Migration from ObservableObject

从ObservableObject迁移

Old (ObservableObject)New (@Observable)
class: ObservableObject
@Observable class
@Published var
var
(automatic)
@StateObject
@State
@ObservedObject
Direct reference
@EnvironmentObject
@Environment(TypeName.self)

旧方案(ObservableObject)新方案(@Observable)
class: ObservableObject
@Observable class
@Published var
var
(自动生效)
@StateObject
@State
@ObservedObject
直接引用
@EnvironmentObject
@Environment(TypeName.self)

SwiftUI 6 New Views and Modifiers

SwiftUI 6新视图与修饰器

swift
// Mesh gradient (iOS 18+)
MeshGradient(
    width: 3, height: 3,
    points: [
        .init(0, 0), .init(0.5, 0), .init(1, 0),
        .init(0, 0.5), .init(0.5, 0.5), .init(1, 0.5),
        .init(0, 1), .init(0.5, 1), .init(1, 1)
    ],
    colors: [
        .red, .purple, .indigo,
        .orange, .cyan, .blue,
        .yellow, .green, .mint
    ]
)

// Zoom navigation transition
NavigationLink {
    DetailView(item: item)
} label: {
    ItemCard(item: item)
}
.matchedTransitionSource(id: item.id, in: namespace)

// ScrollView enhancements
ScrollView {
    LazyVStack {
        ForEach(items) { item in
            ItemRow(item: item)
        }
    }
}
.scrollPosition(id: $scrolledID)
.defaultScrollAnchor(.bottom)

// Custom containers
@Entry macro for EnvironmentValues
@Environment(\.myCustomValue) var value

swift
// Mesh gradient (iOS 18+)
MeshGradient(
    width: 3, height: 3,
    points: [
        .init(0, 0), .init(0.5, 0), .init(1, 0),
        .init(0, 0.5), .init(0.5, 0.5), .init(1, 0.5),
        .init(0, 1), .init(0.5, 1), .init(1, 1)
    ],
    colors: [
        .red, .purple, .indigo,
        .orange, .cyan, .blue,
        .yellow, .green, .mint
    ]
)

// Zoom navigation transition
NavigationLink {
    DetailView(item: item)
} label: {
    ItemCard(item: item)
}
.matchedTransitionSource(id: item.id, in: namespace)

// ScrollView enhancements
ScrollView {
    LazyVStack {
        ForEach(items) { item in
            ItemRow(item: item)
        }
    }
}
.scrollPosition(id: $scrolledID)
.defaultScrollAnchor(.bottom)

// Custom containers
@Entry macro for EnvironmentValues
@Environment(\.myCustomValue) var value

Swift 6 Concurrency

Swift 6并发

swift
// Complete data race safety (strict concurrency checking)
// Enable in Xcode: SWIFT_STRICT_CONCURRENCY = complete

// Sendable conformance required for data crossing isolation boundaries
struct UserData: Sendable {
    let id: UUID
    let name: String
}

// Actor isolation
actor DatabaseManager {
    private var cache: [String: Data] = [:]

    func get(_ key: String) -> Data? { cache[key] }
    func set(_ key: String, value: Data) { cache[key] = value }
}

// Global actors
@MainActor
class ViewModel {
    var items: [Item] = []

    func load() async {
        let data = await fetchFromNetwork() // Runs off main actor
        items = data // Back on main actor automatically
    }
}

// Typed throws (Swift 6)
enum DataError: Error {
    case notFound, corrupted
}

func loadData() throws(DataError) -> Data {
    guard let data = cache.get("key") else {
        throw .notFound
    }
    return data
}

swift
// Complete data race safety (strict concurrency checking)
// Enable in Xcode: SWIFT_STRICT_CONCURRENCY = complete

// Sendable conformance required for data crossing isolation boundaries
struct UserData: Sendable {
    let id: UUID
    let name: String
}

// Actor isolation
actor DatabaseManager {
    private var cache: [String: Data] = [:]

    func get(_ key: String) -> Data? { cache[key] }
    func set(_ key: String, value: Data) { cache[key] = value }
}

// Global actors
@MainActor
class ViewModel {
    var items: [Item] = []

    func load() async {
        let data = await fetchFromNetwork() // Runs off main actor
        items = data // Back on main actor automatically
    }
}

// Typed throws (Swift 6)
enum DataError: Error {
    case notFound, corrupted
}

func loadData() throws(DataError) -> Data {
    guard let data = cache.get("key") else {
        throw .notFound
    }
    return data
}

Minimum Target: iOS 17+

最低适配版本:iOS 17+

For new projects, target iOS 17+ to access:
FeatureMinimum iOSBenefit
@Observable17Simpler state management
SwiftData17Modern persistence (replaces Core Data)
NavigationStack16Type-safe navigation
Swift Charts16Native charting
MeshGradient18Beautiful gradients
ControlWidget18Control Center widgets

新项目建议适配iOS 17+以使用以下特性:
特性最低iOS版本优势
@Observable17更简洁的状态管理
SwiftData17现代持久化方案(替代Core Data)
NavigationStack16类型安全的导航
Swift Charts16原生图表组件
MeshGradient18美观的渐变效果
ControlWidget18控制中心小组件

visionOS and Spatial Computing

visionOS与空间计算

swift
// visionOS app structure
@main
struct MyVisionApp: App {
    var body: some Scene {
        // 2D window
        WindowGroup {
            ContentView()
        }

        // Immersive space
        ImmersiveSpace(id: "immersiveScene") {
            ImmersiveView()
        }

        // 3D volume
        WindowGroup(id: "3dContent") {
            Model3D(named: "Globe") { model in
                model.resizable()
                    .aspectRatio(contentMode: .fit)
            } placeholder: {
                ProgressView()
            }
        }
        .windowStyle(.volumetric)
    }
}

// RealityKit integration
import RealityKit

struct ImmersiveView: View {
    var body: some View {
        RealityView { content in
            let sphere = MeshResource.generateSphere(radius: 0.5)
            let material = SimpleMaterial(color: .blue, isMetallic: true)
            let entity = ModelEntity(mesh: sphere, materials: [material])
            content.add(entity)
        }
        .gesture(TapGesture().targetedToAnyEntity().onEnded { value in
            // Handle spatial tap
        })
    }
}

swift
// visionOS app structure
@main
struct MyVisionApp: App {
    var body: some Scene {
        // 2D window
        WindowGroup {
            ContentView()
        }

        // Immersive space
        ImmersiveSpace(id: "immersiveScene") {
            ImmersiveView()
        }

        // 3D volume
        WindowGroup(id: "3dContent") {
            Model3D(named: "Globe") { model in
                model.resizable()
                    .aspectRatio(contentMode: .fit)
            } placeholder: {
                ProgressView()
            }
        }
        .windowStyle(.volumetric)
    }
}

// RealityKit integration
import RealityKit

struct ImmersiveView: View {
    var body: some View {
        RealityView { content in
            let sphere = MeshResource.generateSphere(radius: 0.5)
            let material = SimpleMaterial(color: .blue, isMetallic: true)
            let entity = ModelEntity(mesh: sphere, materials: [material])
            content.add(entity)
        }
        .gesture(TapGesture().targetedToAnyEntity().onEnded { value in
            // Handle spatial tap
        })
    }
}

watchOS Development

watchOS开发

swift
// watchOS app with SwiftUI
@main
struct MyWatchApp: App {
    var body: some Scene {
        WindowGroup {
            NavigationStack {
                ContentView()
            }
        }
    }
}

// Complications / Widgets
struct MyWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "myWidget", provider: Provider()) { entry in
            MyWidgetView(entry: entry)
        }
        .configurationDisplayName("My Widget")
        .supportedFamilies([
            .accessoryCircular,
            .accessoryRectangular,
            .accessoryInline,
        ])
    }
}

// Watch Connectivity for iPhone <-> Watch communication
import WatchConnectivity

class ConnectivityManager: NSObject, WCSessionDelegate {
    func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
        // Handle message from paired device
    }
}
swift
// watchOS app with SwiftUI
@main
struct MyWatchApp: App {
    var body: some Scene {
        WindowGroup {
            NavigationStack {
                ContentView()
            }
        }
    }
}

// Complications / Widgets
struct MyWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "myWidget", provider: Provider()) { entry in
            MyWidgetView(entry: entry)
        }
        .configurationDisplayName("My Widget")
        .supportedFamilies([
            .accessoryCircular,
            .accessoryRectangular,
            .accessoryInline,
        ])
    }
}

// Watch Connectivity for iPhone <-> Watch communication
import WatchConnectivity

class ConnectivityManager: NSObject, WCSessionDelegate {
    func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
        // Handle message from paired device
    }
}