英文:
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:
-
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?
. -
Ensure that the
imageCache
for each instance ofUrlImageModel
is independent and not shared between the two sections. -
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:)
?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论