Design patterns swift:带闭包的最佳设计,避免强引用循环
假设你有两门课。第一个类有一组小函数,它们通常相互组合使用。因为这些函数需要访问共享资源,所以将它们组合在一起更有效 要调用这些小函数,需要对类进行引用。有两种方法可以做到这一点Design patterns swift:带闭包的最佳设计,避免强引用循环,design-patterns,swift,Design Patterns,Swift,假设你有两门课。第一个类有一组小函数,它们通常相互组合使用。因为这些函数需要访问共享资源,所以将它们组合在一起更有效 要调用这些小函数,需要对类进行引用。有两种方法可以做到这一点 class FirstClass { // lots of small functions ... func doWork(){} //group function that takes a closure func transactionsA(workUnit : ()->(NSError
class FirstClass
{
// lots of small functions
...
func doWork(){}
//group function that takes a closure
func transactionsA(workUnit : ()->(NSError?)) -> NSError?
{
//obtain access to shared resource
...
//do work
workUnit()
//close access to shared resource
...
}
func transactionsB(workUnit : (let instanceOfFirstClass)->(NSError?)) -> NSError?
{
//obtain access to shared resource
...
//do work
workUnit(self)
//close access to shared resource
...
}
}
class SecondClass
{
let instanceOfFirstClass = FirstClass()
//first approach
func doGroupWorkA()
{
instanceOfFirstClass.transactionsA() {[unowned self] () -> (Error?) in
self.instanceOfFirstClass.doWork()
}
}
//second approach
func doGroupWorkA()
{
instanceOfFirstClass.transactionsB() {[unowned self]
(let instanceOfFirstClass) -> (Error?) in
//do the actual work via the smaller functions
instanceOfFirstClass.doWork()
}
}
}
在第一种方法中,您只需通过self.instanceOfFirstClass调用函数,但在第二种方法中,您获得实例作为闭包的参数
可能差别不大,但哪种方法更好?是否存在创建参考周期的风险
我的具体用例是一个小的SQLite包装器
编辑:以扩展我的特定用例,尽管我认为问题和答案应该更广泛:
第一个类是SQLite包装器。它直接与数据库对话(打开/关闭连接,创建/准备/绑定SQL查询,如fetch和insert)
SecondClass可以是需要存储或检索数据的任何类。为了利用事务,我需要对查询进行分组。DoWork()类似于开始事务、循环(获取、处理、插入)、提交/结束事务
事务功能还可以在适当的时候打开和关闭数据库连接。这避免了连接在应用程序的整个期间或文档的整个生存期内保持打开但处于空闲状态
如果出现错误,事务将回滚,连接将关闭。这个问题令人困惑,但感觉您正在重新创建
调度队列
(特别是串行队列)和调度组
。还不清楚如何利用返回的错误,这对模式的意义有很大影响。目前,我在Swift中解决这类问题的首选方法是未来对象(例如:),但我不确定这是否适用,因为我不太清楚您是如何使用FirstClass和SecondClass的。不,我没有在这些类中直接使用队列。所有这些工作都已经在私有队列上进行了。由于这都是串行工作,所以没有必要再增加一个串行调度队列。当工作可以序列化时,使用_enter、_leave和_wait来调度组是很好的。与此处这样的共享资源交谈时,情况并非如此。我不完全确定你们未来的课程是做什么的。它看起来像一个带回调的异步队列?Future类的要点是表示可能失败的计算的未来值。您可以对其应用其他计算,这些计算将在其完成时执行(如果失败,则自动跳过)。关于队列,由于队列可以针对其他队列,并且队列可以挂起,等待其所有块就位(其本身可以通过组进行管理),GCD为您描述的内容提供了强大的工具,而不仅仅是介绍性的“在后台运行某样东西”。但对于您更深层次的问题,我的建议是将所需的实际数据从self
复制到一个不可变的结构中,然后放入处理中。这就摆脱了我认为你会遇到的所有尴尬。将这些操作视为纯函数,并将它们放入操作中(理想情况下甚至是NSOperation
),而不是尝试与self
之类的对象进行交互。我用GCD做了一些事情,但从未针对其他队列。是时候开始一个玩具项目了。:)但self是启动处理的对象。self(即firstObject)有一个接受闭包的函数。闭包做了一些工作,但为了做到这一点,需要调用self函数。为什么我不想与自我互动?它只是本地实例对象。这就像说不要对另一个类的实例调用函数。无论如何,这两种方法都有效(在我有限的测试中)。我只是想知道哪一个是正确的方法。