Почему этот SwiftUI View не обновляется при изменении переменной @State? - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть SwiftUI View, который принимает Hacker News API идентификатор отправки, а затем извлекает детали для этого элемента в fetchStory().

Когда fetchStory() завершил его HTTP-вызов обновляет @State private var url в представлении, однако представление никогда не выполняет повторное рендеринг для отображения нового значения - оно всегда показывает начальное пустое значение.

Почему?

import Foundation
import SwiftUI

struct StoryItem: Decodable {
    let title: String
    let url: String?
}

struct StoryView: View {
    public var _storyId: Int

    @State private var url: String = "";

    init(storyId: Int) {
        self._storyId = storyId
        self.fetchStory()
    }

    var body: some View {
        VStack {
            Text("(Load a webview here for the URL of Story #\(self._storyId))")
            Text("URL is: \(self.url)") // this never changes!
        }
    }

    private func fetchStory() {
        let url = URL(string: "https://hacker-news.firebaseio.com/v0/item/\(self._storyId).json")!

        let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
            guard let data = data else {
                print(String(error.debugDescription))
                return
            }

            do {
                let item: StoryItem = try JSONDecoder().decode(StoryItem.self, from: data)

                if let storyUrl = item.url {
                    self.url = storyUrl
                } else {
                    print("No url")
                }
            } catch {
                print(error)
            }
        }

        task.resume()
    }
}

struct StoryView_Previews: PreviewProvider {
    static var previews: some View {
        StoryView(storyId: 22862053)
    }
}

Ответы [ 2 ]

1 голос
/ 15 апреля 2020

примерно так:

import SwiftUI

struct StoryItem: Decodable {
let title: String
let url: String?
}

class ObservedStoryId: ObservableObject {
@Published var storyId: String = ""
init(storyId: String) {
    self.storyId = storyId
}
}

struct StoryView: View {

@ObservedObject var storyId: ObservedStoryId
@State var url: String = ""

var body: some View {
    VStack {
        Text("(Load a webview here for the URL of Story #\(self.storyId.storyId))")
        Text("URL is: \(self.url)")
        Text(self.storyId.storyId)
    }.onReceive(storyId.$storyId) { _ in self.fetchStory() }
}

private func fetchStory() {
    let url = URL(string: "https://hacker-news.firebaseio.com/v0/item/\(self.storyId.storyId).json")!
    let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
        guard let data = data else {
            print(String(error.debugDescription))
            return
        }
        do {
            let item: StoryItem = try JSONDecoder().decode(StoryItem.self, from: data)
            if let storyUrl = item.url {
                self.url = storyUrl
            } else {
                print("No url")
            }
        } catch {
            print(error)
        }
    }
    task.resume()
}
}

и назовите это так:

struct ContentView: View {

    @ObservedObject var storyId = ObservedStoryId(storyId: "22862053")

    var body: some View {
     StoryView(storyId: storyId)
    }
}
0 голосов
/ 15 апреля 2020

чтобы решить вашу проблему:

init(storyId: Int) {
    self._storyId = storyId
}

var body: some View {
    VStack {
        Text("(Load a webview here for the URL of Story #\(self._storyId))")
        Text("URL is: \(self.url)") // this now works
    }.onAppear(perform: fetchStory)
}

почему это работает, а не ваш код, я думаю, что это: «self.url» может быть обновлен / изменен только в специальных функциях SwiftUI View, таких как как и onAppear (), в другом месте это ничего не меняет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...