Ekra
Ekra

Reputation: 3301

iOS Generic swift closure

I want to Pass a generic model object in swift.

Currently I have a closure that have to return the Model object as below

  completionHandler = ([ModelObject]?, Error?) -> Void

Method calling

func method1( onCompletion: @escaping completionHandler) -> Void {

}

I want to make a generic completionhandler that can pass different model instead of specific Model. Note:- all model object conform to Codable protocol as below

struct ModelObject: Codable {
}

//===== Edit======

func method1<M: Codable>( onCompletion: @escaping (M?, Error?) -> Void) -> Void {
            let decoder = JSONDecoder()
            let items = try? decoder.decode(ModelObject.self, from: data)
            onCompletion(items, nil)// error in this line Cannot convert value of type 'ModelObject?' to expected argument type '_?'
}

Upvotes: 0

Views: 1937

Answers (2)

Mukesh
Mukesh

Reputation: 2902

You can create your method something like:

func method1<Model: Codable>(onCompletion: @escaping (Model?, Error?) -> Void) -> Void {
    let decoder = JSONDecoder()
    let itemObj = try? decoder.decode(Model.self, from: data)
    onCompletion(itemObj, nil)
}

And if you have your struct like:

struct ModelObject: Codable {
}

you can call this method like:

method1 { (model: ModelObject?, error) in

}

You have another struct like:

struct AnotherModelObject: Codable {
}

You can call it like:

method1 { (model: AnotherModelObject?, error) in

}

Upvotes: 5

Vyacheslav
Vyacheslav

Reputation: 27211

You can hide the protocol inside another struct or you can use a custom container.

protocol Container { }
struct Storage {
    let model: Codable
}
struct ModelObject: Codable, Container {
}
enum Result<T> {
    case data(result: T)
}
typealias completionHandler = ([Storage]?, Error?) -> Void

func method1(onCompletion: @escaping completionHandler) -> Void {
    onCompletion([Storage(model:ModelObject())], nil)
}
func method2(onCompletion: @escaping ([Result<Codable>]) -> Void) -> Void {
    onCompletion([Result.data(result: ModelObject() as Codable)])
}
method1 { result, _ in
    print(result![0].model)
}
method2 { result in
    print(result[0])
}

Upvotes: 1

Related Questions