Bartłomiej Semańczyk
Bartłomiej Semańczyk

Reputation: 61774

How to return an object base on class type?

This is what I need for test purposes:

class AssemblerMock: Assemblerable {
    func resolve<Service>(_ serviceType: Service.Type) -> Service? {
        return Service.init() //doesnt work, need to return non nil value here.
    }
}

Upvotes: 0

Views: 48

Answers (1)

Andreas Oetjen
Andreas Oetjen

Reputation: 10199

It works with a little workaround: You need to create a protocol, let's call it Initable:

protocol Initable {
    init()
}

then, your resolve-Template-Method should require Service to be Initable:

func resolve<Service>(_ serviceType: Service.Type) -> Service where Service:Initable {
    return Service.init()
}

Before using it, you also need to create an extension to all the types you might want to resolve:

extension Int : Initable {
    // No implementation possible/needed, because `init` already exits in struct Int
} 

and then call it:

let am = AssemblerMock()
let i = am.resolve(Int.self)
print (i)   // Prints "0" because this is the default Integer value

Remark: I made the return type to return Service and not Service?, but it doesn't matter here. If you want to support failable initializers (init?), you need to modify the return type as well as the Initable protocol:

protocol Initable {
    init?()
}

extension Int : Initable {} 

class FooFailing : Initable {
    required init?() {
        return nil
    }
}

class AssemblerMock {
    func resolve<Service>(_ serviceType: Service.Type) -> Service? where Service:Initable {
        return Service.init()
    }
}

let am = AssemblerMock()
let i = am.resolve(Int.self)
print (i)   // Optional(0)
let foo = am.resolve(FooFailing.self)
print (foo) // nil

Upvotes: 2

Related Questions