我计划在一个新创建的项目中引入一个依赖注入框架,并且发现Typhoon看起来非常不错(除了在 Swift 中引用方法和属性时必须使用字符串)。它通常似乎很适合我的应用程序,但是我为处理网络请求所做的构造存在问题。
我所有的视图控制器(需要网络访问)都继承自一个ServiceViewController
用于延迟初始化服务的视图控制器(此上下文中的服务是一个用于处理网络通信的类):
class ServiceViewController {
var services = [BDService]()//a list of (lazily initialized) services used by the the view controller
//create a service of the specified type (or return from the existing list if it has already been created)
func getService<T : BDService>() -> T {
for service in services {
if service is T {
return service as T
}
}
let klass : T.Type = T.self
let newService : T = klass()//don't ask - due to Swift bug: http://stackoverflow.com/questions/27336607
services.append(newService)
return newService
}
//tell all initialized services to cancel pending requests
func cancelAllPendingTasks() {
services.each { $0.cancelPendingTasks() }
}
//inform whether a request has been sent and we are still waiting for a response
func hasPendingTasks() -> Bool {
return services.any { $0.pendingTasks.count > 0 }
}
}
....
//usage from MyViewController:
let accountService : BDAccountService = super.getService()
/* do something on accountService */
...
let postingService : BDPostingService = super.getService()
/* do something on postingService */
...
super.cancelAllPendingTasks() //e.g. if user clicks back button
最后一个方法cancelPendingTasks
和hasPendingTasks
是我想要保留这个架构的原因。通过将 ViewController 的所有服务放在一个列表中,我们可以确保我们不会忘记取消其中一项服务上的待处理任务。
现在,当我想引入 Typhoon 时,我可以在初始化程序中注入我所有的服务:
public dynamic func myViewController() -> AnyObject {
return TyphoonDefinition.withClass(MyViewController.self) {
(definition) in
definition.useInitializer("initWithAccountService:postingService:") {//(forgive me if I wrote this wrong)
(initializer) in
initializer.injectParameterWith(self.accountService())
initializer.injectParameterWith(self.postingService())
}
}
}
这种方法有两个缺点:
- 取消所有任务(或类似任务)需要调用所有服务
- 服务不再在需要时延迟初始化
广告 1) 处理 now 的一种方法是将这两个服务从初始化程序cancelAllPendingTasks()
添加到列表中。ServiceViewController.services
然后cancelAllPendingTasks()
将能够访问所有服务。但我正在寻找一种避免这样做的方法,这样以后添加服务就不需要“记住做这个和那个”
广告 2)我没有看到通过依赖注入来做到这一点的方法。但我不认为这是一个大问题,因为服务的内存占用可能不那么值得注意:-)
所以我的问题是:我可以以某种方式将服务同时注入构造函数和服务列表吗?
编辑:
当我从@JasperBlues 的回答中发现很容易将同一个对象两次注入属性和初始化程序时,我的第二个问题引起了我的更多关注:如果我们将一堆服务注入到初始化程序中,但忘记注入完全相同的服务放入数组中(例如我们忘记了其中一个),我们会遇到非常难以发现的错误,因为在hasPendingTasks
某天方法返回错误结果之前,没有人会发现它,并且因此而挂起。这在我的原始设计中是不可能的,但如果我们应该注入两次服务,我们会突然得到一个容易出错的重复。