use*_*111 38 uitableview tableview collectionview uicollectionviewcell swift
我开始使用swiftLint并注意到Swift的最佳实践之一是避免使用强制转换.但是在处理tableView,collectionView for cells时我经常使用它:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellID, forIndexPath: indexPath) as! MyOffersViewCell
Run Code Online (Sandbox Code Playgroud)
如果这不是最好的做法,那么处理这个问题的正确方法是什么?我想我可以使用if with as?,但这是否意味着其他条件我需要返回一个空单元格?那可以接受吗?
if let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellID, forIndexPath: indexPath) as? MyOffersViewCell {
// code
} else {
// code
}
Run Code Online (Sandbox Code Playgroud)
Pau*_*w11 54
这个问题可能是以意见为基础的,所以我的答案是一丝不苟,但我不会说那种被迫贬低的人总是很糟糕; 您只需要考虑语义以及在给定情况下如何应用.
as! SomeClass它是一个契约,它基本上说"我保证这个东西是SomeClass的一个实例".如果事实证明它不是SomeClass,则会因为违反合同而抛出异常.
您需要考虑使用此合同的上下文以及如果不使用强制转发,可以采取的适当措施.
在您给出的示例中,如果dequeueReusableCellWithIdentifier 没有给您,MyOffersViewCell那么您可能错误配置了与单元重用标识符有关的内容,并且异常将帮助您找到该问题.
如果您使用了条件下转,那么您将获得nil并且必须以某种方式处理 - 记录消息?抛出异常?它肯定代表了一个不可恢复的错误,你想在开发过程中找到它; 你不希望在发布后必须处理这个问题.您的代码不会突然开始返回不同类型的单元格.如果你只是让代码在强制转发时崩溃,它将直接指向发生问题的行.
现在,考虑一种情况,即您正在访问从Web服务检索的某些JSON.Web服务可能会发生变化,超出您的控制范围,因此更优雅地处理此服务可能会很好.您的应用可能无法运行,但至少您可以显示警报而不是简单地崩溃:
BAD - 如果JSON不是数组,则崩溃
let someArray=myJSON as! NSArray
...
Run Code Online (Sandbox Code Playgroud)
更好 - 使用警报处理无效的JSON
guard let someArray=myJSON as? NSArray else {
// Display a UIAlertController telling the user to check for an updated app..
return
}
Run Code Online (Sandbox Code Playgroud)
Nic*_*ari 19
更新
在使用Swiftlint一段时间后,我现在完全转换为Zero Force-Unwrapping Cult(符合下面@ Kevin的评论).
是不是真的有你需要强制解开一个可选的,你不能使用任何情况下if let...,guard let... else或switch... case let...代替.
所以,现在我会这样做:
for media in mediaArray {
if let song = media as? Song {
// use Song class's methods and properties on song...
} else if let movie = media as? Movie {
// use Movie class's methods and properties on movie...
}
}
Run Code Online (Sandbox Code Playgroud)
...或者,如果您更喜欢详尽switch陈述的优雅和安全性,而不是容易出错的if/elses 链,那么:
switch media {
case let song as Song:
// use Song class's methods and properties on song...
case let movie as Movie:
// use Movie class's methods and properties on movie...
default:
// Deal with any other type as you see fit...
}
Run Code Online (Sandbox Code Playgroud)
...或更好,使用flatMap()转mediaArray成两个(可能是空的)类型的类型的阵列[Song]和[Movie]分别.但这超出了问题的范围(强制解包)......
此外,即使将表视图单元格出列,我也不会强制解包.如果无法将出队的单元格强制转换为相应的UITableViewCell子类,这意味着我的故事板出现了问题,因此我无法恢复某些运行时条件(相反,必须检测并修复了开发时错误)所以我保释与fatalError().
原始答案(备案)
除了Paulw11的答案之外,这种模式有时是完全有效,安全和有用的:
if myObject is String {
let myString = myObject as! String
}
Run Code Online (Sandbox Code Playgroud)
考虑Apple给出的示例:一个Media实例数组,可以包含Song或者Movie对象(Media的两个子类):
let mediaArray = [Media]()
// (populate...)
for media in mediaArray {
if media is Song {
let song = media as! Song
// use Song class's methods and properties on song...
}
else if media is Movie {
let movie = media as! Movie
// use Movie class's methods and properties on movie...
}
Run Code Online (Sandbox Code Playgroud)
当你知道你所投射的是那种类型时,"强制施放"就有它的位置.
假设我们知道myView有一个UILabel带有标记的子视图1,我们可以继续强制执行UIView到UILabel安全:
myLabel = myView.viewWithTag(1) as! UILabel
Run Code Online (Sandbox Code Playgroud)
或者,更安全的选择是使用警卫.
guard let myLabel = myView.viewWithTag(1) as? UILabel else {
... //ABORT MISSION
}
Run Code Online (Sandbox Code Playgroud)
后者更安全,因为它显然可以处理任何不良情况,但前者更容易.所以真的归结为个人偏好,考虑到它的某些东西是否会在将来发生变化,或者如果你不确定你所展开的东西是否是你想要的东西,那么在那种情况下,卫兵将永远是正确的选择.
总结一下:如果你确切地知道它会是什么,那么你可以强制施放,否则如果有可能是其他东西使用后卫
其他人写了一个更一般的案例,但我想给出我对这个确切案例的解决方案:
guard let cell = tableView.dequeueReusableCell(
withIdentifier: PropertyTableViewCell.reuseIdentifier,
for: indexPath) as? PropertyTableViewCell
else {
fatalError("DequeueReusableCell failed while casting")
}
Run Code Online (Sandbox Code Playgroud)
基本上,将它包裹在一个guard语句中,并可选地使用as?.
小智 5
正如一些选角讨论中所述,强制选角tableView.dequeueReusableCell是可以的,并且可以/应该这样做。
正如 Swiftlint Github 网站上的回答,您可以使用一种简单的方法来关闭它以进行表格单元格强制转换。
// swiftlint:disable force_cast
let cell = tableView.dequeueReusableCell(withIdentifier: "cellOnOff", for: indexPath) as! SettingsCellOnOff
// swiftlint:enable force_cast
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19556 次 |
| 最近记录: |