0

Parsed JSON. Now I'm trying to display all this in a view.

But getting an error

Cannot find 'newsFeed' in scope

Here is my code

--- PostsController.swift ---

import Foundation

struct NewsFeed: Codable {
    var status:String = ""
    var totalResults:Int = 0
    var posts:[PostItem]
}

struct PostItem: Codable {
    var id:Int
    var title:String
    var link:String
    var date:String
    var category:String
    var thumbnail:String
    var excerpt:String
    var content:String
}

--- AppSwiftUIApp.swift ---

import SwiftUI

@main struct AppSwiftUIApp: App {

    init() {

        let urlString = "/json_news.json"
        let url = URL(string: urlString)

        guard url != nil else {
            return
        }

        let session = URLSession.shared
        let dataTask = session.dataTask(with: url!) { (data, response, error) in

            if error == nil && data != nil {
                let decoder = JSONDecoder()
                do {
                    let newsFeed = try decoder.decode(NewsFeed.self, from: data!)
                    print(newsFeed.posts)
                } catch {
                    print("Error: \(error)")
                }
            }

        }

        dataTask.resume()

    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }

}

--- MainPageView.swift ---

import SwiftUI

struct MainPageView: View {
    
    var body: some View {

        HeaderView()

        ScrollView(.vertical, showsIndicators: true) {

            VStack() {

                ForEach(newsFeed.posts) { post in

                    VStack(alignment: .leading) {

                        Image(post.thumbnail)
                            .resizable()
                            .aspectRatio(contentMode: .fit)

                    }

                }

            }
            .padding(10)
            .navigationBarHidden(true)
            .navigationBarBackButtonHidden(true)

        }

        FooterView()

    }
    
}

How I can pass a variable to a loop in a view so that I can use it?

1
  • Can you show this in code, please? Commented Mar 10, 2021 at 10:51

1 Answer 1

1

Perform the json decoding in a class that conforms to ObservableObject and assign the result of the decoding to a @Published property

class NewsDecoder: ObservableObject {
    @Published var newsFeed: NewsFeed?

    init() {
        let urlString = "/json_news.json"
        let url = URL(string: urlString)

        guard url != nil else { return }

        let session = URLSession.shared
        let dataTask = session.dataTask(with: url!) { (data, response, error) in
            if error == nil && data != nil {
                let decoder = JSONDecoder()
                do {
                    self.newsFeed = try decoder.decode(NewsFeed.self, from: data!)
                } catch {
                    print("Error: \(error)")
                }
            }
        }

        dataTask.resume()
    }
}

Then create an instance of that class in your view as an @ObservedObject and use the property in your ForEach

struct MainPageView: View {
    @ObservedObject var newsDecoder = NewsDecoder()

and access the data via newsDecoder.newsFeed

struct ContentView: View {
    @ObservedObject var newsDecoder = NewsDecoder()
    var body: some View {
        ForEach(newsDecoder.newsFeed?.posts ?? [], id: \.id) { feed in
            Text(feed.title)
        }
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

I have a new error "Referencing initializer 'init(_:content:)' on 'ForEach' requires that 'PostItem' conform to 'Identifiable'" when using foreach loop "ForEach(newsDecoder.newsFeed.posts) { post in"
This is easily solved by doing some research but you should be able to solve this by adding id: \.id to the ForEach header, please do not add more questions to your original question in the future
Sorry for more questions, but I new in Swift.. I steel have errors. What I need to do? Create new question?
@LexXy I added a short sample view code to my answer, if you still have some issue then yes you should ask a new question for that issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.