onAppear не отображает элементы интерфейса - PullRequest
0 голосов
/ 07 марта 2020

Итак, у меня возникла странная проблема, когда в моем стеке просмотра .onAppear запускает мою функцию для извлечения данных с моего сервера, но не может отображать элементы карты, которые я создал для интерфейса. То, чего я пытаюсь добиться, - это когда пользователь открывает приложение и выводит его на панель инструментов, на нем отображаются различные заголовки платформы. Я не получаю никаких ошибок, так как объект JSON читается правильно.

Некоторые вещи, которые я прочитал, это то, что представление может нуждаться в обновлении после вызова .onAppear, но у меня есть ресурсы нашел не очень объяснил как это сделать. Первый бит кода - мой JSON объект:

{"results" : [{"id":1,"title":"Meet ergoWare","header_image":"http://gba.ergoware.io/cache/content/topstory/ergo_news_01.svg","summary":"GBA's New Ergonomic Portal!"}]}

, который извлекается через эту функцию

func loadHeadlines(CDNLink: String) {
    guard let url = URL(string: CDNLink) else {
        print("Invalid URL")
        return
    }

    let request = URLRequest(url: url)

    URLSession.shared.dataTask(with: request) { data, response, error in
        if error != nil {
            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
            return
        } else {
            do {
                let decodedResponse = try JSONDecoder().decode(Response.self, from: data!)
                    print(decodedResponse)
                self.results = decodedResponse.results
                } catch let err {
                    print("Error parsing: \(err)")

                }
            }
        }.resume()
    }

Затем добавляется тег .onAppear к моему HStack, он преформирует функцию и запускает мой оператор ForEach следующим образом:

ScrollView(showsIndicators: false){
                Text("HEADLINES")
                    .font(.system(size: 18))
                    .fontWeight(.medium)
                    .foregroundColor(.secondary)
                    .frame(maxWidth: .infinity, alignment: .leading)
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack {
                        ForEach(results) { result in
                            CardView(image: result.header_image, heading: result.title, summary: result.summary)
                        }
                    }.onAppear(perform:{self.loadHeadlines(CDNLink: "http://\(self.defaults.object(forKey: "domain") as! String)/cdn?funct=fetchNews")})
                }

Итак, мой вопрос: почему CardView не отображается при загрузке сцены? С помощью симулятора, если я собираю и тестирую приложение, затем выключаю его и возвращаюсь, карты начинают отображаться. Спасибо за любую информацию, которую вы можете предоставить. Ниже у меня есть несколько ссылок на мой полный код.

Вид панели инструментов CardView

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Просто чтобы прояснить разницу между init и onAppear () (согласно комментариям)

Давайте представим, что у вас есть TabView с двумя представлениями. Первое представление - это представление, которое вы создали и предоставили код, второе представление может быть представлением профиля. Функция onAppear () будет вызываться каждый раз, когда пользователь переключается между этими двумя TabView, в то время как функция init () будет запускаться только один раз в этом конкретном случае использования.

Далее, важно отметить, что URLSession работает в фоновом режиме нить. Вы можете обновлять представления только из MainThread, что означает, что вы должны инкапсулировать результат в:

DispatchQueue.main.async {
    self.results = decodedResponse.results
}

Но точный ответ на ваш вопрос

Я только что столкнулся тот же вопрос несколько дней go. В данный момент ScrollView имеет некоторую ошибку / функцию, которая означает, что если вы попытаетесь ScrollView + ForEach для пустого массива, который будет обновлен позже, он не будет отображаться. Если в качестве первого элемента вы дадите жестко запрограммированную статью, а остальные обновите позже, она будет работать. Atleast для меня работал под swift5 xcode 11.3.1 на iOS 13.3.1. Однако я использую ObservableObject для обработки данных в классе и ObservedObject, чтобы воспользоваться модификатором @Published. Вот так

class Result : ObservableObject{
    @Published var results = [Article]()
}

И запишите это в свой код swiftUI:

@ObservedObject private var data = Result()

Ваша функция инициализации swiftui должна содержать такую ​​же функцию добавления, чтобы обойти ошибку / функцию ScrollView:

init() {
    self.data.results.append(....)
    self.callYourRestAPIHere(URL:"whateverhere", result: data)
}

Надеюсь, я ничего не пропустил, но я готов улучшить свой Ответ, если я это сделал.

1 голос
/ 08 марта 2020

Я думаю, вы должны идентифицировать данные в ForEach l oop, чтобы SwiftUI мог различать guish различных элементов данных и мог правильно видеть, изменилось ли содержимое массива. Как это:

ForEach(results, id: \.id) { result in
    CardView(image: result.header_image, heading: result.title, summary: result.summary)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...