動態

詳情 返回 返回

SwiftUI中的鍵盤快捷鍵、初始頁面控制及網絡權限管理解析 - 動態 詳情

SwiftUI 中的鍵盤快捷鍵

你有沒有用過 Mac 應用時想過——“要是這個功能能用快捷鍵直接觸發就好了,不用每次都點按鈕”
SwiftUI 裏面,這個功能超級容易加,用 .keyboardShortcut() 就行。

基本格式是這樣的:

.keyboardShortcut("鍵", modifiers: [.command, .shift])

比如,你想用 Command + C 來觸發一個動作,只要這樣寫:

Button("點擊我") {
    print("按鈕被點了!")
}
.keyboardShortcut("C", modifiers: [.command])

按下 Command + C,這個按鈕的代碼就會執行。

痛點分析:
假設你做的是一個 macOS 錄音管理軟件,用户一天可能要導出幾十次音頻文件。
如果每次都得用鼠標點擊“導出”按鈕,效率很低,還容易點錯。
加一個快捷鍵(比如 Command + E 導出),直接秒操作,用户體驗瞬間提升。

額外示例:多個快捷鍵支持同一操作

struct ContentView: View {
    var body: some View {
        Button("保存文件") {
            print("文件已保存")
        }
        .keyboardShortcut("S", modifiers: [.command])
        .keyboardShortcut(.return, modifiers: [.command]) // Command + 回車
    }
}

這裏用户既能用 Command + S 保存,也能用 Command + 回車 保存,非常靈活。

控制 SwiftUI 應用的第一個界面

當你的應用啓動時,你通常不想每次都顯示同一個頁面,而是要根據情況來決定顯示什麼。
比如用户已經登錄了,那就直接進主界面;沒登錄,就去登錄頁。

基礎寫法:

@main
struct MyApp: App {
    @State private var isLoggedIn = false

    var body: some Scene {
        WindowGroup {
            if isLoggedIn {
                MainView()
            } else {
                LoginView()
            }
        }
    }
}

痛點分析:
想象一下你用銀行 App,剛剛登錄過,五分鐘後回來,結果它又讓你重新輸賬號密碼。
是不是很煩?
通過控制初始界面,你可以讓用户直接回到之前的狀態,減少重複登錄的麻煩。

額外示例:結合 UserDefaults 自動記住登錄狀態

@main
struct MyApp: App {
    @State private var isLoggedIn = UserDefaults.standard.bool(forKey: "isLoggedIn")

    var body: some Scene {
        WindowGroup {
            if isLoggedIn {
                MainView()
            } else {
                LoginView(onLoginSuccess: {
                    UserDefaults.standard.set(true, forKey: "isLoggedIn")
                    isLoggedIn = true
                })
            }
        }
    }
}

這樣只要用户登錄成功一次,下次啓動 App 就會直接進主界面。

NetworkManager & AuthManager:為什麼會報“private 初始化器不可訪問”

你的 NetworkManager 是用 單例模式 寫的:

class NetworkManager {
    static let shared = NetworkManager()
    private init() {}
}

這樣做的意思是:

“外部禁止用 NetworkManager() 創建對象,只能用我提供的 shared 共享實例。”

但是在 AuthManager 裏面,你寫了:

private let networkManager = NetworkManager() //  報錯

這就違反了規則,所以 Swift 提示 “initializer is inaccessible due to 'private' protection level”

正確做法:

private let networkManager = NetworkManager.shared

這樣你用的就是那個唯一的共享實例。

痛點分析:
如果你不小心創建了多個 NetworkManager 實例,每個實例的 URLSession 和認證狀態可能不一樣,
結果可能出現:

  • 登錄成功,但上傳文件時另一個實例不知道你已經登錄。
  • API 請求丟失了認證頭,導致無緣無故失敗。

這些都是很隱蔽、讓人抓狂的 Bug。

額外示例:一個帶 Token 的 NetworkManager

class NetworkManager {
    static let shared = NetworkManager()
    private var authToken: String?
    
    private init() {}

    func setToken(_ token: String) {
        self.authToken = token
    }

    func getRequest(url: String) async throws -> Data {
        var request = URLRequest(url: URL(string: url)!)
        if let token = authToken {
            request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        }
        let (data, _) = try await URLSession.shared.data(for: request)
        return data
    }
}

然後在 AuthManager 登錄後:

let response = try await networkManager.login(email: "a@b.com", password: "123456")
NetworkManager.shared.setToken(response.token)

這樣後續所有 API 調用都會自動帶上 Token。

Add a new 評論

Some HTML is okay.