How to Specify Classes When Writing to PropertyList Using the Codable Protocol

Asked 2 years ago, Updated 2 years ago, 123 views

I would like to create classes and subclasses that conform to Swift's Codable protocol and write and load a mixed array in PropertyList, but it seems that I cannot determine the class.

We have created an Animal class as a sample and added Dog as a subclass.Originally, several subclasses, such as Cat and Monkey, should be created.

 var animals: Animal

animals.append(Dog())
animals.append(Cat())

The purpose is to save animas as a PropertyList by adding and so on.

Encoding is

let data=try PropertyListEncoder().encode(animals)

In , decode

let animals2=try PropertyListDecoder().decode([Animal].self, from:data)

Yes, maybe because it's Animal.self, Animal will be restored instead of Dog or Cat.

Is there something wrong with writing?

This is a sample that can be tested in Playground.

import UIKit


class Animal:Codable {
    varlegCount—Int

    init(){
        legCount = 4
    }
}

class Dog:Animal {
    var name: String="(NO NAME)"

    override init() {
        super.init()
    }

    private enum codingKey: String, codingKey {
        case name
    }

    required init (from decoder: Decoder) flows {
        try super.init (from:decoder)
        let container = try decoder.container(keyedBy:CodingKeys.self)
        name = try container.decode(String.self, forKey:.name)
    }

    override funcencode (to encoder) flows {
        try super.encode (to:encoder)

        var container=encoder.container(keyedBy:CodingKeys.self)
        try container.encode (name, forKey:.name)
    }
}

let dog = Dog()
dog.name = "John"

let animals: Animal = [dog]

let data=try PropertyListEncoder().encode(animals)
let animals2 = try PropertyListDecoder().decode([Animal].self, from:data)
let a=animals2.first!as?Dog
print(a?.name)

Normally, John should be displayed at the end, but a is nil.

Thank you for your cooperation.

swift ios macos

2022-09-30 21:37

1 Answers

let animals2=try PropertyListDecoder().decode([Animal].self, from:data)

Decode the lines in Array<Animal> to an array of subclasses in Animal, right?
For classes (instances) such as Dog, Cat, what class does the Animal class inherit?is unknown.

In addition, decode([Animal].self, so init(from decoder) is called init(from decoder) in the animal class, not init(from decoder) in each inherited class.
Therefore, there is no name property because the array animals2 becomes an array of instances of the Animal class and is no longer an instance of the Dog class.
said he.

So the solution is that the last class of inheritance is a single class, and the instance of that class has the dog or cat attributes

enum Species {
    case dog
    case cat
      // hereinafter abbreviated
}

class Animal:Codable {
    varspecies —Species
    var name —String

    init(_species:Species, name:String="(NO NAME)"){
        self.species=species
        self.name = name
    }
}

and so on.

let dog = Animal (.dog)

So, I think it is necessary to generate instances of each species as to encode/decode property lists.


2022-09-30 21:37

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.