2

Well, today after I update Xcode to version 10.0, I faced following error in my code.

// error: Cannot convert value of type '[UITableViewCell.Type]' to expected argument type
// '[_.Type]'  
table.registerCells(cells: [MainMenuTableViewCell.self,
                            RescueServicesTableViewCell.self])

Here is the registerCells function:

func registerCells<T> (cells : [T.Type]) where T: UITableViewCell  {
        for cell in cells  {
            let nib = UINib(nibName: String(describing: cell), bundle: nil)
            register(nib, forCellReuseIdentifier: String(describing: cell))
        }
    }

At the beginning I thought it might be swift re-versioning issue so I convert from swift 3 to swift 4 and after 2 hours spending time to fix syntaxes the error was still there, until I did the magic trick.

let cellItems = [MainMenuTableViewCell.self,
                 RescueServicesTableViewCell.self]

table.registerCells(cells:cellItems)

This solution works and error gone. Now my question is why I'm getting this error is this Xcode problem or I did something wrong?

2
  • Try clean build Commented Sep 24, 2018 at 9:29
  • Already tried it, not working. Commented Sep 24, 2018 at 9:30

2 Answers 2

3

This is an interesting bug (SR-8825) where the compiler appears to be unable to perform type joining (the process of inferring a common supertype for a collection of types) within a member access on an implicitly unwrapped optional (IUO) declaration (presumably in your case table is an IUO @IBOutlet).

A minimal example would be:

class C {}
class D : C {}
class E : C {}

struct X {
  func foo<T>(_: [T.Type]) where T : C {}
}

var x: X!

// error: Cannot convert value of type '[C.Type]' to expected argument type '[_.Type]'
x.foo([D.self, E.self]) 

Making x either non-optional, or a strong optional (i.e X?) while performing either optional chaining (i.e x?.foo) or force unwrapping (i.e x!.foo) to perform the member access allows the code to compile.


There are a few workarounds you can use, first of which is to explicitly specify the array type, saving the compiler from having to infer the type join:

x.foo([D.self, E.self] as [C.Type])

In your case, this translates to:

table.registerCells(cells: 
  [MainMenuTableViewCell.self, RescueServicesTableViewCell.self] as [UITableViewCell.Type]
)

Second workaround is to use a non-optional base. In your case, you can force unwrap the IUO into a local variable before performing the member access:

// this is just explicitly doing what the compiler would have otherwise done implicitly.
let table = self.table!
table.registerCells(cells: [MainMenuTableViewCell.self, RescueServicesTableViewCell.self])

Third workaround is, as you've already discovered, to separate out the array into its own expression – which allows the compiler to do the type joining on its own:

let cellItems = [MainMenuTableViewCell.self, RescueServicesTableViewCell.self]
table.registerCells(cells: cellItems)

Though the solution I would go with in your case is to make registerCells(cells:) non-generic, as it doesn't appear that you're using the generic placeholder T for anything useful:

extension UITableView {
  func registerCells(_ cells: [UITableViewCell.Type]) {
    for cell in cells  {
      let nib = UINib(nibName: String(describing: cell), bundle: nil)
      register(nib, forCellReuseIdentifier: String(describing: cell))
    }
  }
}

Which you can now just call like so:

table.registerCells([MainMenuTableViewCell.self, RescueServicesTableViewCell.self])
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for complete explanation on this, now it make a lot more sense to me.
0
tableView.dequeueReusableCell(withIdentifier: String(describing: YoursCell.self), for: indexPath)

1 Comment

While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.