Search code examples
iosswiftswiftuiwordpress-rest-api

StringProtocol issue when decoding Wordpress API value in SwiftUI


I have the exact same issue as stated here: Wordpress REST API + Swift

But the accepted answer is not working for me.

My code to retrieve the Wordpress Posts API:

import SwiftUI

struct Rendered: Codable {
     var rendered: String
}

struct Post: Codable, Identifiable {
    var id: Int
    var title: Rendered
}

class Api {
    func getPosts(completion: @escaping ([Post]) -> ()) {
        
        guard let url = URL(string: "https://9fc9d65.ngrok.io/wp-json/wp/v2/posts") else { return }

        URLSession.shared.dataTask(with: url) { (data, _, _) in

            let posts = try! JSONDecoder().decode([Post].self, from: data!)

            DispatchQueue.main.async {
                completion(posts)
            }
        }
        .resume() //resume session call
    }
}

Example JSON response:

[
    {
        "id": 7,
        "title": {
            "rendered": "Example Title"
        }
    }
]

And where I'm rendering the API results as a List:

import SwiftUI

struct PostList: View {
    
    @State var posts: [Post] = []
    
    var body: some View {
        List(posts) { post in
            Text(post.title)
        }
        .onAppear {
            Api().getPosts { (posts) in
                self.posts = posts
            }
        }
    }
}

struct PostList_Previews: PreviewProvider {
    static var previews: some View {
        PostList()
    }
}

This line within List() is where I'm trying to access the decoded title is where I'm receiving the error:

Text(post.title)

Error I'm getting:

Initializer 'init(_:)' requires that 'Rendered' conform to 'StringProtocol'


Solution

  • Your model is defined like this:

    struct Rendered: Codable {
         var rendered: String
    }
    
    struct Post: Codable, Identifiable {
        var id: Int
        var title: Rendered
    }
    

    Which means that title is of the type Rendered which is not a String itself, but rather a struct with a sub protocol called rendered.

    So, my suspicion is that you just need to change your line:

    Text(post.title)
    

    to:

    Text(post.title.rendered)
    

    (This is making an assumption that you aren't seeing errors in the JSON decoding process)