4

segues로 작업 할 때보기 컨트롤러에서 DI를 구현하는 우아한 방법을 찾고 있습니다. 컨트롤러 A를 가지고 컨트롤러 B를로드하면이 동작을 단위 테스트하고 싶습니다. 그것을 구현하는 좋은 방법은 무엇입니까?iOS - UIViewController의 종속성 삽입

답변

1

경량 Typhoon 종속성 주입 라이브러리를 사용해보십시오. Typhoon은 Objective-C 런타임의 메시지 전달 기능을 활용하여 작동합니다. 다음과 같이 하나 이상의 '어셈블리'를 정의 할 수 있습니다.

  • 빌드 타임 어셈블리에서 구성 요소를 어셈블하기위한 방법은 TyphoonDefinition입니다.
  • 런타임시 빌드 인터페이스를 사용하여 정의 된 규칙에 따라 종속성이 주입 된 빌드 된 구성 요소를 확인합니다.

예 : ApplicationAssembly.swift 의존성 삽입 (Dependency Injection)의이 스타일은 비 침습적하고 (같은 종류의 여러 구성 요소에 대한 몇 가지 유형 중심의 DI 라이브러리에 제한을 허용하도록 설계되었습니다

public class ApplicationAssembly: TyphoonAssembly { 

    /* 
    * These are modules - assemblies collaborate to provie components to this one. 
    * At runtime you can instantiate Typhoon with any assembly that satisfies the 
    * module interface. 
    */ 
    var coreComponents : CoreComponents! 
    var themeAssembly : ThemeAssembly! 


    public dynamic func weatherReportController() -> AnyObject { 

     return TyphoonDefinition.withClass(WeatherReportViewController.self) { 
      (definition) in 

      definition.useInitializer("initWithWeatherClient:weatherReportDao:cityDao:assembly:") { 
       (initializer) in 

       initializer.injectParameterWith(self.coreComponents.weatherClient()) 
       initializer.injectParameterWith(self.coreComponents.weatherReportDao()) 
       initializer.injectParameterWith(self.coreComponents.cityDao()) 
       initializer.injectParameterWith(self) 

      } 
     }; 
    } 

    public dynamic func addCityViewController() -> AnyObject { 

     return TyphoonDefinition.withClass(AddCityViewController.self) { 
      (definition) in 

      definition.useInitializer("initWithNibName:bundle:") { 
       (initializer) in 

       initializer.injectParameterWith("AddCity") 
       initializer.injectParameterWith(NSBundle.mainBundle()) 
      } 
      definition.injectProperty("cityDao", with:self.coreComponents.cityDao()) 
      definition.injectProperty("weatherClient", with:self.coreComponents.weatherClient()) 
      definition.injectProperty("theme", with:self.themeAssembly.currentTheme()) 
      definition.injectProperty("rootViewController", with:self.rootViewController()) 
     }     
    } 
} 

), IDE 코드 완성 및 리팩토링을 허용하는 동시에. 또한 "마법의 문자열"을 사용하지 않도록합니다 (불행히도 Swift에서는 선택자 문자열 임).


하나에서 다른 제어기로 진행하기 : 우리는 WeatherReportController assembly.citiesListController을 호출하여 CitiesListController를 제시 할 수 있도록

조립 자체가 주입 될 수있다. Typhoon의 runtime-arguments을 사용하여 정적 및 런타임 종속성을 혼합 할 수도 있습니다. 이렇게하면 수동으로 자체 공장을 작성해야하는 부담을 덜어줍니다.

스토리 보드 : 스토리 보드 segues, 태풍의 속성 또는 method dependencies can be injected as part of the segue를 들어

.

enter image description here

태풍 스위프트 또는 목표 - C와 함께 작동 및 Russia

테스트 호주, 일본에서 특히 인기가 :

여기에 스토리 보드와 뷰 컨트롤러 로직을 테스트하는 방법과 의존성 주입.

유닛 테스트에서는 UIStoryboard 하위 클래스를 "스토리 보드"속성으로 삽입 할 수 있습니다 (읽기 전용 속성이므로 setValue : forKey를 시도하십시오. 그렇지 않으면 UIStoryboard 하위 클래스에서 viewController를 인스턴스화 할 수 있습니다. 훨씬 더 자세한 정보) .storyboard 속성을 대체 한 후 "instantiateViewControllerForStoryboardIdentifier"메소드를 스파이하고 올바른 식별자로 호출했는지 확인할 수 있습니다.

3

스토리 보드를 사용할 때 "생성자"주입을 사용하는 것이 쉬운 방법이라면 정말 도움이 될 것입니다.하지만 슬프게도 프레임 워크가 우리를 위해 VC 초기화를 처리하고 있기 때문에 슬프게도 없습니다.

일반적으로 프로젝트의 크기와 컨텍스트에 따라 Typhoon과 같은 본격적인 프레임 워크 (내 경험으로는 매우 뛰어남)로 이동하거나 중개자를 사용하여 모든 섹그를 처리하는 것과 같은 간단한 작업을 수행 할 수 있습니다 VC 사이.

내가 여기 후자의 방법에 대해 서면으로 작성했습니다 : 특히 http://cocoapatterns.com/ios-view-controller-transitions-mediator-pattern/

여기 http://cocoapatterns.com/passing-data-between-view-controllers/ 및 국가 디자인 패턴과 결합은, 중재자는 segues 동안 주입을 처리하기위한 중앙 방법을 제공하고 또한 유지 보수 및 확장에 도움 코드베이스.