我创建了 UICollectionViewCell 的子类,用于显示一些信息。我有一个类型为“天气”的属性。当设置了该实例后,我想更新单元格。下面的方法不好吗?我在想,如果我在加载 UI 组件之前访问它,我可能会触发 View 提前创建。或者这是无意义的并且仅适用于 UIViewController (关于尽早使用 view
属性)?
如果这不好,正确的方法是什么?
var weather: Weather? {
didSet {
if let weather = weather {
dayLabel.text = dayFormatter.stringFromDate(weather.fromDate)
// ... more code like this
}
}
}
最佳答案
不过,您可能需要一个 else
子句,如果 weather
为 nil
则清除文本字段。同样,如果您可能从后台线程更新此内容,您可能希望将该 UI 更新分派(dispatch)回主线程。
请注意,当您在单元格的 init
中设置 weather
时,不会调用此观察者(也不会在以下位置配置 @IBOutlet
):无论如何)。因此,请确保您不依赖于此。
此外,如果 Weather
是可变的,请注意,如果您更改现有 Weather
对象的 fromDate
,则不会捕获该对象。 (如果 Weather
是可变的,您确实希望通过 KVO、委托(delegate)协议(protocol)模式或其他方式捕获其不断变化的属性。)但是如果您创建 Weather
不变的,你应该没问题。
因此,从技术上讲,这就是问题的答案,但这引发了一些设计注意事项:
人们通常应该努力使不同类型松散耦合,即一种类型不应过于依赖另一种类型的内部行为。但在这里,我们在单元内有一个观察者,它依赖于
天气
的可变性。不建议使用存储属性在 View 中存储模型对象。单元格在滚动到屏幕外时会被重用,但您可能需要一个单独的模型来捕获相关模型对象,然后 Controller 根据需要处理向 View 对象(单元格)提供适当的模型对象。
<
底线,不建议在“ View ”内使用存储的属性来存储“模型”信息。
您可以通过编写代码来解决这两个问题,该代码清楚地表明您仅使用此天气
参数来更新 UI 控件,而不是为了存储任何内容。因此,我只想使用一个方法,而不是存储的属性:
func updateWithWeather(weather: Weather?) {
if let weather = weather {
dayLabel.text = dayFormatter.stringFromDate(weather.fromDate)
// ... more code like this
} else {
dayLabel.text = nil
// ... more code like this
}
}
这可能只能从 collectionView:cellForItemAtIndexPath:
中调用。
但是,这清楚地表明您只是根据天气参数更新控件,而不是尝试执行除此之外的任何操作。而且,巧合的是,天气对象的可变性现在是无关紧要的,正如它应该的那样。如果模型发生变化,请调用 reloadItemsAtIndexPaths:
,这将触发调用 collectionView:cellForItemAtIndexPath:
。
有时,使用 didSet
观察者存储的属性是一种有用的模式。但只有当该属性(property)确实是 View 属性(property)时才应该这样做。例如,考虑绘制某种形状的自定义 View 。您可能已存储属性,用于指定绘制路径时要使用的笔划的宽度和颜色等。然后,存储 lineWidth
和 StrokeColor
属性可能有意义,然后您可能有一个 didSet
调用 setNeedsDisplay()
(触发 View 的重绘)。
所以,您建议的模式确实有实际应用,只是它应该仅限于属性确实是 View 对象的属性的情况。
关于ios - 在 Swift 中使用属性观察器修改 UI 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34324273/