0

First an information: I am actually on the way learning swiftUI, I'm a total newbie. For my first project i decided to create a small app that loads articles from a joomla website. My API will respond to a query in the following structure:

{
"source": "my AppConnector for Joomla!",
"offset": 0,
"count": 0,
"results": [
    {
        "id": "8",
        "title": "Article 1",
        ...
    },
    {
        "id": "8",
        "title": "Article 2",
        ...
    }
]

}

In the future the API will return more complex structures but actually i'm struggling already with that one. All swiftUI examples & videos i've found are just explaining how to retreive an array of items or are to old and shows depreacet code examples (with the one-dimensional examples i have already successfully created a list view of items but that's not what i want).

I've created the following structs:

struct Welcome: Codable {
    let source: String
    let offset, count: Int
    let results: [Result]
}


// MARK: - Result
struct Result: Codable {
    let id, title, alias, introtext: String
    let fulltext, state, catid, created: String
    let createdBy, createdByAlias, modified, modifiedBy: String
    let checkedOut, checkedOutTime, publishUp, publishDown: String
    let images, urls, attribs, version: String
    let ordering, metakey, metadesc, access: String
    let hits, metadata, featured, language: String
    let xreference, note, slug, articleID: String
    let introImage, fullImage: String
}

and the following fetcher:

import Foundation
import SwiftUI
import Combine


public class ArticlesFetcher: ObservableObject {
    @Published var articles = [Welcome]()
    
    init(){
        load()
    }
    
    func load() {
        let url = URL(string: "https://nx-productions.ch/index.php/news")! //This is a public demo url feel free to check the jsondata (SecurityToken temporary disabled)
    
        URLSession.shared.dataTask(with: url) {(data,response,error) in
            do {
                if let d = data {
                    let decodedLists = try JSONDecoder().decode([Welcome].self, from: d)
                    DispatchQueue.main.async {
                        self.articles = decodedLists
                    }
                }else {
                    print("No Data")
                }
            } catch {
                print ("Error")
            }
            
        }.resume()
         
    }
}

My view looks like this:

struct ContentView: View {

    @ObservedObject var fetcher = ArticlesFetcher()
    
    var body: some View {
        VStack {
            List(fetcher.articles.results) { article in
                VStack (alignment: .leading) {
                    Text(article.title)
                    Text(article.articleId)
                        .font(.system(size: 11))
                        .foregroundColor(Color.gray)
                }
            }
        }
    }
}

What i don't understand is the view part - i am not able to point into the fields, with the example above i get compiler errors like "Value of type '[Welcome]' has no member 'results'" or "Value of type 'Int' has no member 'title'"

I think i may just not understand something aboutmy structure or how to loop through it. Thanks for any advise.

1
  • .articles property is [Welcome] - i.e. an array of Welcome types. An array doesn't have a property .results. Each element of that array, which is a Welcome object, has the .results property. So you either need a double loop or revisit the design of your ArticlesFetcher class Commented Jun 30, 2020 at 14:55

1 Answer 1

1

The JSON starts with a { so it's a dictionary. And the type of articles is wrong.

Replace

@Published var articles = [Welcome]()

with

@Published var articles = [Result]()

and replace

let decodedLists = try JSONDecoder().decode([Welcome].self, from: d)
DispatchQueue.main.async {
   self.articles = decodedLists
}

with

let decodedLists = try JSONDecoder().decode(Welcome.self, from: d)
DispatchQueue.main.async {
   self.articles = decodedLists.results
}

Finally but not related replace meaningless

print ("Error")

with

print(error)
Sign up to request clarification or add additional context in comments.

1 Comment

Nice! Thanks a lot! I had also to adapt some changes to my view: struct ContentView: View { @ObservedObject var fetcher = ArticlesFetcher() var body: some View { VStack { List(fetcher.articles) { article in VStack (alignment: .leading) { Text(article.title) Text(article.articleID) .font(.system(size: 11)) .foregroundColor(Color.gray) } } } } } and it works now, thank you!

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.