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

Swift缓存图片需点击两次按钮才加载的问题求助

Swift头像缓存加载问题:选择图片后需点击两次按钮才显示

我是Swift编程新手,遇到一个问题:选择图片后,缓存的头像图片需要点击两次按钮才能加载,而非点击一次即可。尝试过图片放置后刷新应用,但没有效果。

原代码实现

视图代码

@State var openCameraRoll = false
@State private var imageSelected = UIImage()
@State private var showImagePicker = false
@State private var sourceType: UIImagePickerController.SourceType = .photoLibrary
let imageCache = ImageCache.shared

Button(action: {

    openCameraRoll = true
    ImageCache.shared.checkIfImageExistsInCache(forKey: "ProfileImage")
    imageCache.set(imageSelected, forKey: "ProfileImage")
}) {
    if let cachedImage = imageCache.get(forKey: "ProfileImage") {
            Image(uiImage: cachedImage)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 100, height: 100)
                .clipShape(Circle())
                .overlay(
                    Circle()
                        .fill(Color.red)
                        .padding([.top, .leading], 70)
                )
                .overlay(
                    Image(systemName: "plus.circle.fill")
                        .symbolRenderingMode(.palette)
                        .foregroundStyle(.red, .white)
                        .padding([.top, .leading], 70)
                        .font(.system(size: 23))
                )
                .onAppear {
                    print(cachedImage)
                }
    }
    else {
        Image(systemName: "person.circle.fill")
            .resizable()
            .scaledToFit()
            .frame(width: 100, height: 100)
            .foregroundColor(.white)
            .clipShape(Circle())
            .overlay(
                Circle()
                    .fill(Color.red)
                    .padding([.top, .leading], 70)
            )
            .overlay(
                Image(systemName: "plus.circle.fill")
                    .symbolRenderingMode(.palette)
                    .foregroundStyle(.red, .white)
                    .padding([.top, .leading], 70)
                    .font(.system(size: 23))
            )
    }
}
.sheet(isPresented: $showImagePicker) {
    ImagePicker(selectedImage: $imageSelected, sourceType: sourceType)
}
.actionSheet(isPresented: $openCameraRoll) {
    ActionSheet(
        title: Text("Choose Source"),
        buttons: [
            .default(Text("Library")) {
                sourceType = .photoLibrary
                showImagePicker = true
            },
            .default(Text("Camera")) {
                sourceType = .camera
                showImagePicker = true
            },
            .cancel()
        ]
    )
}

ImageCache类代码

class ImageCache {
    static let shared = ImageCache()
    
    private init() {}
    
    func set(_ image: UIImage, forKey key: String) {
        // Convert the image to data
        if let imageData = image.jpegData(compressionQuality: 1.0) {
            // Save the image data to UserDefaults
            UserDefaults.standard.set(imageData, forKey: key)
        }
    }
    func get(forKey key: String) -> UIImage? {
        // Retrieve the image data from UserDefaults
        if let imageData = UserDefaults.standard.data(forKey: key),
           let image = UIImage(data: imageData) {
            return image
        }
        return nil
    }
    func delete(forKey key: String) {
            // Remove the image data from UserDefaults
            UserDefaults.standard.removeObject(forKey: key)
        }
}

问题原因

  1. 缓存时机错误:按钮点击时就调用imageCache.set(imageSelected, forKey: "ProfileImage"),此时用户还未选择图片,imageSelected是初始空UIImage,导致缓存中存入的是空图,第一次选择图片后缓存并未更新。
  2. 视图未触发刷新:ImageCache是类,修改缓存后不会自动通知SwiftUI视图更新,视图无法感知缓存变化,必须再次点击按钮才会重新读取缓存。

解决方案

  1. 移除按钮action中的缓存设置代码,将缓存更新放到图片选择完成的回调中。
  2. 添加@State变量跟踪缓存头像状态,触发视图自动刷新。
  3. 在ImagePicker关闭后(图片选择完成),更新缓存并刷新状态。

修改后的完整代码

视图代码

@State var openCameraRoll = false
@State private var imageSelected = UIImage()
@State private var showImagePicker = false
@State private var sourceType: UIImagePickerController.SourceType = .photoLibrary
@State private var cachedProfileImage: UIImage? // 新增状态变量跟踪缓存头像
let imageCache = ImageCache.shared

Button(action: {
    openCameraRoll = true
}) {
    if let cachedImage = cachedProfileImage ?? imageCache.get(forKey: "ProfileImage") {
            Image(uiImage: cachedImage)
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: 100, height: 100)
                .clipShape(Circle())
                .overlay(
                    Circle()
                        .fill(Color.red)
                        .padding([.top, .leading], 70)
                )
                .overlay(
                    Image(systemName: "plus.circle.fill")
                        .symbolRenderingMode(.palette)
                        .foregroundStyle(.red, .white)
                        .padding([.top, .leading], 70)
                        .font(.system(size: 23))
                )
    }
    else {
        Image(systemName: "person.circle.fill")
            .resizable()
            .scaledToFit()
            .frame(width: 100, height: 100)
            .foregroundColor(.white)
            .clipShape(Circle())
            .overlay(
                Circle()
                    .fill(Color.red)
                    .padding([.top, .leading], 70)
            )
            .overlay(
                Image(systemName: "plus.circle.fill")
                    .symbolRenderingMode(.palette)
                    .foregroundStyle(.red, .white)
                    .padding([.top, .leading], 70)
                    .font(.system(size: 23))
            )
    }
}
.sheet(isPresented: $showImagePicker, onDismiss: {
    // 图片选择完成后更新缓存和状态变量
    if !imageSelected.isEqual(UIImage()) {
        imageCache.set(imageSelected, forKey: "ProfileImage")
        cachedProfileImage = imageSelected
    }
}) {
    ImagePicker(selectedImage: $imageSelected, sourceType: sourceType)
}
.actionSheet(isPresented: $openCameraRoll) {
    ActionSheet(
        title: Text("Choose Source"),
        buttons: [
            .default(Text("Library")) {
                sourceType = .photoLibrary
                showImagePicker = true
            },
            .default(Text("Camera")) {
                sourceType = .camera
                showImagePicker = true
            },
            .cancel()
        ]
    )
}
// 视图初始化时读取缓存
.onAppear {
    cachedProfileImage = imageCache.get(forKey: "ProfileImage")
}

ImageCache类代码(无需修改)

class ImageCache {
    static let shared = ImageCache()
    
    private init() {}
    
    func set(_ image: UIImage, forKey key: String) {
        if let imageData = image.jpegData(compressionQuality: 1.0) {
            UserDefaults.standard.set(imageData, forKey: key)
        }
    }
    func get(forKey key: String) -> UIImage? {
        if let imageData = UserDefaults.standard.data(forKey: key),
           let image = UIImage(data: imageData) {
            return image
        }
        return nil
    }
    func delete(forKey key: String) {
        UserDefaults.standard.removeObject(forKey: key)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 09:29:53