无法将类型“[UITableViewCell.Type]”的值转换为 Swift 4.2 中的“[_.Type]”
Cannot convert value of type '[UITableViewCell.Type]' to '[_.Type]' in Swift 4.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 重新版本控制问题所以我从 swift 3 转换为 swift 4 并在 2 小时后花时间修复语法错误一直在那里,直到我变魔术。
let cellItems = [MainMenuTableViewCell.self,
RescueServicesTableViewCell.self]
table.registerCells(cells:cellItems)
此解决方案有效且错误消失。现在我的问题是为什么我收到此错误是 Xcode 问题还是我做错了什么?
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])
tableView.dequeueReusableCell(withIdentifier: String(describing: YoursCell.self), for: indexPath)
嗯,今天我将 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 重新版本控制问题所以我从 swift 3 转换为 swift 4 并在 2 小时后花时间修复语法错误一直在那里,直到我变魔术。
let cellItems = [MainMenuTableViewCell.self,
RescueServicesTableViewCell.self]
table.registerCells(cells:cellItems)
此解决方案有效且错误消失。现在我的问题是为什么我收到此错误是 Xcode 问题还是我做错了什么?
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])
tableView.dequeueReusableCell(withIdentifier: String(describing: YoursCell.self), for: indexPath)