简体   繁体   中英

My View keeps rendering over and over in SwiftUI

Here is my view:

struct EditProfile: View {
    @State var bio = UserDefaults.standard.string(forKey: "bio") ?? "Edit your bio"
    @ObservedObject var storage = FirebaseStorage()
    @State var text = ""
    let photos = ["img1", "img2", "img3"]
    var body: some View {
        VStack {
            Text("Photos")
            .font(Font.system(size: 21))
            .fontWeight(.bold)
            HStack {
                ForEach(photos, id: \.self){ img in
                    EditableCircleImage(kfImage: self.storage.makeCircleImage(str: img))
                }
            }
            .background(
                RoundedRectangle(cornerRadius: 10)
                    .fill(Color.white)
                    .shadow(color: .gray, radius: 1, x: 0, y: 1)
            )

            Text("Bio")
                .font(Font.system(size: 21))
                .fontWeight(.bold)
            MultiTextField(txt: $text)
                .padding(10)
                .cornerRadius(20.0)
                .background(
                    RoundedRectangle(cornerRadius: 10)
                        .fill(Color.white)
                        .shadow(color: .gray, radius: 1, x: 0, y: 1)
                )
                .border(Color.gray.opacity(0.5), width: 1)

        }.padding(20).background(Color.gray.opacity(0.1))
    }
}

Here is the EditableCircleImage() :

struct EditableCircleImage: View {
    let kfImage: KFImage
    var body: some View {
        ZStack {
            kfImage
                .resizable()
            .scaledToFit()
            .frame(height: 200)
                .clipShape(Circle())
                .overlay(Circle().stroke(Color.orange, lineWidth: 2))
            Button(action: {}){
                Image(systemName: "pencil.circle.fill")
                    .resizable()
                    .scaledToFit()
                    .frame(height: 40)
                .foregroundColor(.gray)

            }.offset(x: 40, y: 50)
        }
    }
}

Here is the model which returns the image: FirebaseStorage.swift :

class FirebaseStorage: ObservableObject {
    let storage = Storage.storage()
    let uid = UserAuth().uid ?? "<uid>"
    @Published var img1 = UserDefaults.standard.string(forKey: "img1") ?? "<img1>"

    func makeCircleImage(str: String) -> KFImage {
        if let url = UserDefaults.standard.string(forKey: str) {
            print("not nil: \(str)")
            return KFImage(URL(string: "http://app-23c8s.appspot.com.storage.googleapis.com/users/\(uid)/\(url)"))
        }
        else {
            print("is nil: \(str)")
            return KFImage(source: nil)
        }

    }
}

The print statements in the model above print over and over, even though no values have changed after the initial render. Any idea why?

Constantly prints:

not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3
not nil: img1
is nil: img2
is nil: img3

UPDATE:

I changed:

ForEach(photos, id: \.self){ img in
    EditableCircleImage(kfImage: self.storage.makeCircleImage(str: img))
}

to

EditableCircleImage(kfImage: self.storage.makeCircleImage(str: "img1"))

and now it prints:

not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1
not nil: img1

Remove conformance of FirebaseStorage class to ObservableObject and remove the property wrapper @ObservedObject from @ObservedObject var storage = FirebaseStorage() . Remove @Published property wrapper too. Run it and let me know if the issue persists. By the way it is unclear to me as to why you have made the class conform to ObservableObject and why you have used the property wrapper in this specific use case. If I am missing something, do let me know. Assumed that this post includes the entire code for the problem you are talking about. Hopefully this helps you out.

It seems that

func makeCircleImage(str: String) -> KFImage { ... }

is an asynchronous function, in particular KFImage(..). You use this in:

ForEach(photos, id: \.self){ img in
     EditableCircleImage(kfImage: self.storage.makeCircleImage(str: img))
}

This is probably the source of the problem. You really should wait until you have all you images before using them, especially in a View.

Changing my code to this:

struct EditProfile: View {
    @State var bio = UserDefaults.standard.string(forKey: "bio") ?? "Edit your bio"
    @ObservedObject var storage = Storages()
    @State var text = ""
    let uid = UserAuth().uid ?? "<uid>"
    let photos: [String:String] = [
        "img1": UserDefaults.standard.string(forKey: "img1") ?? "",
        "img2": UserDefaults.standard.string(forKey: "img2") ?? "",
        "img3": UserDefaults.standard.string(forKey: "img3") ?? "",
    ]
    var body: some View {
        VStack {
            Text("Points")
            .font(Font.system(size: 21))
            .fontWeight(.bold)
            HStack {
                ForEach(photos.sorted(by: <), id: \.key){ (key,val) in
                    EditableCircleImage(
                        kfImage: KFImage(
                            URL(string: "http://app-23c8s.appspot.com.storage.googleapis.com/users/\(self.uid)/\(val)")
                        ),
                        key: key
                    )
                }
            }

struct EditableCircleImage: View {
    let kfImage: KFImage
    let key: String
    var body: some View {
        ZStack {
            kfImage

fixed the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM