Alvin
Alvin

Reputation: 539

Generic class call function

I am trying to create a wrapper for my API return wrapper class for my project.

these are my classes

class Wrapper<T> {

   let message = "Hello World"
   let wrapped = T.self
   public func getData() -> T.Type {
       return wrapped
   }
}

class Object {

   let number = 100
   public func getNumber() -> Int {
       return number
   }
}

class SecondObject {

   let name = "Second Object" 
   public func getName() -> String {
       return name
   }
}

What I want to achieve is, is there any way I can call the Object function like this

let example = Wrapper<Object>()
example.getData().getNumber() // <<-- This is not working
let secondExample = Wrapper<SecondObject>()
secondExample.getData().getName() // <<-- This is not working

The error in my playground is this

error: instance member 'getNumber' cannot be used on type 'Object'

If you notice the Wrapper class, there is message property which will be used for all my API return object model

So my goal is, I could simply call the Wrapper class together with my object model class and just call the function that is inside the object model class.

I am still learning about generic in swift. What am I missing here?

Upvotes: 2

Views: 80

Answers (3)

JeremyP
JeremyP

Reputation: 86651

You don't set wrapped to anything useful. You ned to set it to an instance of T. So you can pass a Tinto the constructor

class Wrapper<T>
{
    let wrapped: T

    init(wrapped: T)
    {
        self.wrapped = wrapped
    }
}

Or you can have the class construct an instance of T, but if you want to do that, you need to tell it how to construct the instance. For example:

class Wrapper<T>
{
    let wrapped: T

    init()
    {
        self.wrapped = T() // << error!
    }
}

won't work because the compiler knows nothing about T, not even if it has an init. You can change that with a protocol

protocol Initable 
{
    init()
}

class Wrapper<T: Initable>
{
    let wrapped: T

    init()
    {
        self.wrapped = T() 
    }
}

And you can apply the protocol to any type you like with an extension. In most cases the extension can be empty because mot types already have an init() method. For example:

class MyClass
{
    init() { /* do stuff */ }
}

extension MyClass: Initable {}

class MyOtherClass
{
    init(number: Int) { /* do stuff */ }
}

extension MyOtherClass: Initable 
{
    init() { self.init(number: 0) }
}

Another option is to supply a closure to the wrapper's init.

class Wrapper<T>
{
    let wrapped: T

    init(factory: ()-> T)
    {
        self.wrapped = factory()
    }
}

let w = Wrapper() { return Array<Int>() }

Normally you'd only do this if you wanted to create multiple instances i.e. you'd keep a reference to the closure and call it each time you needed a new instance.

Upvotes: 1

Bharat Jagtap
Bharat Jagtap

Reputation: 1692

How about this , in your example changing the type of wrapped from non-optional to an optional variable type.

 class Wrapper {

    let message = "Hello World"
    var wrapped : T?

    public func getData() -> T? {
        return wrapped
    }

}

class Object {

    let number = 100
    public func getNumber() -> Int {
        return number
    }
}

class SecondObject {

    let name = "Second Object"
    public func getName() -> String {
        return name
    }
}

and then using it as below



let example = Wrapper()
example.wrapped = Object()
let result1 = example.getData()?.getNumber() // ()
secondExample.wrapped = SecondObject()
let result2 = secondExample.getData()?.getName() 

if let val1 = result1 , let val2 = result2 {
    print("result1 = \(val1) result2 = \(val2)" )     
}

Upvotes: 0

tereks
tereks

Reputation: 1298

class Wrapper<T> {

    private var wrapped: T // Storing your object of T type

    init(value: T) { // init with instance of T
        wrapped = value
    }

    public func getData() -> T { //returning instance of T
        return wrapped
    }
}

class Object {

    let number = 100
    public func getNumber() -> Int {
        return number
    }
}

let o = Object()
let example = Wrapper(value: o) // Here we creating instance of Wrapper with instance of Object
example.getData().getNumber()

Upvotes: 0

Related Questions