2016-09-22 60 views
1

這個問題是針對Swift有很多Swinject經驗的人。爲什麼在沒有「.inObjectScope(.Container)」的情況下注冊Swinject模型類會生成單例?

我會顯示有問題的代碼,我的問題在底部。

有很多代碼,對此很抱歉。

這是MySwinjectStoryboard.swift登記:

import Swinject 

extension SwinjectStoryboard 
{ 
    class func setup() 
    { 
     defaultContainer.register(Stopwatch.self) 
     { 
      responder in Stopwatch( 
       signals: responder.resolve(SignalsService.self)! 
      ) 
     } 

     defaultContainer.register(SignalsService.self) 
     { 
      _ in SignalsService() 
     }.inObjectScope(.Container) 

     defaultContainer.register(ImageService.self) 
     { 
      responder in ImageService(
       signals: responder.resolve(SignalsService.self)! 
       , stopwatch: responder.resolve(Stopwatch.self)! 
      ) 
     }.inObjectScope(.Container) 

     defaultContainer.registerForStoryboard(StartUpViewController.self) 
     { 
      resolvable, viewController in 
      viewController.stopwatch = resolvable.resolve(Stopwatch.self)! 
      viewController.image = resolvable.resolve(ImageService.self)! 
     } 
    } 
} 

這是Stopwatch.swift,發射的onComplete處理程序之前,其簡單地暫停一會兒:

import Foundation 

class Stopwatch: StopwatchProtocol 
{ 
    var key: String { return "Stopwatch_\(_key).Complete" } 

    private var 
    _signals: SignalsProtocol 
    , _key: UInt16 
    , _timer: NSTimer? 
    , _data: AnyObject? 

    func startWith ( 
     Delay delay: Double 
     , ForListener closure: (String, Any?) -> Void 
    ){ 
     _data = nil 
     _startWith(Delay: delay, ForListener: closure) 
    } 

    func stop() 
    { 
     guard let timer = _timer else { return } 
     timer.invalidate() 
     _timer = nil 
     _data = nil 
    } 

    private func _startWith ( 
     Delay delay: Double 
     , ForListener closure: (String, Any?) -> Void 
    ){ 
     stop() 

     _timer = NSTimer.scheduledTimerWithTimeInterval(
      NSTimeInterval(delay) 
      , target: self 
      , selector: #selector(_onTimerComplete) 
      , userInfo: nil 
      , repeats: false 
     ) 
    } 

    @objc private func _onTimerComplete() 
    { 
     stop() 
     print("stopwatch with key `\(key)` complete.") 
    } 

    required init (signals: SignalsProtocol) 
    { 
     _signals = signals 
     _key = getPrimaryKey() 
     print("primary key: \(_key)") 
    } 
} 

ImageService.swift目前只是接受經由一個信號和秒錶屬性init功能:

protocol ImageProtocol {} 

class ImageService: ImageProtocol 
{ 
    private let 
    _signals: SignalsProtocol 
    , _stopwatch: StopwatchProtocol 

    required init ( 
    signals: SignalsProtocol 
    , stopwatch: StopwatchProtocol 
){ 
     _signals = signals 
     _stopwatch = stopwatch 

     lo("ImageService key: \(_stopwatch.key)") 
    } 
} 

SignalsService.swift目前是空的模型類:

protocol SignalsProtocol {} 

class SignalsService: SignalsProtocol {} 

雖然StartUpViewController.swift是一個基本的UIViewController,目前只接受其注入的屬性:

import UIKit 

class StartUpViewController: UIViewController 
{ 
    var image: ImageService? { 
     willSet { 
      guard _image == nil else { return } 
      _image = newValue 
     } 
    } 

    var signals: SignalsService? { 
     willSet { 
      guard _signals == nil else { return } 
      _signals = newValue 
     } 
    } 

    var stopwatch: StopwatchProtocol? { 
     willSet { 
      guard _stopwatch == nil else { return } 
      _stopwatch = newValue 
      print("StartUpViewController key: \(_stopwatch.key)") 
     } 
    } 

    internal var 
    _image: ImageService! 
    , _signals: SignalsService! 
    , _stopwatch: Stopwatch!  
} 

最後getPrivateKey()簡直是一個全球性的靜態,返回獨特Ints:

private var _primaryKey = UInt16(0) 

func getPrimaryKey() -> UInt16 
{ 
    _primaryKey += 1 
    return _primaryKey 
} 

現在據我所知,我在MySwinjectStoryboard.swift中註冊Stopwatch.swift的方式意味着每次實例被注入時,它將成爲一個新的離散實例。然而,無論ImageService.swiftStartUpViewController.swift被注入相同的實例:

StartUpViewController key: Stopwatch_2.Complete 
ImageService key: Stopwatch_2.Complete 

ImageService的重點應該是:

ImageService key: Stopwatch_3.Complete 

有誰知道爲什麼發生這種情況,好嗎?謝謝。

回答

3

服務的默認範圍是.Graph。從documentation

隨着ObjectScope.Graph,實例總是在ObjectScope.None創建,如,如果你直接調用一個容器的解決方法,但在工廠倒閉解決實例根的解析過程中被共享實例來構造對象圖。

如果你想爲每個參考即使在對象圖的分辨率來創建一個唯一的實例,你應該使用對象範圍.None,即

defaultContainer.register(Stopwatch.self) { resolver in 
    Stopwatch(signals: resolver.resolve(SignalsService.self)!) 
}.inObjectScope(.None) 
+0

謝謝雅各! –

相關問題