Issue with Codable and nested structs

Just hit a problem I don’t understand…

Working with:

struct SightingList {
var listRegion: ListRegion?
private var name: String?
//number of other properties

struct ListRegion {
public var centre: CLLocationCoordinate2D
public var radius: Int
public var locationName: String

I’m trying to encode SightingList via Encodable and a JSONDecoder. I’ve extended CLLocationCoordinate2D to make it Codable, and can encode/decode both CLLocationCoordinate2D and ListRegion instances.

However when I extend SightingList to Codable (I need to do this manually as there are properties such as closures I don’t want to encode in there) as below it doesn’t work.

extension SightingList: Encodable {

enum CodingKeys: String, CodingKey {
case name
case region

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(_name, forKey: .name)
try container.encode(listRegion, forKey: .region)

I get the compiler error: Reference to member ‘region’ cannot be resolved without a contextual type. Substituting another property for listRegion in the encode(forKey:) fixes the problem, so it must be something to do with the nature of listRegion.

I can work round this by ‘flattening’ the listRegion struct in encode(to:) but I’d like to understand why I get the error, and ideally how to avoid it. The only time I’ve seen this sort of error before is working with underlying ObjC types/libraries that expect an AnyObject (which obviously a struct isn’t). As I understand Codable should cope with the above data structure as it can cope with structs and can encode a top level as long as it can encode the child properties.

Any ideas?

Perhaps :slight_smile:

An Apple documentation example :

struct Landmark: Codable {
var name: String
var foundingYear: Int
var location: Coordinate
var vantagePoints: [Coordinate]

enum CodingKeys: String, CodingKey {
    case name = "title"
    case foundingYear = "founding_date"
    case location
    case vantagePoints


Good thought, but not the answer in this case unfortunately. If I was relying on the default Encodable serialisation that would be needed to connect the two different version of the field name, but as I’m explicitly linking the two in my custom encode(forKey:) it doesn’t solve it here. (I did give it a go just to make sure though, and no joy).

OK, I’m stupid :slight_smile:

I’ve just gone back and looked at it again in the cold light of the next day and realised my obvious mistake. Somewhere in playing around with it I’d managed to delete the protocol adoption of Codable from where I declared the ListRegion type.

Put that back, and guess what? It all works! The error message could have been more helpful though. Maybe something like “type doesn’t conform to codable”?!

Apologies for wasting everyone’s time!

@flanker Thank you for providing an update! Glad you were able to fix the error message. Happy coding!

This topic was automatically closed after 166 days. New replies are no longer allowed.