Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 用台风两次注入相同性质_Swift_Dependency Injection_Typhoon - Fatal编程技术网

Swift 用台风两次注入相同性质

Swift 用台风两次注入相同性质,swift,dependency-injection,typhoon,Swift,Dependency Injection,Typhoon,我正计划在一个新创建的项目中引入依赖注入框架,并且已经找到了看起来非常好的框架(除了在Swift中引用方法和属性时必须使用字符串)。它似乎很适合我的应用程序,但我在处理网络请求时遇到了一个问题 所有我的视图控制器(需要网络访问)都继承自ServiceViewController,我使用该控制器延迟初始化服务(此上下文中的服务是用于处理网络通信的类): 这种方法有两个缺点: 取消所有任务(或类似任务)需要呼叫所有服务 服务不再在需要时延迟初始化 Ad 1)现在处理cancelAllPendingT

我正计划在一个新创建的项目中引入依赖注入框架,并且已经找到了看起来非常好的框架(除了在Swift中引用方法和属性时必须使用字符串)。它似乎很适合我的应用程序,但我在处理网络请求时遇到了一个问题

所有我的视图控制器(需要网络访问)都继承自
ServiceViewController
,我使用该控制器延迟初始化服务(此上下文中的服务是用于处理网络通信的类):

这种方法有两个缺点:

  • 取消所有任务(或类似任务)需要呼叫所有服务
  • 服务不再在需要时延迟初始化
  • Ad 1)现在处理
    cancelAllPendingTasks()
    的一种方法是将这两个服务从初始值设定项添加到
    ServiceViewController.services
    列表中。然后,
    cancelAllPendingTasks()
    将能够访问所有服务。但我正在寻找一种方法来避免这样做,这样以后添加服务就不需要“记住做这个和那个”

    Ad 2)我看不到依赖项注入有什么办法可以做到这一点。但我不认为这是一个大问题,因为服务的内存占用可能不太值得注意:-)

    因此,我的问题是:我能否以某种方式将服务同时注入构造函数和服务列表

    编辑:
    当我从@Jasperblus的回答中发现,很容易将同一对象两次注入属性和初始值设定项时,我的第二个担忧引起了我更多的关注:如果我们将一组服务注入初始值设定项,但忘记将完全相同的服务注入数组(例如,我们忘记了其中一个),我们将很难找到bug,因为在有一天,
    hasPendingTasks
    方法返回错误的结果之前,没有人会发现它,因此有些东西会挂起。在我最初的设计中,这是一个不可能的场景,但是如果我们要注入两次服务,我们会突然得到一个容易出错的重复。

    Typhone允许您选择使用初始值设定项注入(或不注入)以及以下任何一项:

    • 属性注入
    • 方法注入(具有一个或多个参数)
    • 其他配置,例如指定要在注入发生后调用的回调方法或设置范围
    如果已经通过初始值设定项设置了属性,那么使用属性注入是没有问题的

    对于同一个方法,可以多次调用方法注入。(例如,收集日志目录名称的方法)


    中的显示了将初始值设定项注入与属性注入混合的示例。显示了如何进行方法注入、设置范围或在注入发生后调用回调方法

    在对我的问题进行了更多的研究并实施了台风之后,我有一些想法要分享:

  • 很容易将对象注入两次:

    public dynamic func myViewController() -> AnyObject {
        return TyphoonDefinition.withClass(MyViewController.self) {
            $0.useInitializer("initWithAccountService:postingService:") {
                $0.injectParameterWith(self.accountService())
                $0.injectParameterWith(self.postingService())
            }
            $0.injectProperty("services", with:[self.accountService(), self.postingService()])
        }
    }
    
    这将两次注入相同的对象,并且不会创建accountService和postingService的两个实例。在读到@jasperbluse'的答案之前,我并不清楚这一点

  • 我对accountService和postingService重复注入的担忧实际上很容易克服。我只是再次删除了初始值设定项,并返回使用
    getService()
    方法。因此,我的程序集现在看起来如下所示:

    public dynamic func myViewController() -> AnyObject {
         return TyphoonDefinition.withClass(MyViewController.self) {
             $0.injectProperty("services", with:[self.accountService(), self.postingService()])
         }
    }
    
    上面的方法填充了
    services
    数组,因此
    getService()
    方法将从该数组返回正确的注入对象

  • 关于延迟初始化的第三个问题实际上仍然可以通过简单地不注入服务而直接在代码中创建服务来克服。毕竟,因为可以注入这些服务,所以测试它们仍然很容易。尽管如此,由于其他问题,例如在一个地方指定依赖项,即程序集:-),注入它们可能会更好


  • 但毕竟,这是一次很好的学习经历,台风现在正进入我的项目:-)

    是的,不幸的是,Swift在Objective-C互操作性之外没有选择器的概念,甚至没有反射和动态方法拦截的概念。因此,在台风中使用Swift的规则与使用KVO等可可风格功能的规则相同。我没有完全理解您正在权衡的架构问题。如果有必要,我可以进一步研究,但我想我已经抓住了问题的要点了?我想我知道你的意思:所以我应该将我的服务注入初始值设定项和服务数组,从而将“重复代码”移动到程序集。也就是说,让程序集为属性注入和初始值设定项注入指定相同的对象。这是可以接受的,尽管我更喜欢一个不需要注入两次对象的想法。特别是因为如果我们忘记初始化数组,没有人会发现。您可以将初始值设定项注入与属性方法注入混合匹配。这很常见。即使重复你自己也可以。(属性在init之后,然后是方法)。至于你为什么要重复?这是我没听进去的部分。我会再看一遍这个问题。是的,你实际上回答了我的问题,其中没有提到关于无法注入服务阵列的问题。我的担心主要是因为当我们必须用相同的对象初始化两个不同的属性时,会出现错误。未能正确初始化数组将导致难以找到错误,因为“hasPendingTasks”方法不可靠
    public dynamic func myViewController() -> AnyObject {
        return TyphoonDefinition.withClass(MyViewController.self) {
            $0.useInitializer("initWithAccountService:postingService:") {
                $0.injectParameterWith(self.accountService())
                $0.injectParameterWith(self.postingService())
            }
            $0.injectProperty("services", with:[self.accountService(), self.postingService()])
        }
    }
    
    public dynamic func myViewController() -> AnyObject {
         return TyphoonDefinition.withClass(MyViewController.self) {
             $0.injectProperty("services", with:[self.accountService(), self.postingService()])
         }
    }