2017-06-04 32 views
0

讓我們假設我們有一個UITableViewControllerdidSelectRowAtSection加載一個類的實例,即命名爲:ClassToInject,並希望通過物業注入注入,因爲我們ViewControllerToBePushedClassToInject的屬性,即隨後在didSet回調(因爲它是一個UITabBarViewController),它搜索符合ClassToInjectPresentable簡單,因爲它所有的財產viewControllersSwinject注入自身的財產到新的UIViewController

protocol ClassToInjectPresentable { 
    var property: ClassToInject { get set } 
} 

到現在爲止,我只想做這樣的事情:

func didSelectRowAtIndexPath { 
    let classToInject = self.loadClassToInjectFor(indexPath) 
    let tabBarViewController = SomeTabBarViewController() 
    tabBarViewController.property = classToInject 
    self.navigationController.push(tabBarViewController, animated: true) 
} 

而且在SomeTabBarViewController ...

class SomeTabBarViewController: ClassToInjectPresentable { 
    var property: ClassToInject? { 
    didSet(newValue) { 
     self.viewControllers.filter{ $0 is ClassToInjectPresentable }.map{ $0 as! ClassToInjectPresentable }.forEach{ $0.property = newValue } 
    } 
} 

,一切都應該得到加載好和容易(但它不是)。我已閱讀Swinject,這可能會解決它。我見過很多例子註冊了諸如:

container.register(Animal.self) { _ in Cat(name: "Mimi") } 

但我不知道我是否可以註冊在self加載某些屬性:

container.register(ClassToInjectInjector.self) { _ in 
self.loadClassToInjectFor(indexPath) } 
// And then 
container.register(ClassToInjectPresentable.self) { _ in 
SomeTabBarViewController() } 
    .initCompleted { r, p in 
     let tabBar = p as! SomeTabBarViewController 
     tabBar.property = r.resolve(ClassToInjectInjector.self) 
     // And lastly? 
     self.navigationController.pushViewController(tabBar, animated: true) 
    } 
} 

回答

0

最後,我按照提出的建議得到了最終的答案。

public class Containers { 
    fileprivate init() { } 
} 

extension Containers { 
    static let activityPresentableContainer: Container = { 
     let container = Container() 
     container.register(ActivityTabBarController.self) { (r: Resolver, arg1: Activity) in 
      return ActivityTabBarController(activity: arg1) 
     } 
     container.register(ActivityPresentable.self) { 
      (r: Resolver, arg1: ActivityPresentableTabs, arg2: Activity) in 
      switch arg1 { 
      case .summary: 
       return ActivitySummaryViewController(activity: arg2) 
      case .detail: 
       return ActivityDetailPageViewController(activity: arg2) 
      case .map: 
       return ActivityMapViewController(activity: arg2) 
      case .charts: 
       return ActivityChartsViewController(activity: arg2) 
      case .strava: 
       return ActivityStravaViewController(activity: arg2) 
      } 
     }.inObjectScope(.transient) 
     return container 
    }() 

通過這種方法,命名ActivityTabBarController得到總是由activityPresentableContainer使用下面的語句實例:

let controller = Containers.activityPresentableContainer.resolve(
    ActivityTabBarController.self, argument: activity 
)! 

然後,每個TabBarController內的卡的使用所需的參數被實例化Activity和使用.transient上下文的選項卡類型。它解決這樣的:

let activitySummary = Containers.activityPresentableContainer.resolve(
    ActivityPresentable.self, arguments: ActivityPresentableTabs.summary, activity! 
) as! UIViewController 

這樣我可以概括取決於只是,他們正在使用的信息標籤欄的選項卡。如果其中一個選項卡隨時更改,我可以按照ActivityPresentable協議更改註冊。

2

這是很難推薦合適的解決方案,而知道你的應用程序的細節,但這裏有一些建議:

container.register(ClassToInjectInjector.self) { _ in 
    self.loadClassToInjectFor(indexPath) 
} 

一般來說,所有register -ations應你的對象之外進行。常見的設置有一個全局的Container,其中包含所有註冊 - 您應該將它們看作指令來構建沒有任何隱式上下文的應用程序對象。如果你的依賴需要在UITableViewController被創建,你可以將它傳遞給resolve方法作爲參數:

container.register(ClassToInjectPresentable.self) { resolver, property in 
    let tabBar = SomeTabBarViewController() 
    tabBar.property = property 
    return tabBar 
} 

// in UItableVIewController 
container.resolve(ClassToInjectPresentable.self, 
        argument: self.loadClassToInjectFor(indexPath)) 

而且這通常是一個壞主意:

.initCompleted { r, p in 
    ... 
    self.navigationController.pushViewController(tabBar, animated: true) 
} 

你不應該混合應用程序邏輯與DI - 使用Swinject純粹是爲了構建你的依賴關係。

所以你UITableViewController可能是這個樣子:

func didSelectRowAtIndexPath { 
    let classToInject = self.loadClassToInjectFor(indexPath) 
    let tabBar = container.resolve(
     SomeTabBarViewController.self, argument: loadClassToInjectFor(indexPath) 
    ) 
    navigationController.push(tabBar, animated: true) 
} 

至於你TabBar和視圖控制器:怎麼辦UIViewControllers進入TabBar?是否有可能做這樣的事情?

class SomeTabBarViewController { 
    init(viewControllers: [UIViewController]) { 
     ... 
    } 
} 

container.register(SomeTabBarViewController.self) { r, property 
    SomeTabBarViewController(viewControllers:[ 
     r.resolve(MyViewController.self, argument: property), 
     r.resolve(MyViewController2.self, argument: property) 
    ]) 
} 
+0

'tabBar.property = injector'從哪裏來? –

+0

對不起,它的意思是'tabBar.property = property'。我已經更新了一個答案 –