4

I'm refactoring my code and adding support for Swift generics. I'm stuck with a compiler error. My code is:

func dequeueReusableViewController<T: UIViewController where T: Reusable>() -> T {
        // Try to fetch view controller from the reuse queue.
        if !self.viewControllerReuseQueue.isEmpty {
            return self.viewControllerReuseQueue.popFirst()! as! T
        }

        // Ask delegate to instantiate a new view controller.
        return delegate!.reusableViewControllerForPageViewController(self)
}

This compiles smoothly. Then, later, when I try to dequeue a view controller:

// Get view controller from the reuse queue.
let viewController: UIViewController = self.dequeueReusableViewController()

I'm getting an error:

Generic parameter 'T' could not be inferred

How can I solve this? I checked similar questions on SO but none of them describes my case.

Rafał Sroka
  • 39,540
  • 23
  • 113
  • 143
  • What about "let viewController = self.dequeueReusableViewController() as! UIViewController"? – brduca Feb 02 '16 at 15:39
  • Same thing, I'm getting the same error – Rafał Sroka Feb 02 '16 at 15:41
  • And forcing the cast to the generic type? return delegate!.reusableViewControllerForPageViewController(self) as! T – brduca Feb 02 '16 at 15:44
  • No difference. When I added this cast I got a compiler warning: `Forced cast of 'T' to same type has no effect` – Rafał Sroka Feb 02 '16 at 15:53
  • We are going to need a [sscce](http://sscce.org/) of the issue. Something else must be going on. Setting the type `let x: Type = genericCall()` or `let x = genericCall() as Type` should have resolved the issue shown. I see you updated to include `UIViewController` in the type, did you add an extension to `UIViewController` that conforms to `Reusable`? – Joe Feb 02 '16 at 16:29

3 Answers3

5

The type cannot be inferred when calling a generic function returning a generic type without specifying the type of the variable you are assigning to or casting the call to the function. You can do:

let viewController: SomeViewController = self.dequeueReusableViewController()

or

let viewController = self.dequeueReusableViewController() as SomeViewController

I would recommend the first option unless the second is required (needing to assign to an optional for example).

Joe
  • 56,979
  • 9
  • 128
  • 135
  • Thanks for the answer! I tried `let viewController: UIViewController = self.dequeueReusableViewController()` and I'm getting exactly same error. – Rafał Sroka Feb 02 '16 at 15:26
  • That's because on its own, `UIViewController` does not implement `Reusable`. – ahaese Feb 02 '16 at 19:31
2

There is no way the compiler know what type T is as you do not infer it.

You could force the method to know about type T:

func dequeueReusableViewController<T: UIViewController where T: Reusable>(type: T.Type) -> T?

// ...

let viewController = self.dequeueReusableViewController(YourViewController)

Alternatively, and somewhat neater you could let the variable do the work:

func dequeueReusableViewController<T: UIViewController where T: Reusable>() -> T?

// ...

let viewController: YourViewController = self.dequeueReusableViewController()

Either way you need to provide some help to let the compiler know what you're dealing with.

Oliver Atkinson
  • 7,970
  • 32
  • 43
0

Should work if you are using like below example

protocol Reusable {
    func someMethod()
}

class VC: UIViewController, Reusable {

   func someMethod() {
    //Implement
   }

}

class Dequeuer {

    var viewControllerReuseQueue = [VC(),VC(),VC()]

    func dequeueReusableViewController<T: UIViewController where T: Reusable>() -> T? {
    // Try to fetch view controller from the reuse queue.
    return viewControllerReuseQueue.first as? T
  }

}

let vc: VC? = Dequeuer().dequeueReusableViewController()
print(vc)

GENERICS -

let viewController = self.dequeueReusableViewController() 

is just storing the value in viewController but the type of viewController is unknown thats why it is showing you Generic parameter 'T' could not be inferred

Try let viewController: UIViewController = self.dequeueReusableViewController()

Then T will get inferred from the type UIViewController.

Rahul Katariya
  • 3,528
  • 3
  • 19
  • 24