当前位置: 首页 > 知识库问答 >
问题:

WebImage未更新视图-SwiftUI(Xcode 12)

凌照
2023-03-14

我的问题是,当我将observed objects string属性更改为另一个值时,它会更新JSON映像值(使用Unsplash API),打印出更新的值,但WebImage(来自SDWebImagesWiFTUI)不会更改。

结果应用于得结构:

struct Results : Codable {
    var total : Int
    var results : [Result]
}

struct Result : Codable {
    var id : String
    var description : String?
    var urls : URLs
}

struct URLs : Codable {
    var small : String
}

下面是包含要更新的webImage的视图:

struct MoodboardView: View {
    @ObservedObject var searchObjectController = SearchObjectController.shared
    
    var body: some View {
        
        List {
            VStack {
                Text("Mood Board: \(searchObjectController.searchText)")
                    .fontWeight(.bold)
                    .padding(6)
                ForEach(searchObjectController.results, id: \.id, content: { result in
                    Text(result.description ?? "Empty")
                    WebImage(url: URL(string: result.urls.small) )
                        .resizable()
                        .frame(height:300)
                    })
                }.onAppear() {
                searchObjectController.search()
            }
            
        }
    }
}   

下面是执行API请求的类:

class SearchObjectController : ObservableObject {
    static let shared = SearchObjectController()
    private init() {}
    
    var token = "gQR-YsX0OpwkYpbjhPVi3b4kSR-DtWrR5phwDm2kPMM"
    @Published var results = [Result]()
    @Published var searchText : String = "forest"
    
    func search () {
        let url = URL(string: "https://api.unsplash.com/search/photos?query=\(searchText)")
        var request = URLRequest(url: url!)
        request.httpMethod = "GET"
        request.setValue("Client-ID \(token)", forHTTPHeaderField: "Authorization")
        print("request: \(request)")
        
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            guard let data = data else {return}
            print(String(data: data, encoding: .utf8)!)

            do {
                let res = try JSONDecoder().decode(Results.self, from: data)
                DispatchQueue.main.async {
                    self.results.append(contentsOf: res.results)
                }
                //print(self.results)
            } catch {
                print("catch: \(error)")
            }
        }
        task.resume()
    }
}

下面是我如何在一个按钮中更改searchText的值,如果你想看的话:

struct GenerateView: View {
    
    @ObservedObject var searchObjectController = SearchObjectController.shared
    
    @State private var celsius: Double = 0
    
    var body: some View {
        ZStack {
            Color.purple
                .ignoresSafeArea()
            VStack{
                
                Text("Generate a Random Idea")
                    .padding()
                    .foregroundColor(.white)
                    .font(.largeTitle)
                    .frame(maxWidth: .infinity, alignment: .center)
                    
                Image("placeholder")
                Slider(value: $celsius, in: -100...100)
                    .padding()
                Button("Generate") {
                    print("topic changed to\(searchObjectController.searchText)")
                    
                    searchObjectController.searchText.self = "tables"
                }
                Spacer()
            }
        }
    }
}

共有1个答案

丁星火
2023-03-14

结果是您更新了搜索文本,但没有再次搜索。看这就有窍门了:

Button("Generate") {
    print("topic changed to\(searchObjectController.searchText)")

    searchObjectController.searchText.self = "tables" // you changed the search text but didnt search again
    self.searchObjectController.search() // adding this does the trick
}

还有。我更新了您的代码以使用EnvironmentObject。如果您在整个应用程序中使用一个对象的实例。考虑让它成为environmentObject,这样就不必一直传递它。

添加它很容易。将其添加到@main场景中

快速导入TUI

@main
struct StackoverflowApp: App {
    
    @ObservedObject var searchObjectController = SearchObjectController()
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(self.searchObjectController)
        }
    }
}

而且使用起来更简单:

struct MoodboardView: View {
    
    // Env Obj. so we reference only one object
    @EnvironmentObject var searchObjectController: SearchObjectController

    var body: some View {
        
        Text("")
    }
}

下面是您的代码,它与所做的更改和预期的工作一样:我在所做的更改中添加了注释


struct ContentView: View {
    
    var body: some View {
        MoodboardView()
    }
}

struct GenerateView: View {

    @EnvironmentObject var searchObjectController: SearchObjectController

    @State private var celsius: Double = 0

    var body: some View {
        ZStack {
            Color.purple
                .ignoresSafeArea()
            VStack{
                
                Text("Generate a Random Idea")
                    .padding()
                    .foregroundColor(.white)
                    .font(.largeTitle)
                    .frame(maxWidth: .infinity, alignment: .center)
                    
                Image("placeholder")
                Slider(value: $celsius, in: -100...100)
                    .padding()
                Button("Generate") {
                    print("topic changed to\(searchObjectController.searchText)")
                    
                    searchObjectController.searchText.self = "tables" // you changed the search text but didnt search again
                    self.searchObjectController.search() // adding this does the trick
                    
                }
                Spacer()
            }
        }
    }

}

class SearchObjectController : ObservableObject {
    
    //static let shared = SearchObjectController() // Delete this. We want one Object of this class in the entire app.
     
    //private init() {} // Delete this. Empty Init is not needed

    var token = "gQR-YsX0OpwkYpbjhPVi3b4kSR-DtWrR5phwDm2kPMM"
    @Published var results = [Result]()
    @Published var searchText : String = "forest"

    func search () {
        let url = URL(string: "https://api.unsplash.com/search/photos?query=\(searchText)")
        var request = URLRequest(url: url!)
        request.httpMethod = "GET"
        request.setValue("Client-ID \(token)", forHTTPHeaderField: "Authorization")
        print("request: \(request)")
        
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            guard let data = data else {return}
            print(String(data: data, encoding: .utf8)!)

            do {
                let res = try JSONDecoder().decode(Results.self, from: data)
                DispatchQueue.main.async {
                    self.results.append(contentsOf: res.results)
                }
                //print(self.results)
            } catch {
                print("catch: \(error)")
            }
        }
        task.resume()
    }
}

struct MoodboardView: View {
    
    // Env Obj. so we reference only one object
    @EnvironmentObject var searchObjectController: SearchObjectController

    var body: some View {
        
        List {
            VStack {
                Text("Mood Board: \(searchObjectController.searchText)")
                    .fontWeight(.bold)
                    .padding(6)
                ForEach(searchObjectController.results, id: \.id, content: { result in
                    Text(result.description ?? "Empty")
                    WebImage(url: URL(string: result.urls.small) )
                        .resizable()
                        .frame(height:300)
                    })
                }.onAppear() {
                searchObjectController.search()
            }
            
            // I added your update button here so I can use it.
            GenerateView()
        }
    }
}

struct Results : Codable {
    var total : Int
    var results : [Result]
}

struct Result : Codable {
    var id : String
    var description : String?
    var urls : URLs
}

struct URLs : Codable {
    var small : String
}

ps.请不要在搜索时出现,只需将结果追加到数组中,而不要删除旧的。这就是为什么更新后仍然会看到第一个图像的原因。新的只是被附加在底部。向下滚动查看它们。如果您不想这样做,只需在search上用结果清空数组即可

 类似资料:
  • 我有一个以3x4矩阵排列的GridView,GridView中的每一项都是一个包含ImageView和Textview的FrameLayout。最初,文本视图被设置为显示字母“X”。点击后,字母变成“Y”。 它适用于除第一项之外的所有GridView项。如果我点击第一个(左上角),那么无论我等待多长时间,都不会发生任何事情。如果我点击Android模拟器屏幕上的任何其他地方(甚至在GridView

  • 问题内容: 使用FetchRequest包装器,并在视图内部更改获取结果的数据。该功能在视图首次加载时起作用,该视图随所做的每个更改而更新。 问题是,如果我离开视图导航并再次返回,则获取请求数据的更改将停止刷新视图。查看更改的唯一方法是导航并再次返回。 我正在打印获取请求,并且对数据所做的更改正在起作用,这说明了为什么如果我再次导航回去,视图将正确显示,但是当视图上的数据更改时,视图没有刷新。 这

  • 问题内容: 在事件回调中更新模型时,更新模型属性对视图没有影响,是否有任何解决办法? 这是我的服务: 功能已在控制器中动态添加。 控制器: 视图: 因此,问题在于单击按钮会正确更新视图,但是当我从Channel收到消息时,什么也没发生,即使该函数被调用 问题答案: 你失踪了。 每当您从Angular世界外部触摸任何东西时,都需要调用,以通知Angular。可能来自: xhr回调(由$ http服务

  • 问题内容: 我试图弄清楚Angular的工作原理,并在模型更改时无法更新视图。 的HTML JS http://jsfiddle.net/N2G7z/ 有任何想法吗? 问题答案: 正如上面提到的Ajay beniwal一样,您需要使用Apply来开始消化。

  • 我对中的有一个问题。 下面是我的代码: 问题:在中按下时,会像它应该的那样消失,取而代之。但是,并不会消失,而是停留在视图B的顶部。 当更改为时,如何强制关闭?请注意,也可以由以外的其他视图更改,因此只将传递给并在单击时将其设置为false并不能完成此工作。

  • 我开始尝试,我感到惊讶的是,更改