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) } }
问题原因
- 缓存时机错误:按钮点击时就调用
imageCache.set(imageSelected, forKey: "ProfileImage"),此时用户还未选择图片,imageSelected是初始空UIImage,导致缓存中存入的是空图,第一次选择图片后缓存并未更新。 - 视图未触发刷新:ImageCache是类,修改缓存后不会自动通知SwiftUI视图更新,视图无法感知缓存变化,必须再次点击按钮才会重新读取缓存。
解决方案
- 移除按钮action中的缓存设置代码,将缓存更新放到图片选择完成的回调中。
- 添加@State变量跟踪缓存头像状态,触发视图自动刷新。
- 在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
相关产品推荐
相关产品推荐

