Can generic classes have a delegate???

Hi,


what I am trying to build is a ListConroller that tells it's delegate when a new entry was selected. The actual data type behind the single list elements is generic.

Sounds easy I thought.


Version1 – What I wanted, but did not work: Having a List of Entry and of course the Delegate is dependent on this type, too

protocol ListControllerDelegate: class {
    associatedtype Entry
    func list(_ list: ListController<Entry>, didSelectEntry element: Entry)
}
class ListEntryController<Entry>: NSViewController {
    var listView: NSTableCellView { get { return view as! NSTableCellView } }
    var entry: Entry?
    //…
}
class ListController<Entry>: NSObject, NSTableViewDelegate, NSTableViewDataSource {
    // Here I want a delegate that Whose associatedtype is Entry, that's all
    // ERROR: I would love something like this but it does not exist
    weak var delegate: ListEntryController? where ListEntryController.Entry = Entry
    var entries = [ListEntryController<Entry>]()
    var selectedIndex: Int = 0 {
        didSet {
            delegate?.list(self, didSelectEntry: entries[selectedIndex])
        }
    }
    // implementation of for getting data and selection change
    // …
}


Version 2 – This seemed to be the ugly way that should work: I had to make my List dependent on the Delegate and use it's associated type

protocol ListControllerDelegate: class {
    associatedtype Entry
    func list(_ list: ListController<Self>, didSelectEntry element: Entry)
}


class ListEntryController<Entry>: NSViewController {
    var listView: NSTableCellView { get { return view as! NSTableCellView } }
    var entry: Entry?
    /
}
// UGLY: List of thype Delegate :-(
class ListController<Delegate: ListControllerDelegate>: NSObject, NSTableViewDelegate, NSTableViewDataSource {
    /
    typealias Entry = Delegate.Entry
    weak var delegate: Delegate?
    var entries = [ListEntryController<Entry>]()
    var selectedIndex: Int = 0 {
        didSet {
            // ERROR: does not accept self as argument, should be of type ListController<_>
            delegate?.list(self, didSelectEntry: entries[selectedIndex])
        }
    }
    // implementation of for getting data and selection change
    // …
}
/
// UGLY again, the class needs to be final else implementation fails
final class MyClass: ListControllerDelegate {
    typealias Entry = String

    // would fail here if class is not final
    internal func list(_ list: ListController<MyClass>, didSelectEntry element: String) {
    }
}


So I am totally stuck. I am sure i am overlooking something and probably both ways are possible somehow. I simply may not have found the right notation?
Would be very glad if anyone could help? Where in the Swift documentation would I have found my answer?


All the best

Christoph

Replies

I think you want something like this:

import Foundation

protocol ListControllerDelegate: class { 
    associatedtype Entry 
    func list(_ list: ListController<Entry, Self>, didSelectEntry: Entry)
} 

class ListEntryController<Entry> : NSObject { 
    var entry: Entry? 
} 

class ListController<Entry, Delegate> : NSObject where Delegate : ListControllerDelegate, Delegate.Entry == Entry { 
    weak var delegate: Delegate? 

    var entries = [ListEntryController<Entry>]() 

    var selectedIndex: Int = 0 { 
        didSet { 
            delegate?.list(self, didSelectEntry: entries[selectedIndex].entry!)
        } 
    } 
}

The key point is the

ListController
is specialised by both an
Entry
and a
Delegate
, and
Delegate.Entry
must match
Entry
.

I’ve no idea where this actually works, but it does at least compile (-:

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"