在Swift中创建不可变的委托
最初发布于 swiftrocks.com 。
为了防止诸如委托之类的属性发生引用循环,通常使用weak
关键字:
weak var delegate: HomeViewDelegate?
不幸的是,由于它可以保护您避免丢失引用,因此weak
关键字会强制使用var
和可选类型,如果您要构建的UIView
类的东西在没有委托的情况下不能使用,那么这可能会非常麻烦。突然减少变更代表:
class HomeView: UIView {
weak var delegate: HomeViewDelegate?
func renderView() {
guard let delegate = delegate else {
//Timmy: this should never happen!
return
}
let category = delegate.currentlySelectedCategory()
categoryView.render(category: category)
delegate.homeViewDidUpdate()
}
}
但是, weak
不是打破参考周期的唯一方法。 就像在捕获列表中一样,关键字unowned
可以在属性中使用以创建非强引用:
unowned let delegate: HomeViewModelDelegate
与weak
引用不同, unowned
引用应始终具有价值。 这样,您不仅可以在声明非可选类型时使用它们,而且还可以通过let
来使用它们,从而恢复不变性并确保您的对象不会以意外的方式起作用:
class HomeView: UIView {
private unowned let delegate: HomeViewDelegate
init(delegate: HomeViewDelegate) {
self.delegate = delegate
}
func renderView() {
let category = delegate.currentlySelectedCategory()
categoryView.render(category: category)
delegate.homeViewDidUpdate()
}
}
使用weak
,没有任何事情可以阻止HomeView
在没有委托的情况下使用,并且由于关键字的可选要求,需要guard
措施以解包从委托检索的值。 另一方面, unowned
可让您打破参考周期,同时仍然像强大一样使用参考。
但是,请注意, unowned
属性将与捕获列表关键字一样工作。 如果您尝试访问已取消分配的未拥有引用,则您的应用将崩溃。
如果保证您的对象永远不会超过其无主引用(例如,像ViewModel
),则使用unowned
可以极大地提高代码质量和性能。
但是, unowned
可能会使您的应用崩溃,就像隐式展开的可选属性一样。 您不应该对所有事物都使用weak
吗?
大多数人都依赖于weak
,而由于其潜在的崩溃,尤其是在捕获列表上,他们都对weak
unowned
。 这是使用Swift的安全方法,但不是Apple的预期做法。
与隐式展开的可选选项(我认为这只是解决体系结构问题的一种懒惰方法)不同, unowned
引用比weak
引用有显着优势:它们具有更好的性能,允许不变性,并且由于不能手动将其设置为nil
,因此您的代码不会意外地遵循意外路径。 unowned
引用绝对是安全的-仅当您滥用关键字时才会出现问题。
根据Apple的说法,当对象不能超过其引用时,应始终使用未拥有的引用:
仅当确定引用始终引用尚未取消分配的实例时,才使用无主引用。
如果在释放该实例后尝试访问一个未拥有的引用的值,则会收到运行时错误。
如果捕获的引用永远不会为零,则应始终将其捕获为未拥有的引用,而不是弱引用。
在任何其他情况下,您应继续使用weak
引用。
还有什么?
下次创建委托或@escaping
闭包时,请考虑其上下文,并查看它是否有可能超过其引用。 如果不是这样,您可能会发现未unowned
属性是提高代码质量的有趣工具。
参考文献和优秀读物
Apple Docs:ARC和关键字
- 我如何知道我的iOS应用程序的手机访问是否被禁用?
- 在iPhone上为RTL语言翻转布局
- iOS点击时将表格视图单元格全屏显示
- 触摸表视图单元格后的第一个方法didSelectRowAtIndexPath还是prepareforSegue?
- 我应该如何在Swift中使用NSSetUncaughtExceptionHandler
- dyld:Library未加载:@ rpath / SwiftyJSON.framework / SwiftyJSON
- 无法通过iOS SDK和原生Facebook应用程序对Facebook进行身份validation
- codesign_allocate:错误:无法find实用程序“codesign_allocate”,而不是开发人员工具或PATH
- 如何检索使用XMPP框架的会员聊天室列表?