2

好吧,今天我将 Xcode 更新到 10.0 版后,我的代码中遇到了以下错误。

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

这是registerCells功能:

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))
        }
    }

一开始我认为这可能是 swift re-versioning 问题,所以我从 swift 3 转换为 swift 4,在花了 2 个小时修复语法后,错误仍然存​​在,直到我做了魔术。

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

table.registerCells(cells:cellItems)

该解决方案有效并且错误消失了。现在我的问题是为什么我收到这个错误是这个 Xcode 问题还是我做错了什么?

4

2 回答 2

3

这是一个有趣的错误 ( SR-8825 ),其中编译器似乎无法在隐式展开的可选 (IUO) 声明的成员访问中执行类型连接(推断类型集合的公共超类型的过程)(大概在你的情况下table是 IUO @IBOutlet)。

一个最小的例子是:

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]) 

在执行可选链接 (ie ) 或强制展开 (ie ) 以执行成员访问时,将其设为非可选或强可选 (ie )允许代码编译xX?x?.foox!.foo


您可以使用一些解决方法,首先是显式指定数组类型,从而使编译器不必推断类型连接:

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

在您的情况下,这转化为:

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

第二种解决方法是使用非可选基础。在您的情况下,您可以在执行成员访问之前强制将 IUO 解包到局部变量中:

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

正如您已经发现的那样,第三个解决方法是将数组分离成它自己的表达式——这允许编译器自己进行类型连接:

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

尽管在您的情况下我会采用的解决方案是制作registerCells(cells:)非通用的,因为您似乎没有将通用占位符T用于任何有用的东西:

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))
    }
  }
}

您现在可以这样调用:

table.registerCells([MainMenuTableViewCell.self, RescueServicesTableViewCell.self])
于 2018-09-24T10:50:11.407 回答
0
tableView.dequeueReusableCell(withIdentifier: String(describing: YoursCell.self), for: indexPath)
于 2021-02-05T13:19:15.353 回答