给定一个可选的Book类型数组,在表视图控制器类中声明:
var books: [Book]?
后来cellForRowAtIndexPath
我有:
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath)
let book = books?[indexPath.row]
cell.textLabel?.text = book?.title
return cell
}
现在,到目前为止,我只看到这个书籍数组可选解包使用if语句来循环遍历数组。
但是为什么在cellForRow这里我们不打开书籍并解开书籍而不是添加另一本书?在它之后,如books?[indexPath.row]
和cell.textLabel?.text = book?.title
答案 0 :(得分:1)
从不将非可选表视图或集合视图的数据源数组声明为可选。
var books = [Book]()
这让你的生活变得如此轻松
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath)
let book = books[indexPath.row]
cell.textLabel?.text = book.title
return cell
}
答案 1 :(得分:1)
使用?
的可选展开意味着如果该值存在,请将其解包。如果您不打算在其他地方使用潜在的零值,那么这样做是可以的(可以安全地做)。在你的情况下,你可以从技术上这样做(它会编译,并可能赢得崩溃),但它不是最安全的方式,因为现在你依赖于沿着支持零值的方法。
那就是说,你真的不需要声明你的数组是可选的。因为您无论如何都要枚举数据行数,所以数组应该始终存在。变量包含的行数,而不是是否存在。换句话说:在检查行数之前检查数组是否存在只是编译器的额外工作和您编写的额外代码。
您也可以利用guard
,减少在您没有良好数据时执行的代码量:
// ...
guard let book = books[indexPath.row] else { return cell }
cell.textLabel?.text = book.title
return cell
答案 2 :(得分:1)
您不必解开books
或book
,因为text
的{{1}}属性是可选的UILabel
。您必须打开选项的唯一时间是您在某些不接受可选项的上下文中使用检索到的值。但String?
确实如此,因此您的示例运行正常。
我对这种语法的问题是,虽然它是一个有用的简写,但这有点草率。如果存在编程问题(例如,text
是books
,当调用它时即使技术上不可能),问题中的代码将默默地继续执行,您将留下挠头,想知道为什么单元格中的标签是空白的。 (对于建议使用nil
语句的模式也是如此,如果解包失败,则静默返回guard
。)
但我强烈不同意其他地方提出的cell
不应该是可选的建议。如果在实例化视图控制器时无法填充此数组,则books
应是可选的(并且为books
),直到检索到此信息为止。
最重要的是," nil
的状态尚未设置"和#34; books
已填充,但未返回任何记录"。这是可选项的目的,以避免任意的标记值,例如"空数组"表示books
没有设置其值。 (我同情那些反对过度使用期权的人,但这根本不是其中之一。而且我也不会购买books
性能开销问题,因为它并不重要这个例子让我觉得它是过早优化的一个完美例子。)
相反,我相信你应该(a)选择Optional
;但是(b)检测它是否意外books
并将其报告为错误,因为如果调用nil
,则不能cellForRowAt
。
因此,我建议:
nil
这实现了我们想要的,正确填充标签,但如果出现代码逻辑错误且func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath)
let book = books![indexPath.row]
cell.textLabel?.text = book.title
return cell
}
为books
,也会立即将开发人员带到有问题的代码行。
现在,许多开发人员对使用nil
强制解包运算符感到厌恶。我个人认为这很好,因为当调用此方法!
为books
时,它是一个基本的编程错误,并且强制解包运算符将在违规行停止执行我确切地知道问题是什么。
但是,如果你真的想避免使用强制解包操作符nil
,那么请使用!
语句,如果guard
为{{1},则触发信息性fatalError
}}:
books
关键是,如果出现nil
为func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath)
guard let book = books?[indexPath.row] else {
fatalError("No book found")
}
cell.textLabel?.text = book?.title
return cell
}
的情况,您希望在开发过程中立即知道,而不是猜测问题的根源是什么。
要明确的是,这种强制展开和/或books
模式应该永远不会用于因为您无法控制的情况下展开失败的情况。例如,在解析来自远程Web服务的响应或处理用户输入时,请不要使用这些模式。您希望优雅地处理可能由您控制之外的错误。但是如果某个特定场景发生真正的程序错误,那么强制解包和/或nil
方法是可取的,因此逻辑错误立即显现出来,而不是强迫你去寻找异常的来源。应用行为。