好吧,今天我将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 3 转换为 swift 4,经过 2 个小时花时间修复语法,错误仍然存在,直到我做了魔术。
let cellItems = [MainMenuTableViewCell.self,
RescueServicesTableViewCell.self]
table.registerCells(cells:cellItems)
此解决方案有效,错误消失。现在我的问题是为什么我收到此错误是这个 Xcode 问题还是我做错了什么?
这是一个有趣的错误(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])
在执行可选链接(即x?.foo
(或强制解包(即x!.foo
(以执行成员访问时,使x
成为非可选或强可选(即X?
(允许代码编译。
您可以使用一些解决方法,首先是显式指定数组类型,使编译器不必推断类型连接:
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])
tableView.dequeueReusableCell(withIdentifier: String(describing: YoursCell.self), for: indexPath)