0

I am trying to create a protocol (AppStore) which requires the conformer to implement an array of items (subscriptions) that conform to a protocol (Subscriber) that has an associated type.

goal You can think of AppStore like an NSNotificationCenter. I want to add subscribers (like addObserver...). When something happens call handleNewState on the subscribers (like handleNotification:) and pass in an AppState conformer that actually has some variables set on it. The stock AppState doesn't have any properties available.

public protocol AppStore {
    //trying to have an array of subscriptions in the protocol
    //but a concrete Subscriber type needs to be specified, I thought a generic Subscriber would be more flexible here?
    var subscriptions:[Subscription<>]{get set}// Reference to generic type 'Subscription' requires arguments in <...>

    associatedtype AppStateType:AppState
    var appState:AppStateType { get set }
}
extension AppStore {
    //so that AppStore can implement this function
    public mutating func subscribe<T:protocol<Subscriber, AnyObject>>(aSubscriber:T){
        subscriptions.append(Subscription(sub:aSubscriber))
    }
}

public protocol Subscriber {
    associatedtype AppStateType
    func handleNewState(newState:AppStateType)
}

public struct Subscription <T:protocol<Subscriber, AnyObject>> {
    private weak var subscriber:T? = nil
    init(sub:T){
        self.subscriber = sub
    }
}
public protocol AppState { }

How am I supposed to define var subscriptions:[Subscription<>]? Or should I be doing this a different way

I would use it like this

public struct OSXAppState:AppState {
     var someStateProp:Int = 0
}
extension NSView : Subscriber { 
    public func handleNewState(newState:OSXAppState){
         if newState == 1 { //do this }
         else { //do that }
    } 
}
public struct OSXAppStore : AppStore {
    public typealias GenericSubscriber = NSView//???: something more generic "anything that implements Subscriber"
    public var subscriptions: [Subscription<GenericSubscriber>] = []
    public var appState: AppState = OSXAppState()
}
joels
  • 7,249
  • 11
  • 53
  • 94
  • 1
    Can you describe your goal in more detail? What problem are you trying to solve with this code? This may not be the most direct way toward that goal. –  Apr 27 '16 at 14:45

1 Answers1

1

I assume that you were adhering to AnyObject in order to be able to use weak. This can be done more simply by making the protocol class-only. I changed the protocol composition

protocol<Subscriber, AnyObject>

to

protocol Subscriber: class

I also added

associatedtype GenericSubscriber: SubscriberType

to allow the generic

Subscription<T: SubscriberType>

to be used in the array.

public protocol Subscriber: class {
  associatedtype AppStateType:AppState
  func handleNewState(newState:AppStateType)
}

public struct Subscription<T:Subscriber> {
  private weak var subscriber:T?
  init(sub:T){
    self.subscriber = sub
  }
}

public protocol AppState { }

public protocol AppStore {
  // Allows Subscription<T:Subscriber> to be used as an array element
  associatedtype GenericSubscriber:Subscriber

  var subscriptions:[Subscription<GenericSubscriber>]{get set}
  var appState:AppState { get set }
}

extension AppStore {
  // The concrete type of GenericSubscriber is inferred from this context
  public mutating func subscribe(aSubscriber: GenericSubscriber){
    subscriptions.append(Subscription<GenericSubscriber>(sub:aSubscriber))
  }
}

public struct OSXAppState:AppState {
  var someStateProp:Int
}
extension NSView : Subscriber {
  public func handleNewState(newState:OSXAppState){
  }
}
  • The `associatedtype AppStateType` is the key piece here. I want to create an AppState conformer that uses it's own AppState type. `public struct OSXAppState:AppState { }`. Without AppStateType how do I do this `extension NSView : Subscriber { public func handleNewState(newState: OSXAppState ){ } }` (newState: **OSXAppState** ) – joels Apr 27 '16 at 16:20
  • I updated the answer to reflect how you are using the code. –  Apr 28 '16 at 00:21
  • Thank you! So, how would I implement a struct that conforms to AppStore? The use I have only allows NSView but I would to allow anything that conforms to Subscriber. I updated my use case code to include OSXAppStore. – joels Apr 28 '16 at 06:19