skip to Main Content

I am created a swiftui app but for test purpose, I have a create a mocked repo to return the data from a json instead of placing an api call. The result of the JSONDecode is always nil…

the Json is as below and stored at the root project like the google.plist, ContentView and so on.

[
    {
        "ts": 1000000,
        "id": 1,
        "userName": "honeybee",
        "userLocation": "Honey bee",
        "userImageUrl": "user_1",
        "title": "Here",
        "postType": "post",
        "postImageUrl": "food_1",
    },
    {
        "ts": 1000000,
        "id": 2,
        "userName": "honeybee",
        "userLocation": "Honey bee",
        "userImageUrl": "user_2",
        "title": "Here",
        "postType": "store",
        "postImageUrl": "food_2"
    },

I created a model FeedItemEntity as below:

enum PostType: String, Codable {
    case Post =  "post"
    case Store = "store"
    case Restaurant = "restaurant"
    case Review = "review"
    case Recipe = "recipe"
}

struct FeedItemEntity: Codable {
    var ts: Int
    var userName: String
    var userLocation: String
    var userImageUrl: String
    var title: String
    var postImageUrl: String
    var postType: PostType
    var rating: Int
}

extension FeedItemEntity: Identifiable {
    var id: UUID {
        let id = UUID()
        return id
    }
}

and then my code is doing this:

class MockedFeedService: FeedServiceProtocol {
    
    static let shared = MockedFeedService()

    
    func getFeed() -> Future<[ios_foodloose_app.FeedItemEntity], Error> {
        return Future<[FeedItemEntity], Error> { promise in
            
            guard let url = Bundle(for: MockedFeedService.self).url(forResource: "basic-test-feed-response",withExtension: "json"),
                  let data = try? Data(contentsOf: url) else {
                return promise(.failure(NSError(domain: "", code: 401, userInfo: [ NSLocalizedDescriptionKey: "Error"])))
            }
            
            let response = try? JSONDecoder().decode( [FeedItemEntity].self, from: data)
            promise(.success(response!))
        }
    }
    
} 

in my case response is always nil

Any idea why ?

Thanks

2

Answers


  1. Your JSON file doesn’t contain a rating field.

    You can update your basic-test-feed-response.json by either adding a rating field to all items of the array or make the optional rating field in the FeedItemEntity model like this:

    struct FeedItemEntity: Codable {
        var ts: Int
        var userName: String
        var userLocation: String
        var userImageUrl: String
        var title: String
        var postImageUrl: String
        var postType: PostType
        var rating: Int?
    }
    

    You can use do-catch mechanism to obtain a description of what went wrong:

    do {
        let response = try JSONDecoder().decode([FeedItemEntity].self, from: data)
        promise(.success(response))
    } catch {
        print(error)
    }
    

    In Xcode console, you will see:

    keyNotFound(CodingKeys(stringValue: "rating", intValue: nil),
    Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index
    0", intValue: 0)], debugDescription: "No value associated with key
    CodingKeys(stringValue: "rating", intValue: nil) ("rating").",
    underlyingError: nil))

    Login or Signup to reply.
  2. This will work, I made some adjustment in JSON and Decoder. Please modify it as per your need.

    import Foundation
    
    let json = """
    [
        {
            "ts": 1000000,
            "id": 1,
            "userName": "honeybee",
            "userLocation": "Honey bee",
            "userImageUrl": "user_1",
            "title": "Here",
            "postType": "post",
            "postImageUrl": "food_1"
        },
        {
            "ts": 1000000,
            "id": 2,
            "userName": "honeybee",
            "userLocation": "Honey bee",
            "userImageUrl": "user_2",
            "title": "Here",
            "postType": "store",
            "postImageUrl": "food_2"
        }
    ]
    """.data(using: .utf8)!
    print (json)
    
    enum PostType: String, Codable {
        case Post =  "post"
        case Store = "store"
        case Restaurant = "restaurant"
        case Review = "review"
        case Recipe = "recipe"
    }
    
    struct FeedItemEntity: Codable {
        var ts: Int
        var userName: String
        var userLocation: String
        var userImageUrl: String
        var title: String
        var postImageUrl: String
        var postType: PostType
    }
    
    extension FeedItemEntity: Identifiable {
        var id: String {
            let id = UUID().uuidString
            return id
        }
    }
    
    // create a JSON decoder
    let decoder = JSONDecoder()
    
    // decode the JSON into your model object and print the result
    do {
        let feed = try decoder.decode([FeedItemEntity].self, from: json)
        print(feed)
    } catch {
        print(error)
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search