Swift 3: generic delegate type type error with specific consumer type

I have a problem with a generic delegate ProducerDelegatethat will have an argument ( Int) with the same type that the method IntConsumer( Int) needs it

If delegate methods are called and I want to use the resulting value element

func didProduce<Int>(from: Producer<Int>, element: Int) {
    output(element: element)
}

to call another method, I got an error:

Cannot convert value of type 'Int' to expected argument type 'Int'

And my question is: why?

I will explain my case (and here is the playground file with the same source: http://tuvalu.s3.amazonaws.com/so/generic-delegate.playground.zip )

I have a generic manufacturers class Producerwith a protocol for the created elements ProducerDelegate:

import Foundation

/// Delegate for produced elements
protocol ProducerDelegate : class {

    /// Called if a new element is produced
    ///
    /// - Parameters:
    ///     - from: producer
    ///     - element: produced element
    func didProduce<T>(from: Producer<T>, element: T)
}

/// Produces new element
class Producer<T> {

    /// The object that acts as consumer of produced element
    weak var delegate: ProducerDelegate?

    /// The producing element
    let element: T

    /// Initializes and returns a `Producer` producing the given element
    ///
    /// - Parameters:
    ///     - element: An element which will be produced
    init(element: T) {
        self.element = element
    }

    /// Produces the object given element
    func produce() {
        delegate?.didProduce(from: self, element: element)
    }
}

In the consumer, the manufacturer introduces:

/// Consumes produced `Int` elements and work with it
class IntConsumer {

    /// Producer of the `Int`s
    let producer: Producer<Int>

    /// Initializes and returns a `IntConsumer` having the given producer
    ///
    /// - Parameters:
    ///     - producer: `Int` producer
    init(producer: Producer<Int>) {
        self.producer = producer
        self.producer.delegate = self
    }

    /// outputs the produced element
    fileprivate func output(element: Int) {
        print(element)
    }
}

Now I need to add the extension for the delegate as follows:

extension IntConsumer: ProducerDelegate {
    func didProduce<Int>(from: Producer<Int>, element: Int) {
        output(element: element)
    }
}

But this fails: Cannot convert value of type 'Int' to expected argument type 'Int'

Swift , Int, :

func didProduce<Int>(from: Producer<Int>, element: Int) {
    output(element: element as! Int)
}

, String, :

func didProduce<String>(from: Producer<String>, element: String) {
    guard let element2 = element as? Int else { return }

    output(element: element2)
}

, - typealias, :

extension IntConsumer: ProducerDelegate {
    typealias T = Int

    func didProduce<T>(from: Producer<T>, element: T) {
        guard let element = element as? Int else { return }

        output(element: element)
    }
}

, - .

+4
1

func didProduce<T>(from: Producer<T>, element: T)

: " ". , - IntConsumer Int.

:

func didProduce<Int>(from: Producer<Int>, element: Int) {...}

"Int" - Int . "Int" , , , Int.

- :

/// Delegate for produced elements
protocol ProducerDelegate : class {

    associatedtype Element

    /// Called if a new element is produced
    ///
    /// - Parameters:
    ///     - from: producer
    ///     - element: produced element
    func didProduce(from: Producer<Element>, element: Element)
}

: " , ".

:

extension IntConsumer : ProducerDelegate {

    // Satisfy the ProducerDelegate requirement – Swift will infer that
    // the associated type "Element" is of type Int.
    func didProduce(from: Producer<Int>, element: Int) {
        output(element: element)
    }
}

( <Int>).

, , ProducerDelegate - . , , , ProducerDelegate, , .

:

// A wrapper for a ProducerDelegate that expects an element of a given type.
// Could be implemented as a struct if you remove the 'class' requirement from 
// the ProducerDelegate.
// NOTE: The wrapper will hold a weak reference to the base.
class AnyProducerDelegate<Element> : ProducerDelegate {

    private let _didProduce : (Producer<Element>, Element) -> Void

    init<Delegate : ProducerDelegate>(_ base: Delegate) where Delegate.Element == Element {
        _didProduce = { [weak base] in base?.didProduce(from: $0, element: $1) }
    }

    func didProduce(from: Producer<Element>, element: Element) {
        _didProduce(from, element)
    }
}

, base .

Producer delegate, :

var delegate: AnyProducerDelegate<Element>?

IntConsumer:

/// Consumes produced `Int` elements and work with it
class IntConsumer {

    // ...        

    init(producer: Producer<Int>) {
        self.producer = producer
        self.producer.delegate = AnyProducerDelegate(self)
    }

    // ...

}

, , delegate nil, , didProduce . , - , , - .

+2

Source: https://habr.com/ru/post/1664818/


All Articles