Skip to content

Instantly share code, notes, and snippets.

@thekarladam
Created September 19, 2015 02:03
Show Gist options
  • Save thekarladam/c3974dc545d56b41ee5b to your computer and use it in GitHub Desktop.
Save thekarladam/c3974dc545d56b41ee5b to your computer and use it in GitHub Desktop.
protocol DelegateOwningType {
typealias DelegateType
var delegate : DelegateType { get set }
}
class DelegatedOperation <T : DelegateOwningType, TDelegate where T.DelegateType == TDelegate.Type>: NSOperation {
let authority : T
var delegate : TDelegate
init(someT : T, someTD : TDelegate) {
authority = someT
delegate = someTD
authority.delegate = someTD
super.init()
}
}
@jckarter
Copy link

Should be able to simplify to this:

protocol DelegateOwningType: class {
    typealias DelegateType

    var delegate : DelegateType { get set }
}

class DelegatedOperation <T : DelegateOwningType>: NSOperation {
    let authority : T
    var delegate : T.DelegateType

    init(someT : T, someTD : T.DelegateType) {
        authority = someT
        delegate = someTD

        authority.delegate = someTD

        super.init()
    }
}

@thekarladam
Copy link
Author

So close…
Forcing preexisting types to conform remains the problem

class FooBar : NSNetServiceBrowser {
}

protocol DelegateOwningType {
    typealias DelegateType : AnyObject

    unowned(unsafe) var delegate : DelegateType { get set }
}

extension NSNetServiceBrowser : DelegateOwningType {}

class DelegatedOperation <T : DelegateOwningType>: NSOperation {
    var authority : T
    var delegate : T.DelegateType

    init(someT : T, someTD : T.DelegateType) {
        authority = someT
        delegate = someTD

        authority.delegate = someTD

        super.init()
    }
}


class Bar : NSObject, NSNetServiceDelegate {
}

let testOp = DelegatedOperation<NSNetServiceBrowser>(NSNetServiceBrowser(), Bar())

@jckarter
Copy link

I was able to get this to compile, matching the optionality of the delegate property on NSNetServiceBrowser, and making its delegate typealias explicit (even though we ought to infer it):

import Foundation

class FooBar : NSNetServiceBrowser {
}

protocol DelegateOwningType {
    typealias DelegateType : AnyObject

    var delegate : DelegateType? { get set }
}

extension NSNetServiceBrowser : DelegateOwningType {
  // Should be able to infer this...
  typealias DelegateType = NSNetServiceBrowserDelegate
}

class DelegatedOperation <T : DelegateOwningType>: NSOperation {
    var authority : T
    var delegate : T.DelegateType

    init(someT : T, someTD : T.DelegateType) {
        authority = someT
        delegate = someTD

        authority.delegate = someTD

        super.init()
    }
}


class Bar : NSObject, NSNetServiceBrowserDelegate {
}

let testOp = DelegatedOperation<NSNetServiceBrowser>(someT: NSNetServiceBrowser(), someTD: Bar())

@thekarladam
Copy link
Author

enum Result<T, Error: ErrorType> {
    case Success(T)
    case Failure(Error)
}

protocol RequiredWorkerMethods {
    typealias ResultType

    func begin(authority : AnyObject)
    var finish : (ResultType) -> Void { get set }
    var result : ResultType { get set }
}

protocol DelegateOwningType : AnyObject {
    typealias DelegateType
//  typealias SubclassedDelegateType = protocol<RequiredWorkerMethods, DelegateType>

    var delegate : DelegateType? { get set }
}

extension NSNetServiceBrowser : DelegateOwningType {
    typealias DelegateType = NSNetServiceBrowserDelegate
}

extension NSNetServicesError : ErrorType {}

protocol ConcreteWorker : RequiredWorkerMethods {
    typealias AuthorityType
}

class DelegatedOperation <T : DelegateOwningType, ConcreteDelegateType : ConcreteWorker, WorkProductType
where ConcreteDelegateType.AuthorityType == T>: NSOperation {
    var authority : T
    var delegate : ConcreteDelegateType
    var operationResult : ConcreteDelegateType.ResultType { return delegate.result }
    init(_ someT : T, _ someTD : T.DelegateType) {
        authority = someT
        delegate = someTD
        ^^^^ Cannot assign a value of type 'T.DelegateType' to a value of type 'ConcreteDelegateType'
        authority.delegate = someTD

        super.init()
    }

    override func start() {
        var worker = delegate

        worker.begin(authority)
        worker.finish = { inResult in self.finished = true }

        super.start()
    }
}

@jckarter
Copy link

This compiles for me if I add the T.DelegateType == ConcreteDelegateType constraint:

import Foundation 

enum Result<T, Error: ErrorType> {
    case Success(T)
    case Failure(Error)
}

protocol RequiredWorkerMethods {
    typealias ResultType

    func begin(authority : AnyObject)
    var finish : (ResultType) -> Void { get set }
    var result : ResultType { get set }
}

protocol DelegateOwningType : AnyObject {
    typealias DelegateType
//  typealias SubclassedDelegateType = protocol<RequiredWorkerMethods, DelegateType>

    var delegate : DelegateType? { get set }
}

extension NSNetServiceBrowser : DelegateOwningType {
    typealias DelegateType = NSNetServiceBrowserDelegate
}

extension NSNetServicesError : ErrorType {}

protocol ConcreteWorker : RequiredWorkerMethods {
    typealias AuthorityType
}

class DelegatedOperation <
  T : DelegateOwningType,
  ConcreteDelegateType : ConcreteWorker,
  WorkProductType
where
  ConcreteDelegateType.AuthorityType == T,
  T.DelegateType == ConcreteDelegateType
>: NSOperation {
    var authority : T
    var delegate : ConcreteDelegateType
    var operationResult : ConcreteDelegateType.ResultType { return delegate.result }
    init(_ someT : T, _ someTD : T.DelegateType) {
        authority = someT
        delegate = someTD
        // ^^^^ Cannot assign a value of type 'T.DelegateType' to a value of type 'ConcreteDelegateType'
        authority.delegate = someTD

        super.init()
    }

    override func start() {
        var worker = delegate

        worker.begin(authority)
        worker.finish = { inResult in /*FIXME self.finished = true*/ return }

        super.start()
    }
}

@thekarladam
Copy link
Author

I think our compilers may not be in sync because I get this error every time

enum Result<T, Error: ErrorType> {
    case Success(T)
    case Failure(Error)
}

protocol RequiredWorkerMethods {
    typealias ResultType

    func begin(authority : AnyObject)
    var finish : (ResultType) -> Void { get set }
    var result : ResultType { get set }
}

protocol DelegateOwningType : AnyObject {
    typealias DelegateType
    var delegate : DelegateType? { get set }
}

extension NSNetServiceBrowser : DelegateOwningType {
    typealias DelegateType = NSNetServiceBrowserDelegate
}

extension NSNetServicesError : ErrorType {}

protocol ConcreteWorker : RequiredWorkerMethods {
    typealias AuthorityType
}

class DelegatedOperation <T : DelegateOwningType, ConcreteDelegateType : ConcreteWorker
where T.DelegateType == ConcreteDelegateType>: NSOperation {
    var authority : T
    var delegate : ConcreteDelegateType
    var operationResult : ConcreteDelegateType.ResultType { return delegate.result }

    init(_ someT : T, _ someTD : T.DelegateType) {
        authority = someT
        delegate = someTD
        authority.delegate = someTD

        super.init()
    }

    override func start() {
        var worker = delegate

        worker.begin(authority)
        worker.finish = { inResult in  }

        super.start()
    }
}

class ConcreteFoo : NSObject, NSNetServiceBrowserDelegate, NSNetServiceDelegate, ConcreteWorker {
    typealias ResultType = Result<[AnyObject], NSNetServicesError>
    typealias AuthorityType = NSNetServiceBrowser

    var encounteredError : NSNetServicesError?
    var finish : (ResultType) -> Void
    var result : ResultType

    override init() {}

    func begin(authority: AnyObject) {}
}

let serviceLookup = DelegatedOperation<NSNetServiceBrowser, ConcreteFoo>(NSNetServiceBrowser(), ConcreteFoo())
^^^^'DelegatedOperation' requires the types 'DelegateType' (aka 'NSNetServiceBrowserDelegate') and 'ConcreteFoo' be equivalent

@thekarladam
Copy link
Author

Because I have to specify the type, the compiler won't accept it as a protocol and I can't declare conformance to as the compiler doesn't regard type aliases as complete types and there's no way to hint it as merely being a protocol

@jckarter
Copy link

I see, yeah, you wouldn't be able to use ConcreteFoo as the ConcreteDelegateType and satisfy the same-type constraint. You need some way to say "I want an NSNetServiceBrowser with a specific delegate type". You could use a wrapper struct for that:

protocol DelegateOwningType {
    typealias DelegateType
    var delegate : DelegateType? { get nonmutating set }
}

struct ConcreteNSNetServiceBrowser<T: NSNetServiceBrowserDelegate>: DelegateOwningType {
  var browser: NSNetServiceBrowser

  var delegate: T? {
    get {
      return browser.delegate as! T?
    }
    set {
      browser.delegate = newValue
    }
  }
}

which I think will work better. That lets this work:

import Foundation 

enum Result<T, Error: ErrorType> {
    case Success(T)
    case Failure(Error)
}

protocol RequiredWorkerMethods {
    typealias ResultType

    func begin(authority : AnyObject)
    var finish : (ResultType) -> Void { get set }
    var result : ResultType? { get set }
}

struct ConcreteNSNetServiceBrowser<T: NSNetServiceBrowserDelegate> {
  var browser: NSNetServiceBrowser

  var delegate: T? {
    get {
      return browser.delegate as! T?
    }
    set {
      browser.delegate = newValue
    }
  }
}

extension NSNetServicesError : ErrorType {}

protocol ConcreteWorker : RequiredWorkerMethods {
    typealias AuthorityType
}

class DelegatedOperation <
  ConcreteDelegateType: protocol<NSNetServiceBrowserDelegate, ConcreteWorker>
>: NSOperation {
    var authority : ConcreteNSNetServiceBrowser<ConcreteDelegateType>
    var delegate : ConcreteDelegateType
    var operationResult : ConcreteDelegateType.ResultType { return delegate.result! }

    init(_ someT : ConcreteNSNetServiceBrowser<ConcreteDelegateType>, _ someTD : ConcreteDelegateType) {
        authority = someT
        delegate = someTD
        authority.delegate = someTD

        super.init()
    }

    override func start() {
        var worker = delegate

        worker.begin(authority.browser)
        worker.finish = { inResult in  }

        super.start()
    }
}

class ConcreteFoo : NSObject, NSNetServiceBrowserDelegate, NSNetServiceDelegate, ConcreteWorker {
    typealias ResultType = Result<[AnyObject], NSNetServicesError>
    typealias AuthorityType = NSNetServiceBrowser

    var encounteredError : NSNetServicesError?
    var finish : (ResultType) -> Void
    var result : ResultType?

    override init() {
      self.finish = {_ in}
    }

    func begin(authority: AnyObject) {}
}

let serviceLookup = DelegatedOperation<ConcreteFoo>(
  ConcreteNSNetServiceBrowser(browser: NSNetServiceBrowser()),
  ConcreteFoo()
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment