Debanjan Chakraborty
Debanjan Chakraborty

Reputation: 35

Where clause in extension of a class in swift with enum and generics

I'm new to generics and I want to apply it for this logic.

So I have created an enum of user types. I have a userModel object that contains this user type information.

Now my UIViewController A will contain a user object and a tableView. Based on the user type, the number of cells and the cell design will also change.

Basically I don't want to clutter the entire logic into cell ForRowAtIndexPath and other such methods, which is why I was looking into generics.

This is my code

       enum UserType : Int {
            case None = 0, Musician, Listener
        }

        class User {
            var userType : UserType = .None
        }

        class A<T:User>: UIViewController {

            var selectedUser: T?
        }


        extension A where T.userType : UserType.Musician 
         {
            func foo() { print("Musician") }
        }

This gives me an error

Playground execution failed:

error: MyPlayground.playground:13:53: error: enum element 'Musician' is not a member type of 'UserType'
            extension A where T.userType : UserType.Musician {

I would like to know why this error is comming and if my approach is wrong.

Upvotes: 0

Views: 1169

Answers (1)

Maxim Kosov
Maxim Kosov

Reputation: 1980

To create extension you must provide only information known at compile time. userType is property of User and hence it's runtime information. It can't be used to create extension.

But I think you still might benefit from protocols and generics. I'm not sure if it suits you, but anyway here's how it can be done.

You can declare protocols for each type of user like this

protocol UserProtocol {
    var userType: UserType { get }

    func doYourThing()
}

protocol MusicianProtocol: UserProtocol {}
protocol ListenerProtocol: UserProtocol {}

and create default implementation of UserProtocol

extension UserProtocol where Self: MusicianProtocol {
    var userType: UserType { return .musician }

    func doYourThing() {
        print("Do-di-do!")
    }
}

extension UserProtocol where Self: ListenerProtocol {
    var userType: UserType { return .listener }

    func doYourThing() {
        print("Anything except vynil is garbage!")
    }
}

Of course this way you will need separate class for each user

class Musician: MusicianProtocol {}

class Listener: ListenerProtocol {}

but generic handling is still possible by using UserProtocol

func letsPlay(_ users: UserProtocol...) {
    for u in users {
        u.doYourThing()
    }
}


let m = Musician()
let l = Listener()

letsPlay(m, l)

Upvotes: 2

Related Questions