1 Reply
      Latest reply: Oct 31, 2016 6:08 AM by eskimo RSS
      ChristophV Level 1 Level 1 (10 points)

        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

        • Re: Can generic classes have a delegate???
          eskimo Apple Staff Apple Staff (6,280 points)

          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"