TruMan1
TruMan1

Reputation: 36088

How to create protocol-oriented generic services?

I'm trying to create a protocol that will serve data for view controllers. I'm trying to take the protocol approach and makes things flexible, so the view controllers can conform using any type of data.

However, I'm getting the error: Protocol 'Serviceable' can only be used as a generic contraint because it has Self or associated type requirements

This is what I'm trying to do:

protocol Serviceable {
    associatedtype DataType
    func get(handler: ([DataType] -> Void)?)
}

struct PostService: Serviceable {
    func get(handler: ([Postable] -> Void)? = nil) {
        print("Do something...")
    }
}

struct AuthorService: Serviceable {
    func get(handler: ([Authorable] -> Void)? = nil) {
        print("Do something...")
    }
}

protocol Postable {
    var title: String { get set }
    var content: String { get set }
}

protocol ServiceControllable: class {
    var service: Serviceable { get } // Error: Protocol 'Serviceable' can only be used as a generic contraint because it has Self or associated type requirements
}

extension ServiceControllable {
    func setupDataSource() {
        service.get { items in
            // Do something
        }
    }
}

class MyViewController: ServiceControllable {
    let service: Serviceable = PostService() // Error: Same as above

    override func viewDidLoad() {
        super.viewDidLoad()
        setupDataSource()
    }
}

How do I set this up so that my view controllers can implement ServiceControllable and have access to a generic setupDataSource that populates tables, collections, etc?

Upvotes: 1

Views: 107

Answers (1)

werediver
werediver

Reputation: 4757

You want something like this.

import UIKit

protocol Serviceable {
    associatedtype DataType
    func get(handler: ([DataType] -> Void)?)
}

struct PostService: Serviceable {
    func get(handler: ([Postable] -> Void)? = nil) {
        print("Do something...")
    }
}

protocol Authorable {}

struct AuthorService: Serviceable {
    func get(handler: ([Authorable] -> Void)? = nil) {
        print("Do something...")
    }
}

protocol Postable {
    var title: String { get set }
    var content: String { get set }
}

protocol ServiceControllable: class {

    // THIS is the way to use generic-constraint-protocols in protocols.
    associatedtype _Serviceable: Serviceable

    var service: _Serviceable { get }

}

extension ServiceControllable {
    func setupDataSource() {
        service.get { items in
            // Do something
        }
    }
}

class MyViewController: UIViewController, ServiceControllable {

    let service = PostService()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupDataSource()
    }
}

The related documentation section: Protocol Associated Type Declaratio.

Upvotes: 1

Related Questions