bjmayor 发布于 2025-07-14

借助AI学习开源项目-AppState

继续解读下面的相关代码:

  • //
  • // AppState.swift
  • // Ice
  • //
  • import Combine
  • import SwiftUI
  • /// The model for app-wide state.
  • @MainActor
  • final class AppState: ObservableObject {
  • /// A Boolean value that indicates whether the active space is fullscreen.
  • @Published private(set) var isActiveSpaceFullscreen = Bridging.isSpaceFullscreen(Bridging.activeSpaceID)
  • /// Manager for the menu bar's appearance.
  • private(set) lazy var appearanceManager = MenuBarAppearanceManager(appState: self)
  • /// Manager for events received by the app.
  • private(set) lazy var eventManager = EventManager(appState: self)
  • /// Manager for menu bar items.
  • private(set) lazy var itemManager = MenuBarItemManager(appState: self)
  • /// Manager for the state of the menu bar.
  • private(set) lazy var menuBarManager = MenuBarManager(appState: self)
  • /// Manager for app permissions.
  • private(set) lazy var permissionsManager = PermissionsManager(appState: self)
  • /// Manager for the app's settings.
  • private(set) lazy var settingsManager = SettingsManager(appState: self)
  • /// Manager for app updates.
  • private(set) lazy var updatesManager = UpdatesManager(appState: self)
  • /// Manager for user notifications.
  • private(set) lazy var userNotificationManager = UserNotificationManager(appState: self)
  • /// Global cache for menu bar item images.
  • private(set) lazy var imageCache = MenuBarItemImageCache(appState: self)
  • /// Manager for menu bar item spacing.
  • let spacingManager = MenuBarItemSpacingManager()
  • /// Model for app-wide navigation.
  • let navigationState = AppNavigationState()
  • /// The app's hotkey registry.
  • nonisolated let hotkeyRegistry = HotkeyRegistry()
  • /// The app's delegate.
  • private(set) weak var appDelegate: AppDelegate?
  • /// The window that contains the settings interface.
  • private(set) weak var settingsWindow: NSWindow?
  • /// The window that contains the permissions interface.
  • private(set) weak var permissionsWindow: NSWindow?
  • /// A Boolean value that indicates whether the "ShowOnHover" feature is prevented.
  • private(set) var isShowOnHoverPrevented = false
  • /// Storage for internal observers.
  • private var cancellables = Set<AnyCancellable>()
  • /// A Boolean value that indicates whether the app is running as a SwiftUI preview.
  • let isPreview: Bool = {
  • #if DEBUG
  • let environment = ProcessInfo.processInfo.environment
  • let key = "XCODE_RUNNING_FOR_PREVIEWS"
  • return environment[key] != nil
  • #else
  • return false
  • #endif
  • }()
  • /// A Boolean value that indicates whether the application can set the cursor
  • /// in the background.
  • var setsCursorInBackground: Bool {
  • get { Bridging.getConnectionProperty(forKey: "SetsCursorInBackground") as? Bool ?? false }
  • set { Bridging.setConnectionProperty(newValue, forKey: "SetsCursorInBackground") }
  • }
  • /// Configures the internal observers for the app state.
  • private func configureCancellables() {
  • var c = Set<AnyCancellable>()
  • Publishers.Merge3(
  • NSWorkspace.shared.notificationCenter
  • .publisher(for: NSWorkspace.activeSpaceDidChangeNotification)
  • .mapToVoid(),
  • // Frontmost application change can indicate a space change from one display to
  • // another, which gets ignored by NSWorkspace.activeSpaceDidChangeNotification.
  • NSWorkspace.shared
  • .publisher(for: \.frontmostApplication)
  • .mapToVoid(),
  • // Clicking into a fullscreen space from another space is also ignored.
  • UniversalEventMonitor
  • .publisher(for: .leftMouseDown)
  • .delay(for: 0.1, scheduler: DispatchQueue.main)
  • .mapToVoid()
  • )
  • .receive(on: DispatchQueue.main)
  • .sink { [weak self] _ in
  • guard let self else {
  • return
  • }
  • isActiveSpaceFullscreen = Bridging.isSpaceFullscreen(Bridging.activeSpaceID)
  • }
  • .store(in: &c)
  • NSWorkspace.shared.publisher(for: \.frontmostApplication)
  • .receive(on: DispatchQueue.main)
  • .sink { [weak self] frontmostApplication in
  • guard let self else {
  • return
  • }
  • navigationState.isAppFrontmost = frontmostApplication == .current
  • }
  • .store(in: &c)
  • if let settingsWindow {
  • settingsWindow.publisher(for: \.isVisible)
  • .debounce(for: 0.05, scheduler: DispatchQueue.main)
  • .sink { [weak self] isVisible in
  • guard let self else {
  • return
  • }
  • navigationState.isSettingsPresented = isVisible
  • }
  • .store(in: &c)
  • } else {
  • Logger.appState.warning("No settings window!")
  • }
  • Publishers.Merge(
  • navigationState.$isAppFrontmost,
  • navigationState.$isSettingsPresented
  • )
  • .debounce(for: 0.1, scheduler: DispatchQueue.main)
  • .sink { [weak self] shouldUpdate in
  • guard
  • let self,
  • shouldUpdate
  • else {
  • return
  • }
  • Task.detached {
  • if ScreenCapture.cachedCheckPermissions(reset: true) {
  • await self.imageCache.updateCacheWithoutChecks(sections: MenuBarSection.Name.allCases)
  • }
  • }
  • }
  • .store(in: &c)
  • menuBarManager.objectWillChange
  • .sink { [weak self] in
  • self?.objectWillChange.send()
  • }
  • .store(in: &c)
  • permissionsManager.objectWillChange
  • .sink { [weak self] in
  • self?.objectWillChange.send()
  • }
  • .store(in: &c)
  • settingsManager.objectWillChange
  • .sink { [weak self] in
  • self?.objectWillChange.send()
  • }
  • .store(in: &c)
  • updatesManager.objectWillChange
  • .sink { [weak self] in
  • self?.objectWillChange.send()
  • }
  • .store(in: &c)
  • cancellables = c
  • }
  • /// Sets up the app state.
  • func performSetup() {
  • configureCancellables()
  • permissionsManager.stopAllChecks()
  • menuBarManager.performSetup()
  • appearanceManager.performSetup()
  • eventManager.performSetup()
  • settingsManager.performSetup()
  • itemManager.performSetup()
  • imageCache.performSetup()
  • updatesManager.performSetup()
  • userNotificationManager.performSetup()
  • }
  • /// Assigns the app delegate to the app state.
  • func assignAppDelegate(_ appDelegate: AppDelegate) {
  • guard self.appDelegate == nil else {
  • Logger.appState.warning("Multiple attempts made to assign app delegate")
  • return
  • }
  • self.appDelegate = appDelegate
  • }
  • /// Assigns the settings window to the app state.
  • func assignSettingsWindow(_ window: NSWindow) {
  • guard window.identifier?.rawValue == Constants.settingsWindowID else {
  • Logger.appState.warning("Window \(window.identifier?.rawValue ?? "<NIL>") is not the settings window!")
  • return
  • }
  • settingsWindow = window
  • configureCancellables()
  • }
  • /// Assigns the permissions window to the app state.
  • func assignPermissionsWindow(_ window: NSWindow) {
  • guard window.identifier?.rawValue == Constants.permissionsWindowID else {
  • Logger.appState.warning("Window \(window.identifier?.rawValue ?? "<NIL>") is not the permissions window!")
  • return
  • }
  • permissionsWindow = window
  • configureCancellables()
  • }
  • /// Opens the settings window.
  • func openSettingsWindow() {
  • with(EnvironmentValues()) { environment in
  • environment.openWindow(id: Constants.settingsWindowID)
  • }
  • }
  • /// Dismisses the settings window.
  • func dismissSettingsWindow() {
  • with(EnvironmentValues()) { environment in
  • environment.dismissWindow(id: Constants.settingsWindowID)
  • }
  • }
  • /// Opens the permissions window.
  • func openPermissionsWindow() {
  • with(EnvironmentValues()) { environment in
  • environment.openWindow(id: Constants.permissionsWindowID)
  • }
  • }
  • /// Dismisses the permissions window.
  • func dismissPermissionsWindow() {
  • with(EnvironmentValues()) { environment in
  • environment.dismissWindow(id: Constants.permissionsWindowID)
  • }
  • }
  • /// Activates the app and sets its activation policy to the given value.
  • func activate(withPolicy policy: NSApplication.ActivationPolicy) {
  • // Store whether the app has previously activated inside an internal
  • // context to keep it isolated.
  • enum Context {
  • static let hasActivated = ObjectStorage<Bool>()
  • }
  • func activate() {
  • if let frontApp = NSWorkspace.shared.frontmostApplication {
  • NSRunningApplication.current.activate(from: frontApp)
  • } else {
  • NSApp.activate()
  • }
  • NSApp.setActivationPolicy(policy)
  • }
  • if Context.hasActivated.value(for: self) == true {
  • activate()
  • } else {
  • Context.hasActivated.set(true, for: self)
  • Logger.appState.debug("First time activating app, so going through Dock")
  • // Hack to make sure the app properly activates for the first time.
  • NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first?.activate()
  • DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
  • activate()
  • }
  • }
  • }
  • /// Deactivates the app and sets its activation policy to the given value.
  • func deactivate(withPolicy policy: NSApplication.ActivationPolicy) {
  • if let nextApp = NSWorkspace.shared.runningApplications.first(where: { $0 != .current }) {
  • NSApp.yieldActivation(to: nextApp)
  • } else {
  • NSApp.deactivate()
  • }
  • NSApp.setActivationPolicy(policy)
  • }
  • /// Prevents the "ShowOnHover" feature.
  • func preventShowOnHover() {
  • isShowOnHoverPrevented = true
  • }
  • /// Allows the "ShowOnHover" feature.
  • func allowShowOnHover() {
  • isShowOnHoverPrevented = false
  • }
  • }
  • // MARK: AppState: BindingExposable
  • extension AppState: BindingExposable { }
  • // MARK: - Logger
  • private extension Logger {
  • /// The logger to use for the app state.
  • static let appState = Logger(category: "AppState")
  • }
swift

好的,我们继续解读 AppState.swift 文件。

如果说 AppDelegate 是应用程序的“事件总管”,那么 AppState 就是整个应用程序的**“大脑”和“中央数据中心”**。它持有并管理着 app 运行所需的所有状态、数据和核心逻辑。AppDelegate 负责响应系统事件,然后通知 AppState 来进行实际的状态更新和处理。

阅读全文 »

bjmayor 发布于 2025-07-13

借助AI学习开源项目-AppDelegate

  • //
  • // AppDelegate.swift
  • // Ice
  • //
  • import SwiftUI
  • @MainActor
  • final class AppDelegate: NSObject, NSApplicationDelegate {
  • private weak var appState: AppState?
  • // MARK: NSApplicationDelegate Methods
  • func applicationWillFinishLaunching(_ notification: Notification) {
  • guard let appState else {
  • Logger.appDelegate.warning("Missing app state in applicationWillFinishLaunching")
  • return
  • }
  • // Assign the delegate to the shared app state.
  • appState.assignAppDelegate(self)
  • // Allow the app to set the cursor in the background.
  • appState.setsCursorInBackground = true
  • }
  • func applicationDidFinishLaunching(_ notification: Notification) {
  • guard let appState else {
  • Logger.appDelegate.warning("Missing app state in applicationDidFinishLaunching")
  • return
  • }
  • // Dismiss the windows.
  • appState.dismissSettingsWindow()
  • appState.dismissPermissionsWindow()
  • // Hide the main menu to make more space in the menu bar.
  • if let mainMenu = NSApp.mainMenu {
  • for item in mainMenu.items {
  • item.isHidden = true
  • }
  • }
  • // Perform setup after a small delay to ensure that the settings window
  • // has been assigned.
  • DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  • guard !appState.isPreview else {
  • return
  • }
  • // If we have the required permissions, set up the shared app state.
  • // Otherwise, open the permissions window.
  • switch appState.permissionsManager.permissionsState {
  • case .hasAllPermissions, .hasRequiredPermissions:
  • appState.performSetup()
  • case .missingPermissions:
  • appState.activate(withPolicy: .regular)
  • appState.openPermissionsWindow()
  • }
  • }
  • }
  • func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
  • // Deactivate and set the policy to accessory when all windows are closed.
  • appState?.deactivate(withPolicy: .accessory)
  • return false
  • }
  • func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
  • return true
  • }
  • // MARK: Other Methods
  • /// Assigns the app state to the delegate.
  • func assignAppState(_ appState: AppState) {
  • guard self.appState == nil else {
  • Logger.appDelegate.warning("Multiple attempts made to assign app state")
  • return
  • }
  • self.appState = appState
  • }
  • /// Opens the settings window and activates the app.
  • @objc func openSettingsWindow() {
  • guard let appState else {
  • Logger.appDelegate.error("Failed to open settings window")
  • return
  • }
  • // Small delay makes this more reliable.
  • DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  • appState.activate(withPolicy: .regular)
  • appState.openSettingsWindow()
  • }
  • }
  • }
  • // MARK: - Logger
  • private extension Logger {
  • static let appDelegate = Logger(category: "AppDelegate")
  • }
swift

我没有swift开发经验。请尽可能详细地解释上述代码。

gemini answer

好的,我们来详细解释一下这段 Swift 代码。假设你没有任何 Swift 开发经验,我会用最通俗易懂的方式来讲解。

这段代码定义了一个名为 “Ice” 的 macOS 应用程序的 AppDelegate。你可以把 AppDelegate 想象成这个应用程序的**“总管”或“事件经理”**。当 app 的生命周期中发生关键事件时,比如 app 启动、关闭窗口、或者即将退出时,操作系统就会通知这个“总管”,由它来负责处理。


核心功能总结

简单来说,这段代码为 “Ice” 这个 app 定义了启动时的核心行为。它的主要工作包括:

  1. 启动与初始化:处理 app 启动时的一系列设置流程。
  2. 权限检查:检查 app 是否获得了正常运行所必需的系统权限。如果没有,它会主动弹出窗口,引导用户去授权。
  3. 窗口管理:控制设置窗口和其他窗口的显示与隐藏。
  4. 后台运行:确保即使用户关闭了所有可见窗口,app 依然能在后台持续运行。这通常是菜单栏工具的典型特征。

阅读全文 »

bjmayor 发布于 2025-07-12

@MainActor 是干嘛用的?

@MainActor is a Swift attribute that ensures code runs on the main thread/main actor. It’s used to guarantee UI updates and other main-thread-only operations execute safely.

Key uses:

  • Classes/structs that update UI
  • Properties/methods that must run on main thread
  • Preventing data races in concurrent code
  • SwiftUI view models and UI-related code

阅读全文 »

bjmayor 发布于 2025-07-12

claude code 使用豆包 1.6

https://github.com/fuergaosi233/claude-code-proxy

上文用的litellm 配置豆包 1.6 使用claude code, 实际体验并不好。
新找了个开源项目效果还不错。

阅读全文 »

bjmayor 发布于 2025-07-12

使用 LiteLLM 配合豆包1.6 来驱动 Claude Code:完整配置指南


claudeCode 搞账号太难了。而且挺贵。
目前有白嫖的方式: https://anyrouter.top/register?aff=wWte
注册完,点击右上角的使用指南就可以了。
关键是配置环境变量:ANTHROPIC_AUTH_TOKEN 和 ANTHROPIC_BASE_URL

另外最近kimi开源的k2也可以这么搞。ANTHROPIC_BASE_URL填https://api.moonshot.cn/anthropic,ANTHROPIC_AUTH_TOKEN 填kimi的key就行。

豆包是openapi接口模型,麻烦点,要借助LiteLLM

概述

豆包1.6(Doubao-1.6)是字节跳动最新推出的通用大语言模型,具备强大的代码理解和生成能力。通过 LiteLLM 这个统一的 LLM API 框架,我们可以将豆包1.6 集成到 Claude Code 中,获得更优质的编程辅助体验。

为什么选择豆包1.6 + Claude Code

  • 成本优势:豆包1.6 的定价相比 Claude 3.5 Sonnet 更具性价比
  • 中文优化:对中文代码注释和技术文档的理解更准确
  • 代码能力:在代码生成、重构、解释方面表现出色
  • 稳定服务:依托火山引擎,提供企业级稳定性保障

前置条件

  1. 已安装 Claude Code CLI 工具
  2. 拥有火山引擎账号并完成实名认证
  3. 开通了方舟大模型服务

步骤一:获取豆包 API 凭证

1.1 创建 API Key

  1. 登录 https://console.volcengine.com/
  2. 进入「方舟大模型服务」-「API Key 管理」
  3. 点击「创建 API Key」,保存好生成的密钥

1.2 确认模型可用性

在控制台确认已开通 doubao-1-6 系列模型:

  • doubao-1-6-chat-32k:通用对话模型
  • doubao-1-6-pro-32k:高性能版本
  • doubao-1-6-lite-32k:轻量快速版本

阅读全文 »

bjmayor 发布于 2025-07-04

从第一性原理讲透:为什么你的 Docker Service 因“vxlan interface: file exists”而失败?

在云原生和容器化的世界里,Docker Swarm 为我们提供了一种简单而强大的方式来编排和管理容器集群。然而,在这种便利的背后,是一套复杂而精密的网络模型。当我们兴致勃勃地执行 docker service createdocker stack deploy 时,有时会迎面撞上一个令人困惑的错误,就像你遇到的那样:

  • network sandbox join failed: subnet sandbox join failed for "10.0.3.0/24": error creating vxlan interface: file exists

重启 Docker (systemctl restart docker) 似乎无济于事,但通过 docker stack rmdocker network prune 组合拳却能奇迹般地解决。这背后到底发生了什么?

要回答这个问题,我们不能只停留在“怎么解决”的层面,而必须深入底层,从第一性原理(First Principles)出发,理解 Docker Swarm 的网络是如何工作的。

阅读全文 »