在一个结构体中添加图像会更新另一个视图。

huangapple go评论63阅读模式
英文:

Adding image in one struct updates another view

问题

I understand that you have two sections in your code where users can upload photos, and there seems to be an issue where the profile picture section is grabbing the saved URL from the second scenario and using it as the new profile picture. This could be happening if you are inadvertently sharing the image variable between these two sections or if there's some shared state.

You should ensure that the image variable used for the profile picture is isolated from the image variable used in the second scenario. It's possible that the two parts of your code are sharing the same @Published var image: UIImage? variable or a common URL.

You might want to double-check the following points:

  1. Make sure you have separate instances of UrlImageModel for the profile picture and the second scenario, each with its own @Published var image: UIImage? and @Published var urlString: String?.

  2. Ensure that the imageCache for each instance of UrlImageModel is independent and not shared between the two sections.

  3. Confirm that the URLs you are using for the profile picture and the second scenario are distinct and not being overwritten or shared unintentionally.

By isolating the variables and ensuring separate instances for the profile picture and the second scenario, you should be able to prevent the issue of one affecting the other.

英文:

Running into an issue where I have two sections where a user can upload photos. The first being the profile picture where I implement a cache system like so:

class UrlImageModel: ObservableObject {
    @Published var image: UIImage?
    @Published var urlString: String?
    var imageCache = CacheImageManager.getImageCache()
     @Published var newImageAdded = false
     @Published var pulledCacheImage: UIImage?
     init (urlString: String?) {
         self.urlString = urlString
         loadImage()
    
     }
  
    func loadImage() {
        guard let urlString = urlString else {
            return
        }
        if newImageAdded {
            print("new Image Added")
            loadImageFromURL()
        }
       else if loadImageFromCache() && newImageAdded {
            print("cache located") // AFTER INPUT LOADING, NO NEW IMAGE
            return
        }
        else{
            loadImageFromURL()
        }
    }

    func loadImageFromCache() -> Bool {
        guard let urlString = urlString else {
            print("urlString is nil")
            return false
        }
        
       // print("cache LOADING: \(imageCache)") // << after input input second outcome printed // 4th after refreshing NO NEW IMAGE
        
        guard let cacheImage = imageCache.getCache(forKey: urlString) else {
            print("cache not found for key: \(urlString)") // << 5th SHOWS NEW IMAGE!! OR INIATIES IT
            return false
        }
        
        image = cacheImage
        return true
    }

    private func loadImageFromURL (){
      
        guard let urlString = urlString else {
                 return
             }
        let url = URL(string: urlString)!
           let task = URLSession.shared.dataTask(with:url, completionHandler:
               getImageFromResponse(data: response: error: ))
           task.resume()
    }
    
    private func getImageFromResponse (data: Data?, response: URLResponse?, error: Error?){
        DispatchQueue.main.async {
         
            guard error == nil else {
                print("error: \(error!)")
                return
            }
        }
        
        guard let data = data else {
            print("no data for image found")
            return
        }
        
        DispatchQueue.main.async {
            guard let loadedImage = UIImage(data: data) else {
                return
            }
            self.imageCache.setCache(forKey: self.urlString!, image: loadedImage)
            self.image = loadedImage
        }
    }
}

class CacheImageManager {
    static let shared = CacheImageManager()
    private lazy var cache: NSCache<NSString, UIImage> = {
        let cache = NSCache<NSString, UIImage>()
        cache.countLimit = 100
        cache.totalCostLimit = 1024 * 1024 * 100
        return cache
    }()
    
    func getCache(forKey key: String) -> UIImage? {
        return cache.object(forKey: NSString(string: key))
    }
    
    func setCache(forKey key: String, image: UIImage) {
        cache.setObject(image, forKey: NSString(string: key))
    }
    
    func removeCache(forKey key: String) {
        cache.removeObject(forKey: NSString(string: key))
    }
}
extension CacheImageManager{
    private static var imageCache = CacheImageManager()
    static func getImageCache() -> CacheImageManager {
        imageCache
    }
}

I then have the second scenario where a user can upload an image below:

private func persistImageToStorage() {
            guard let uid = FirebaseManager.shared.auth.currentUser?.uid else { return }
            let ref = FirebaseManager.shared.storage.reference(withPath: uid)
        
            guard let imageData = self.inputImage?.jpegData(compressionQuality: 0.5) else { return }
            ref.putData(imageData, metadata: nil) { metadata, err in
                if let err = err {
                   print("failed to push to storage \(err)")
                    return
                }

                ref.downloadURL { url, err in
                    if let err = err {
                        print("failed to fetch download link")
                        return
                    }

                   print("Image saved Successfully")
                    guard let url = url else { return }
                    
                    //save
                    image = url.absoluteString
                    ema.recipeImage = url.absoluteString
                   
                }
            }
        }
    
    var body: some View {
        NavigationView{
            VStack{
                VStack{
                    WebImage(url: URL(string: image))
                        .placeholder(Image("defaultRecipeImage").resizable())
                        .resizable()
                        .clipShape(RoundedRectangle(cornerRadius: 10.0))
                        .frame(width:320, height: 200)
                        .aspectRatio(contentMode: .fill)
                    }
                .padding(.top, 15)
                .onChange(of: inputImage, perform: { _ in
                    persistImageToStorage()
                })
               struct EditorImagePicker: UIViewControllerRepresentable{
    @Binding var imageForRecipe: UIImage?

    class Coordinator: NSObject, PHPickerViewControllerDelegate{
        var parent: EditorImagePicker

        init(_ parent: EditorImagePicker){
            self.parent = parent
            print("locator b")
        }

        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)

            guard let provider = results.first?.itemProvider else { return }

            if provider.canLoadObject(ofClass: UIImage.self){
                provider.loadObject(ofClass: UIImage.self){image, _ in
                    DispatchQueue.main.async {
                        self.parent.imageForRecipe = image as? UIImage
                    }
                }
            }
        }
    }

    func makeUIViewController(context: Context) -> PHPickerViewController {
        //configures ios to just be able to select images
        var config = PHPickerConfiguration()
        config.filter = .images

        //the view of picker
        let picker = PHPickerViewController(configuration: config)
        picker.delegate = context.coordinator
        return picker
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
        //leave empty for now
    }
}

 .sheet(isPresented: $showingImagePicker){
                    EditorImagePicker(imageForRecipe: $inputImage)
                }

The issue I'm encountering is when a user uploads an image for scenario 2, the profile picture then grabs that saved url and uses it as the new profile picture (and stores in cache). Is there something that is connecting the two that would be causing this issue?

答案1

得分: 1

这个错误是因为在重新初始化此结构时,self 的值已过时。修复如下:

func makeCoordinator() -> Coordinator {
    Coordinator()
}

func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
    context.coordinator.imageForRecipeBinding = _imageForRecipe
}

你为什么不使用 SwiftUI 内置的 .photosPicker(isPresented:) 有什么特别的原因吗?

英文:

This mistake is:

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

Because self is a value that is out of date when this struct is re-init. Fix like this:

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
       context.coordinator.imageForRecipeBinding = _imageForRecipe
    }

is there a reason you are not using SwiftUI built-in .photosPicker(isPresented:)?

huangapple
  • 本文由 发表于 2023年4月20日 05:03:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76058786.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定