BLACK FRIDAY SALE: Save big on all my Swift books and bundles! >>

Project 10 Challenge 3 Wrapping struct in a class

Forums > 100 Days of SwiftUI

My data model is shown below. Not sure why the Order class will not comply with Codable when it only contains a Codable var orderDetail?

class Order: ObservableObject, Codable {
    @Published var orderDetail = OrderDetail()
}

struct OrderDetail: Codable {
    static let types = ["Vanilla", "Strawberry", "Chocolate", "Rainbow"]

     var type = 0
     var quantity = 3
     var name = ""
     var streetAddress = ""
     var city = ""
     var zip = ""

    var hasValidAddress: Bool {
        if name.trimmingCharacters(in: .whitespaces).isEmpty || streetAddress.trimmingCharacters(in: .whitespaces).isEmpty || city.trimmingCharacters(in: .whitespaces).isEmpty || zip.trimmingCharacters(in: .whitespaces).isEmpty {
            return false
        }

        return true
    }

    var cost: Double {
        // $2 per cake
        var cost = Double(quantity) * 2

        // complicated cakes cost more
        cost += (Double(type) / 2)

        // $1/cake for extra frosting
        if extraFrosting {
            cost += Double(quantity)
        }

        // $0.50/cake for sprinkles
        if addSprinkles {
            cost += Double(quantity) / 2
        }

        return cost
    }

     var specialRequestEnabled = false {
        didSet {
            if specialRequestEnabled == false {
                extraFrosting = false
                addSprinkles = false
            }
        }
    }
     var extraFrosting = false
     var addSprinkles = false
}

   

@Bnerd  

Why do you want your Class(Model) to conform to Codable protocol?

   

I was assuming I would need to save the JSON from the class, but now you mention it I guess I can just save and load the OrderDetail var?

   

But... What to do with the required init that does nor seem to work for a struct?

   

Gerry gets a coded message from the compiler!

I simplified your struct to just the first seven lines and tried it in Playgrounds.

class Order: ObservableObject, Codable {
    @Published var orderDetail = OrderDetail()
}

struct OrderDetail: Codable {
    static let types = ["Vanilla", "Strawberry", "Chocolate", "Rainbow"]

    var type          = 0
    var quantity      = 3
    var name          = ""
    var streetAddress = ""
    var city          = ""
    var zip           = ""
    //  ....... snip! ............
}

var myOrder = Order()        // in Playgrounds this creates a new object
myOrder.orderDetail.quantity // Playgrounds should report this is 3

The error messages states the compiler:

cannot automatically synthesize 'Decodable' because Published<OrderDetail> does not conform to 'Decodable' offending line --> @Published var orderDetail = OrderDetail()

If you remove the property wrapper, this compiles just fine. Xcode is able to synthesize the Decodable protocol because, as you stated, all the properties are Codable.

So the @Published property wrapper is the culprit here. Care to explore and figure out why?

   

OK. The original version (before challenge 3) addressed the published/Codable issue by adding encode/decode steps for the class. This challenge was to wrap a struct in a class which I thought was intended to simplify the codable problem. So, I am looking for a way to encode the class which does not have the vars used in the CodingKey or in the required init. Not sure how this is going to be simpler right now?! Here is where I am with an error on the required init for the struct, and no simplification...

class Order: ObservableObject {
    @Published var orderDetail = OrderDetail()

}

struct OrderDetail: Codable {
    static let types = ["Vanilla", "Strawberry", "Chocolate", "Rainbow"]
    //Make vars Codable
    enum CodingKeys: CodingKey {
        case type, quantity, extraFrosting, addSprinkles, name, streetAddress, city, zip
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        try container.encode(type, forKey: .type)
        try container.encode(quantity, forKey: .quantity)

        try container.encode(extraFrosting, forKey: .extraFrosting)
        try container.encode(addSprinkles, forKey: .addSprinkles)

        try container.encode(name, forKey: .name)
        try container.encode(streetAddress, forKey: .streetAddress)
        try container.encode(city, forKey: .city)
        try container.encode(zip, forKey: .zip)
    }
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        type = try container.decode(Int.self, forKey: .type)
        quantity = try container.decode(Int.self, forKey: .quantity)

        extraFrosting = try container.decode(Bool.self, forKey: .extraFrosting)
        addSprinkles = try container.decode(Bool.self, forKey: .addSprinkles)

        name = try container.decode(String.self, forKey: .name)
        streetAddress = try container.decode(String.self, forKey: .streetAddress)
        city = try container.decode(String.self, forKey: .city)
        zip = try container.decode(String.self, forKey: .zip)
    }
    //Initializer for new empty orders using defaults below
    init() { }

     var type = 0
     var quantity = 3
     var name = ""
     var streetAddress = ""
     var city = ""
     var zip = ""
     ....

   

Hacking with Swift is sponsored by RevenueCat

SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.