Search code examples
swiftdesign-patternsadapter

Create instance from class using other class instance


So i came across this case, an already published application needed to change all of it's API's & Models.


Now i have created a generic tier to handle the requests and apis and almost mid way into implementing all the services, now i came across this problem, the previous defined models are used widely around the application of course and since its MVC , Massive View Controller. it is going to cost me too much changing everything in each scene to the new model type,
therefore i thought of making an adapter to cast the new models when i get them in my callback closure to the old ones type.


I have already figured out a way but the problem its pretty much long, long way i am looking for a better approach if existed and a better solution over all for the case if there was a better one.


protocol Parsable {
    var time: String { get }
    var span: String { get }
    init(_ copy: Parsable)
}

class Foo: Parsable {
    required init(_ copy: Parsable) {
        self.span =  copy.span
        self.time =  copy.time
    }

    init(time: String, span: String) {
        self.time = time
        self.span = span
    }
    var time = ""
    var span = ""
}

class Fee: Parsable {
    required init(_ copy: Parsable) {
        self.span =  copy.span
        self.time = copy.time
    }
    init(time: String, span: String, date: String) {
        self.time = time
        self.span = span
        self.date = date // an extra var that is not used in Foo
    }
    var time = ""
    var span = ""
    var date = ""
}

var foo = Foo(time: "", span: "")
var fee = Fee(time: "2", span: "ye", date: "123")
// Usage
var deeped = Foo(fee)

As you can tell from the code i've created a protocol that contains the variables and an init() that holds its type, now imagine this to implement a model with +50 variable and +40 model in total, might need an age or two.


Solution

  • So i Achieved this using Codable, i have created a dummy protocol that is conforming to Codable, and using that in every class, struct that i needed to convert it, and created a generic function extended from that protocol, to encode the object to data then decode it into the new type desired,

    With that i don't have to declare any variable or property i needed to copy manually.

    check out the code below.

    protocol Convertable: Codable {}
    
    class Foo: Convertable {
        var foo: String
        var fee: String
        init(foo: String, fee: String) {
            self.foo = foo
            self.fee = fee
        }
    }
    class Fee: Convertable{
        var fee: String
         init( fee: String) {
            self.fee = fee
        }
    }
    
    //Generic function to convert
    extension Convertable {
        func convert<T: Codable>(_ primary: T.Type) -> T? {
            return try? JSONDecoder().decode(primary, from: try! JSONEncoder().encode(self))
        }
    }
    var foo = Foo(foo: "nothing", fee: "nothing")
    let fee = foo.convert(Fee.self)
    fee?.fee // nothing