You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何为CarPlay从URL加载图片替代Base64?

CarPlay中CPGridButton异步加载网络图片的实现方案

核心思路

原代码是同步加载Base64图片,换成URL异步加载后,无法在创建CPGridButton时直接拿到图片,所以要先创建带占位图的按钮,再异步加载图片并更新按钮的图片资源。

修改后的完整代码

private func updateGridTemplate() {
    guard let interfaceController = self.interfaceController else { return }
    
    var gridButtons = [CPGridButton]()
    
    for notification in storedNotifications {
        guard let configs = notification.incidenceConfigurations else { continue }
        for config in configs {
            // 先创建带占位图的按钮,保证UI先显示
            let placeholderImage = UIImage(named: "Icon") ?? UIImage()
            let button = CPGridButton(titleVariants: [config.phrase ?? "Title"], image: placeholderImage, handler: { _ in
                self.showOptions(item: config)
            })
            gridButtons.append(button)
            
            // 异步加载网络图片,替换占位图
            guard let imageUrlString = config.icon, let url = URL(string: imageUrlString) else { continue }
            
            // 调用你已实现的异步加载方法,这里是示例实现
            loadImage(from: url) { [weak self] loadedImage in
                guard let self = self, let image = loadedImage else { return }
                // CarPlay UI操作必须在主线程执行
                DispatchQueue.main.async {
                    button.image = image
                }
            }
        }
    }
    
    let leadingButton = CPBarButton(type: .text) { barButton in
        self.viewModel.makePhoneCall()
    }
    leadingButton.title = "CALL ME"
    
    if trailingButton == nil {
        trailingButton = CPBarButton(type: .text) { barbutton in
            print("")
        }
    }
    
    updateTrailingButtonTitle()
    
    let gridTemplate = CPGridTemplate(title: "MY APP", gridButtons: gridButtons)
    gridTemplate.trailingNavigationBarButtons = [trailingButton!]
    gridTemplate.leadingNavigationBarButtons = [leadingButton]
    
    interfaceController.setRootTemplate(gridTemplate, animated: true)
}

// 异步图片加载方法示例(如果还没实现可以直接用这个)
private func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) {
    URLSession.shared.dataTask(with: url) { data, _, error in
        guard let data = data, error == nil else {
            completion(nil)
            return
        }
        let image = UIImage(data: data)
        completion(image)
    }.resume()
}

关键注意点

  • 占位图优先:先给按钮设置占位图,避免CarPlay界面出现空白,提升用户体验
  • 主线程更新UI:CarPlay的所有UI操作必须在主线程执行,所以图片加载完成后一定要切换到主线程更新按钮的image属性
  • 避免循环引用:用[weak self]捕获列表,防止闭包持有导致内存泄漏
  • 缓存优化:如果需要频繁加载相同图片,建议添加缓存逻辑(比如用NSCache),减少重复网络请求,提升性能

内容的提问来源于stack exchange,提问作者lacaveira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:22:05