ã誰ããèªåã®VIPERãæã£ãŠããŸããã äžæãªèèãã®èšäºã§ã¯ãVIPERã¢ãŒããã¯ãã£ãŒãå°ããªå ·äœäŸã§æ€èšããããšæããŸããããã¯åæã«ããã®ã¢ãŒããã¯ãã£ãŒã®å šèœåã瀺ããææ°ã®Swift 4ã§æžãããŠããŸãã èšäºå šäœãèªãŸãã«ããã«ã³ãŒããèŠãã人ã®ããã«ãã©ãããžã®ãªã³ã¯ã¯äžçªäžã«ãããŸãã
![](https://habrastorage.org/webt/s6/pq/m1/s6pqm1b7m1cus4abpufcmjphlz0.jpeg)
ç®æ¬¡
- ãšã³ããªãŒ
- 第0ç« ãVIPERã¢ãŒããã¯ãã£ã¹ããŒã
- 第1ç« éåžžã«åçŽãªã¢ãžã¥ãŒã«ã®äŸ
- 第2ç« ããè€éãªã¢ãžã¥ãŒã«ã®äŸ
- ãããã«
- ãªããžããªãªã³ã¯
ãšã³ããªãŒ
HabreïŒ 1ã2 ïŒãªã©ã VIPERã®ã¢ãŒããã¯ãã£ã«ã€ããŠã¯ããªãå€ãã®ããšãæžãããŠããŸãã
ãããã£ãŠãéçºè ã¯ã SOLIDã®ååïŒç¹ã«ã å¯äžã®è²¬ä»»ã®åå ãïŒãšæŽåæ§ã®ãããæè»æ§ã®é«ãç°ãªãã¢ãŒããã¯ãã£ãšã ã¯ãªãŒã³ãªã¢ãŒããã¯ãã£ ïŒ ãã·ã¢èªã®ã¬ãã¥ãŒ ïŒãå¿ èŠã§ããã
ã©ã³ãã©ãŒã¯ãã®ãããã¯ãåãäžãã äŒè°å šäœãããã«æ§ããããã«ã¯æ¬ãæžããŸããã ãšããã§ãVIPERã«æ £ããŠããªãå Žåã¯ããã®æ¬ãã¢ãŒããã¯ãã£ã®çŽ¹ä»ãšããŠèªãããšããå§ãããŸãã ãã®VIPERãäœã®ããã«å¿ èŠãªã®ããã©ã®ããã«è¡šç€ºãããã®ãããã説æããåãã§ããŸãã ãã®æ¬ã¯ãå€å žçãªVIPERã®åé¡ãããã³Ramblerã®éçºè ããã®äžã§å°ãå€æŽããããšã«ã€ããŠã説æããŠããŸãã æ®å¿µãªããããã®æ¬ã¯2016幎ã«æžãããŠããããã®äŸã¯Objective-Cãšãã®ãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã«é¢ãããã®ã§ãã ãã®ãããžã§ã¯ãã¯ãå€ãã®è¿œå äºé ãéå°ãªæœè±¡åãããã³å€ãããã¯ã©ã¹ã§ãã³ã°ããŠããŸãã äžèŠãè€éãããŠåçºçã«èŠãããããããŸããã
ãããã£ãŠãVIPERã¢ãŒããã¯ãã£ã§å°ããªã¢ããªã±ãŒã·ã§ã³ã é貚ã³ã³ããŒã¿ãŒ ããäœæããåã¬ã€ã€ãŒã§èšè¿°ããå¿ èŠããããã®ãšãåã¬ã€ã€ãŒã«èšå®ãããŠããã«ãŒã«ã瀺ããŸããã ç§ã¯ããããããããã䜿çšããªãã£ããšããã«èšãããã¹ãã§ã ã©ã³ãã©ãŒã®çµéšãšãã®äŸã«è§Šçºããããå€å žçãªVIPERãšãã®ãããã«å€æŽãããããŒãžã§ã³ã
Swiftã§ãã£ãšãšã¬ã¬ã³ãã«äœããæžãããã©ããã¯ãæå¥ãèšããªãã§ãã ããã ããã§ãããã®èšäºã¯å»ºç¯ã«é¢ãããã®ã§ããã Swiftèªäœã®çŸããã«é¢ãããã®ã§ã¯ãããŸããã ãŸããæå³çã«ãµãŒãããŒãã£ã®ã©ã€ãã©ãªãšäŸåé¢ä¿ã䜿çšããŸããã§ããã å šäœã®äŸã¯ããã€ãã£ãiOSã©ã€ãã©ãªã®ã¿ã䜿çšããŠèšè¿°ãããŠããŸãã
第0ç« ãVIPERã¢ãŒããã¯ãã£ã¹ããŒã
VIPERã®ååã«åºã¥ããŠã¯ã€ãã¯ã©ã³ãå®è¡ããŸãã 1ã€ã®ç»é¢ãŸãã¯æ£ç¢ºã«ã¯1ã€ã®View Controllerã¯ãVIPERã®1ã€ã®ã¢ãžã¥ãŒã«ã«å¯Ÿå¿ããå¿ èŠããããŸãã äžè¬ã«ãVIPERã¯ãé·ãéèŠåŽããŠããView Controllerãå€ãã®ã¬ã€ã€ãŒã«åå²ããããã«èšèšãããŠããããã¹ãŠã®ãŠãŒã¶ãŒãããããã®åœ¹å²ãæãããŸãã æŠç¥çã«ãã¢ãžã¥ãŒã«å ã®æ¥ç¶ãäžå³ã«ç€ºããŸãã
![](https://habrastorage.org/webt/hq/zy/cf/hqzycfexvow0y3tvihtwgqllz-u.jpeg)
ããããä»ã®ã¹ããŒã ãèŠãããšãããã§ãããã
ããã¯ãããšãã°ïŒ
![](https://habrastorage.org/files/66d/c26/871/66dc2687102a4df1aff7296d9321b476.png)
ç¥èªVIPERããã®åæåã¯äœããæå³ããŸãïŒé²èŠ§è â玹ä»è âåå ¥è âå®äœâ Rã¢ãŠã¿ãŒã ãããçŸå®ã«ã¯ããããã®ã³ã³ããŒãã³ãã ããã¢ãžã¥ãŒã«ã«å«ãŸããŠããããã§ã¯ãªãããšã³ãã£ãã£ã¯äžè¬ã«ã¢ãžã¥ãŒã«ã®æŠå¿µã«å«ãŸããŠããªãå¯èœæ§ããããŸãã ã¯ãä»»æã®ã¢ãžã¥ãŒã«ãŸãã¯ãµãŒãã¹ã§äœ¿çšã§ããèªå·±å®çµåã®ã¯ã©ã¹ã§ãã è€éãªç»é¢ã§ã¯ãã¢ãžã¥ãŒã«ããµãã¢ãžã¥ãŒã«ã«åå²ããããšãã§ããåãµãã¢ãžã¥ãŒã«ã«ã¯ç¬èªã®ãã¬ãŒã³ã¿ãŒãšã€ã³ã¿ã©ã¯ã¿ãŒããããŸãã
åŸæ¥ã®VIPERãšã¯ç°ãªããé±å±±ã«ã¯2ã€ã®åœ¹å²ãå®è¡ããããã WireframeããããŸãããã¢ãžã¥ãŒã«ãçµã¿ç«ãŠãå¥ã®ç»é¢ïŒã¢ãžã¥ãŒã«ïŒã«åãæ¿ããŸããã ãã®å³ã¯ã Configuratorãã¢ãžã¥ãŒã«ã®æ§ç¯ãæ åœãã Routerã移è¡ãæ åœããããšã瀺ããŠããŸãã Ramblerãããã®ããžãã¯ãæ¡çšããŸããããå¯äžã®éãã¯Configuratorã®ä»£ããã«Assemblyãããããšã§ãã ããããæ¬è³ªã¯åãã§ãã
Configuratorã¯ãã¢ãžã¥ãŒã«å ã®ãã¹ãŠã®äŸåé¢ä¿ãèªèããŠããŸãã ViewControllerã«ã¯Presenterãããã Presenterã«ã¯Interactorãªã©ãããããšã瀺ããŠããŸãã äŸã®åŸåã§ããã«è©³ããæ€èšããŸãã
ãŸããå€å žçãªVIPERã§ã¯ã ã»ã°ãšã¯æŸæ£ããããããã¹ããŒãªãŒããŒãã䜿çšããŠç»é¢ãåãæ¿ããããšã¯ã§ããŸããã ç§ãã¡ã®ã±ãŒã¹ã§ã¯ãRamblerãšåæ§ã«ã ã»ã°ãšãä»ãã移è¡ãæ©èœããAppleãæãã§ããããã«ã䜿çšãæšå¥šãããŸãã
ããŸããŸã100ïŒ ããã·ããã¥ãŒãView Controllerããäœæã§ããŸããã Appleèªäœã¯ãã©ã€ããµã€ã¯ã«ãšã¡ãœããïŒ viewDidLoad ã viewDidAppearãªã©ïŒã§ç¹å®ã®åœ¹å²ãæãããŠããããããããèæ ®ããããã«åºã¥ããŠã¢ãŒããã¯ãã£ãæ§ç¯ããå¿ èŠããããŸãã ã¢ãžã¥ãŒã«ã¢ã»ã³ããªã¯ãView Controllerãæ¢ã«åæåãããŠããã ãã§ãªãããã§ã«ããŒããããŠãããšãã«viewDidLoadããèµ·åãããŸãã ãŸããã¯ã©ã·ãã¯ããŒãžã§ã³ã§è¡ãããŠããAppDelegateã§ã¯ãªããã¹ããŒãªãŒããŒãããåæãã¥ãŒã³ã³ãããŒã©ãŒãèšå®ããæ©äŒãæäŸããŸãã ããã¯ãç¹å®ã®ãšã³ããªãã€ã³ããžã®å³å¯ãªãã€ã³ãããªããç°¡åã«å€æŽã§ãããããã¯ããã«äŸ¿å©ã§ãã
ã¢ãžã¥ãŒã«ãçµã¿ç«ãŠãåŸãã¢ãžã¥ãŒã«ã®ãããªãåäœã¯éåžžã«å€å žçã§ãã View / ViewController㯠ããã¿ã³ã®ã¯ãªãã¯ãããã¹ãå ¥åããŸãã¯UIãšã®ãã®ä»ã®å¯Ÿè©±ã®ããžãã¯ã«ã€ããŠè²¬ä»»ãè² ããŸããã ãããã¯ãã¹ãŠãããã«Presenterã«è»¢éãããŸãã ãã¥ãŒã¯ãã¢ãžã¥ãŒã«ã®äžéšãšããŠããŸãã¯å ±éã®ãã¥ãŒãšããŠãããŸããŸãªã¢ãžã¥ãŒã«ã§äœ¿çšã§ããŸãã
ãã¬ãŒã³ã¿ãŒã¯ãã¢ã¯ã·ã§ã³ã®ãªãã€ã¬ã¯ãå ãã«ãŒã¿ãŒãŸãã¯ã€ã³ã¿ãŒã¢ã¯ã¿ãŒã«æ±ºå®ããŸãã ã«ãŒã¿ãŒã¯çŸåšã®ç»é¢ãéããããæ°ããç»é¢ãéããŸãã é·ç§»ã®ç¹å®ã®å®è£ ã¯ããã®äžã§å®è¡ãããŸãã ã€ã³ã¿ã©ã¯ã¿ãŒã¯ãåä¿¡ããã€ãã³ããã©ã®ããã«åŠçããã©ã®ãµãŒãã¹ãåŒã³åºããã決å®ããŸãã ã¢ãžã¥ãŒã«ã®ããžãã¯ãå«ãŸããŠããŸãã
ãããã Presenterã®ããéèŠãªæ©èœã¯ããŠãŒã¶ãŒã«è¡šç€ºãããView / ViewControllerã®èŠèŠããŒã¿ã®æºåãšéä¿¡ã§ãã ãã¬ãŒã³ã¿ãŒã¯ã¢ãžã¥ãŒã«ã®äžå¿ã§ãããã©ã®ããŒã¿ãã©ã®ãããªåœ¢åŒã§è¡šç€ºãããããç¥ã£ãŠããŸãã ç°ãªãã¹ããŒã ã§ãã£ãŠãã圌ã¯åžžã«çãäžã«ããŸãã ïŒãããŠããããInteractor ãè³ã«ããïŒ
Interactorã¯ãä»ã®ãµãŒãã¹ã®ãã¡ãµãŒãã§ãã ã€ã³ã¿ã©ã¯ã¿ãŒã«ã¯ãããžãã¯èªäœãå«ããããšãã§ããŸãã MVCã§ã¯ ãã³ã³ãããŒã©ãŒãšæ¯èŒã§ããŸãããã³ã³ãããŒã©ãŒã¯ããŒã¿ã®è¡šç€ºæ¹æ³ã«ã€ããŠäœãç¥ããŸããã
ç§ãã¡ã®è§£éã«ããããµãŒãã¹ãšã¯ãã¢ããªã±ãŒã·ã§ã³ã®ããŸããŸãªã¢ãžã¥ãŒã«ãéšåïŒèªèšŒããžãã¯ãããŒã¿ããŒã¹ã®æäœããµãŒããŒã®æäœãæå·åãªã©ïŒããã¢ã¯ã»ã¹ã§ããããŸããŸãªãã«ããŒããã®ä»ã®ã¯ã©ã¹ãæããŸãã ãµãŒãã¹ã¯çžäºã«ããŸãEntityãšå¯Ÿè©±ã§ããŸãã ãšã³ãã£ãã£ã¯ãåãªãååçãªãšã³ãã£ãã£ïŒãŠãŒã¶ãŒãæžç±ãåèªïŒã§ãã åè¿°ã®ããã«ã ãšã³ãã£ãã£ã¯ VIPERã¢ãžã¥ãŒã«ã®ã³ã³ããŒãã³ãã§ã¯ãããŸããã äžè¬ã«ãã¢ãŒããã¯ãã£ã¯å ã VIPãšåŒã°ããŠããŸããã
äœãç解ããŠããªãå Žåã¯åé¡ã§ã¯ãããŸããã ããã«ãã®äŸã§ã¯ããã¹ãŠãæããã«ãªããŸãããããã¯è¡šé¢çãªèª¬æã«ãããŸããã
第1ç« éåžžã«åçŽãªã¢ãžã¥ãŒã«ã®äŸ
![](https://habrastorage.org/webt/g5/fk/9b/g5fk9bjhypd3jssfxsvot3pxhzg.jpeg)
ã¢ããªã±ãŒã·ã§ã³ã®ãã®ãããªç»é¢ã«ã¯ãäžéšã®äººãèããããã«ViewControllerã«ãã¹ãŠãé 眮ã§ãããããVIPERã®ãã¹ãŠã®èœåãšå¿ èŠæ§ã衚瀺ãããŸããã ããããçŽç²ãªã¢ãŒããã¯ãã£ã®ã€ããªãã®ãŒã¯ãã®ååã«åãããããæãåçŽãªç»é¢ãæãåçŽãªã¢ããªã±ãŒã·ã§ã³ã§ãããVIPERã¢ãŒããã¯ãã£äžã§äœæããããšãã§ããŸãã åžžã«ã«ãŒã«ãé å®ããå¿ èŠããããŸãã
ã¯ã©ã¹ã®ã¢ãžã¥ãŒã«å ã§ã¯ãã®ååã«è¿œå ã®åèªãè¿œå ããããããã¢ãžã¥ãŒã«åã¯çãéžæããããšããå§ãããŸãã ããšãã°ã ãAbout Applicationãã¢ãžã¥ãŒã«ã¯AboutãšåŒã°ããŸãã View Controllerã¯AboutViewControllerãšåŒã°ããŸã ã æ®ãã®ã¯ã©ã¹ã¯AboutPresenter ã AboutInteractor ã AboutConfiguratorãªã©ã§ãã
ã¢ãžã¥ãŒã«ã®åæåãView Controllerããå§ãŸãå Žåãã¢ãžã¥ãŒã«ã¯ããããéå§ããå¿ èŠããããšèããŠãã ããã AboutViewControllerã¯ã©ã¹ãšAboutConfiguratorã¯ã©ã¹ãäœæããŸãã AboutConfiguratorã¯ã©ã¹ã¯ã AboutConfiguratorProtocolãããã³ã«ã«æºæ ããå¿ èŠããããã¡ãœããã¯1ã€ã ãã§ãã
protocol AboutConfiguratorProtocol: class { func configure(with viewController: AboutViewController) } class AboutConfigurator: AboutConfiguratorProtocol { func configure(with viewController: AboutViewController) { } }
å°æ¥ããã®ã¡ãœããå ã§ãã¢ãžã¥ãŒã«ãæ§æããŸãã AboutViewControllerã«ã¯ã viewDidLoadã§èšå®ãããã³ã³ãã£ã®ã¥ã¬ãŒã¿ãŒããããã£ãšã AboutPresenterProtocolãããã³ã«ã«æºæ ãããã¬ãŒã³ã¿ãŒããããã£ããããŸãã
éèŠãªã«ãŒã«ïŒ ãã¹ãŠã®ã³ã³ããŒãã³ãã¯ãçŽæ¥ã§ã¯ãªããããã³ã«ãä»ããŠã®ã¿çžäºã«éä¿¡ããŸãïŒ ããã¯ãå°æ¥åäœãã¹ããèšè¿°ããã³ãŒãå šäœãã¯ãªãŒã³ã«ä¿ã€ããã«å¿ èŠã§ãã
AboutPresenterProtocolã«ã¯configureViewïŒïŒã¡ãœãããå«ãŸããŠããå¿ èŠããããŸã ããã®ã¡ãœããã¯ãView Controllerã®èŠèŠèŠçŽ ã®åæããŒã¿ãåæåããã³æ§æããŸãã ãã®æç¹ã§ã AboutViewControllerã¯æ¬¡ã®ããã«ãªããŸãã
class AboutViewController: UIViewController { var presenter: AboutPresenterProtocol! let configurator: AboutConfiguratorProtocol = AboutConfigurator() override func viewDidLoad() { super.viewDidLoad() configurator.configure(with: self) presenter.configureView() } }
ãã¬ãŒã³ã¿ãŒã«ã¯ã ãéããããã¿ã³ãšãµã€ããžã®ãªã³ã¯ã®ãããã¿ã³ãã¯ãªãã¯ãããšãã«åŒã³åºãããã«ãŒã¿ãŒãšã¡ãœããããããŸã ã AboutPresenterProtocolã¯æ¬¡ã®ããã«ãªããŸãã
protocol AboutPresenterProtocol: class { var router: AboutRouterProtocol! { set get } func configureView() func closeButtonClicked() func urlButtonClicked(with urlString: String?) }
ãã®ã¢ãžã¥ãŒã«ã¯éåžžã«ã·ã³ãã«ã§ãããããView Controllerã®å šäœã®æ§æã¯ã URLãæã€ãã¿ã³ã®çœ²åãããžã¥ã¢ã«ãšãã£ã¿ãŒããã§ã¯ãªãã³ãŒãããèšå®ãããããšã§ãã AboutViewControllerã®å Žåããã®ãããªãããã³ã«ïŒ
protocol AboutViewProtocol: class { func setUrlButtonTitle(with title: String) }
AboutPresenterå ã§ãã¡ãœãããå®è£ ããŸãã
func configureView() { view.setUrlButtonTitle(with: interactor.urlRatesSource) }
ã¿ãŒã³ãå§ãŸããã€ã³ã¿ã©ã¯ã¿ãŒãçŸããŸããã ããžãã¯ãšããŒã¿ã®ä¿å/ååŸã¯ãåžžã«ããã«è»¢éããå¿ èŠããããŸãã ãã®å Žåãã€ã³ã¿ã©ã¯ã¿ãŒã«ã¯ããµã€ãã®URLãä¿åããããããã£ãšããã®URLãéãã¡ãœããããããŸã ã
protocol AboutInteractorProtocol: class { var urlRatesSource: String { get } func openUrl(with urlString: String) }
ãããã éãããã¿ã³ãã¯ãªãã¯ããã€ãã³ãã®åŠçã«ã€ããŠã¯ã©ãã§ããããïŒ ããã§ããã¬ãŒã³ã¿ãŒã¯ããã®ã€ãã³ããç»é¢éã®é·ç§»ã«é¢é£ä»ããããŠãããšå€æããåŠçãã«ãŒã¿ãŒã«éä¿¡ãããŸãã ãã®ã¢ãžã¥ãŒã«ã§ã¯ãã«ãŒã¿ãŒã¯çŸåšã®View Controllerã®ã¿ãéããããšãã§ããŸãã
圌ã®ãããã³ã«ïŒ
protocol AboutRouterProtocol: class { func closeCurrentViewController() }
ãã¬ãŒã³ã¿ãŒãããã³ã«ã¯æ¬¡ã®ããã«ãªããŸãã
protocol AboutPresenterProtocol: class { var router: AboutRouterProtocol! { set get } func configureView() func closeButtonClicked() func urlButtonClicked(with urlString: String?) }
VIPERã¢ãžã¥ãŒã«ã®ã³ã³ããŒãã³ãã«ã€ããŠèª¬æãããããã³ã«ããã¹ãŠæã£ãã®ã§ããããã®ã¡ãœããã®å®è£ ã«ç§»ããŸãããã View ControllerãAboutViewProtocolãããã³ã«ã«æºæ ããŠããããšãå¿ããã«è¿œå ããŠãã ããã ã¹ããŒãªãŒããŒãã®ãã¿ã³ãView Controllerã®ããããã£ã«é¢é£ä»ããã¯ãªãã¯ããã€ãã³ããå²ãåœãŠãæ¹æ³ã«ã€ããŠã¯èª¬æããªããããView Controllerã®ã¡ãœãããããã«èšè¿°ããŸãã
@IBOutlet weak var urlButton: UIButton! @IBAction func closeButtonClicked(_ sender: UIBarButtonItem) { presenter.closeButtonClicked() } @IBAction func urlButtonClicked(_ sender: UIButton) { presenter.urlButtonClicked(with: sender.currentTitle) } func setUrlButtonTitle(with title: String) { urlButton.setTitle(title, for: .normal) }
View Controllerã¯ãã¿ã³ãã¯ãªãã¯ããåŸã«äœããã¹ããããããŸãããã setUrlButtonTitleïŒwith titleïŒStringïŒã¡ãœãããåŒã³åºããããšãã«äœããã¹ãããæ£ç¢ºã«ç¥ã£ãŠããŸãã View Controllerã¯ããã¬ãŒã³ã¿ãŒããã®ã¡ãœãããåŒã³åºããããŒã¿ã«åºã¥ããŠã UIèŠçŽ ã®æŽæ°ã移åãåæç» ãé衚瀺ã®ã¿ãè¡ããŸãã åæã«ããã¬ãŒã³ã¿ãŒã¯ããã®ããŒã¿ãView / ViewControllerã«ã©ã®ããã«é 眮ãããŠããããæ£ç¢ºã«ç¥ããŸããã
å®å šãªãã¬ãŒã³ã¿ãŒã¯ã©ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
class AboutPresenter: AboutPresenterProtocol { weak var view: AboutViewProtocol! var interactor: AboutInteractorProtocol! var router: AboutRouterProtocol! required init(view: AboutViewProtocol) { self.view = view } // MARK: - AboutPresenterProtocol methods func configureView() { view.setUrlButtonTitle(with: interactor.urlRatesSource) } func closeButtonClicked() { router.closeCurrentViewController() } func urlButtonClicked(with urlString: String?) { if let url = urlString { interactor.openUrl(with: url) } } }
ã³ã³ãã£ã®ã¥ã¬ãŒã¿ãŒãå®å šã«å¿ããŠããŸããã çµå±ã®ãšããã圌ãªãã§ã¯äœãæ©èœããŸããã 圌ã®ã³ãŒãã¯ïŒ
class AboutConfigurator: AboutConfiguratorProtocol { func configure(with viewController: AboutViewController) { let presenter = AboutPresenter(view: viewController) let interactor = AboutInteractor(presenter: presenter) let router = AboutRouter(viewController: viewController) viewController.presenter = presenter presenter.interactor = interactor presenter.router = router } }
åç §ãµã€ã¯ã«ãååŸããªãããã«ãView Controllerã®ãã¬ãŒã³ã¿ãŒã¯åŒ·ããšç€ºãããPresenterã®View Controllerã¯åŒ±ããšç€ºããããã¬ãŒã³ã¿ãŒãšã®ã€ã³ã¿ã©ã¯ã¿ãŒã¯åŒ±ããšç€ºãããŸãã ãã®ãã§ãŒã³å šäœã§ã ViewControllerãæãéèŠã§ãã ãããã£ãŠãããã§ã¯ããã·ããã¥ãŒã«ã€ããŠè©±ãããšã¯äžé©åã§ãã ViewControllerãéãããšãä»ã®ãã¹ãŠã®èŠçŽ ãç Žæ£ãããŸããããã¯ã ViewControllerãžã®åŒ·åãªãªã³ã¯ã誰ãæã€ããšãã§ããªãããã§ã ã ããããªããšã ã¡ã¢ãªãªãŒã¯ãçºçããŸãã
ã€ã³ã¿ã©ã¯ã¿ãŒã¯ã©ã¹ã¯æ¬¡ã®ããã«ãªããŸãã
class AboutInteractor: AboutInteractorProtocol { weak var presenter: AboutPresenterProtocol! let serverService: ServerServiceProtocol = ServerService() required init(presenter: AboutPresenterProtocol) { self.presenter = presenter } var urlRatesSource: String { get { return serverService.urlRatesSource } } func openUrl(with urlString: String) { serverService.openUrl(with: urlString) } }
ã³ãŒãã¯éåžžã«åçŽãªã®ã§ãã³ã¡ã³ãã¯åé·ã§ãã ServerServiceã«æ³šæãã䟡å€ããããŸãã ããã¯ãView Controlleräžã®ãã¿ã³ã®URLãæäŸããSafariïŒãŸãã¯ä»ã®äœãïŒã§ãªã³ã¯ãéããµãŒãã¹ã§ãã ServerServiceãšãã®ãããã³ã«ã®ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
protocol ServerServiceProtocol: class { var urlRatesSource: String { get } func openUrl(with urlString: String) } class ServerService: ServerServiceProtocol { var urlRatesSource: String { return "https://free.currencyconverterapi.com" } func openUrl(with urlString: String) { if let url = URL(string: urlString) { UIApplication.shared.open(url, options: [:]) } } }
ããã®ãã¹ãŠãç°¡åã§ãã ã«ãŒã¿ãŒã®ã¿ãæ®ããŸãã
class AboutRouter: AboutRouterProtocol { weak var viewController: AboutViewController! init(viewController: AboutViewController) { self.viewController = viewController } func closeCurrentViewController() { viewController.dismiss(animated: true, completion: nil) } }
ç¹°ãè¿ããŸããããã¹ãŠã®ãœãŒã¹ã³ãŒãã¯ãªããžããªã«ãããŸãã èšäºã®æåŸã«ãªã³ã¯ããŸãã
第2ç« ããè€éãªã¢ãžã¥ãŒã«ã®äŸ
ä»åºŠã¯ãã¢ãŒããã¯ãã£ãããè€éãªäŸã§èŠãŠãåã¬ã€ã€ãŒã®ã«ãŒã«ãèŠçŽããŸãã
![](https://habrastorage.org/webt/c0/oc/xr/c0ocxr-rlt5midm_tmmmprtkfya.png)
ãã¹ãŠã®ç»é¢ãåããã¹ããŒãªãŒããŒãã¯æ¬¡ã®ããã«ãªããŸãã ã¡ã€ã³ç»é¢ã§ã¯ãå€æããé貚ãšå€æããé貚ãéžæã§ããŸãã å¥ã®é貚ã«å€æããéé¡ãå ¥åããããšãã§ããŸãã å¥ã®é貚ã«æç®ãããéé¡ã¯ãå ¥åãã£ãŒã«ãã®äžã«è¡šç€ºãããŸãã ãããŠäžçªäžã«ã¯ãå€æçãšã ã¢ããªã±ãŒã·ã§ã³ã«ã€ã㊠ãç»é¢ã«åãæ¿ããããã®ãã¿ã³ããããŸãã
ãã¹ãŠã®é貚ãšãã®çºæ¿ã¬ãŒãã®ããŒã¿ã¯ãç¡æãµã€ãhttps://free.currencyconverterapi.comãããªã¯ãšã¹ããããŸã ã äŸã®åçŽåã®ããã«ã ããŒã¿ãUserDefaultsã«ä¿åããŸããã Core DataãŸãã¯ä»ã®æ¹æ³ã§ä¿åããããã«1ã€ã®ã¯ã©ã¹ã®ã¿ãç°¡åã«å€æŽã§ããŸãã
![](https://habrastorage.org/webt/8b/cz/k1/8bczk19czhvwhenaehm63vf_66k.png)
ãããã³ã«ã®ããã«ãåã¢ãžã¥ãŒã«ã«åå¥ã®ãã¡ã€ã«ãäœæããããšã¯é©ãã¹ãããšã§ãã ãã®ã¢ãããŒããæ°ã«å ¥ããªãå Žåã¯ãã¯ã©ã¹èªäœã®ãã¡ã€ã«ã«ãããã³ã«ãçŽæ¥èšè¿°ã§ããŸãã å人çã«ã¯ããã¹ãŠã®ã¢ãžã¥ãŒã«ãããã³ã«ã1ãæã«éããããŠããæ¹ã䟿å©ã§ãã 奜ã¿ã®åé¡ã
äŒçµ±çã«ãView Controllerããã®ã¢ãžã¥ãŒã«ãæ€èšãå§ããŸãã View / ViewControllerã®éèŠãªã«ãŒã«ã¯ã Entityããããã«çŽæ¥æž¡ãããªãããšã§ãã ãã®ããã«ã¯ãè¿œå ã®ã¬ã€ã€ãŒ/ãµãŒãã¹ãäœæããå¿ èŠããããŸãã
viewDidLoadã¡ãœããã¯ã Aboutã¢ãžã¥ãŒã«ã®å®è£ ãšåãã§ãã ã¢ãžã¥ãŒã«æ§æãåŒã³åºããã View ïŒãã®å Žåã¯ViewController ïŒãæ§æããããã®ã³ãã³ããã€ã³ã¿ã©ã¯ã¿ãŒã«äžããããŸãã
![](https://habrastorage.org/webt/ed/so/tg/edsotgna3ddkipyv5vco0dw0aze.png)
ãã¹ãŠã®CurrencyPickerViewã³ãŒãã¯èæ ®ãããŸããã IBOutletã¯åœŒã®View Controllerã«ãããŸããã圌ã®ããžãã¯ã¯ãã¬ãŒã³ã¿ãŒã§åŠçãããŸãã ãããã£ãŠããããžã®ãªã³ã¯ãã³ã³ãã£ã®ã¥ã¬ãŒã¿ãŒã«ç»é²ãããŸãã CurrencyPickerViewã«ã¯ããªã²ãŒãããããView Controllerã§ã¯ãªããã¬ãŒã³ã¿ãŒã«ãªããŸãã ã³ã³ãã£ã®ã¥ã¬ãŒã¿ãŒã§ã次ã®åŒã³åºããè¿œå ããŸãã
class MainConfigurator: MainConfiguratorProtocol { func configure(with viewController: MainViewController) { ... presenter.currencyPickerView = viewController.currencyPickerView viewController.currencyPickerView.delegate = presenter } }
ããè€éãªäŸã䜿çšãããšãView Controllerãã¢ã³ããŒããããããžãã¯ããã¬ãŒã³ã¿ãŒããã€ã³ã¿ã©ã¯ã¿ãŒã«ãããã«ãµãŒãã¹ã«è»¢éãããããšãæããã«ãªããŸãã ãã®ã¢ãžã¥ãŒã«ã§ã®Viewã®æ§æã¯ããè€éã§ãã¢ããªã±ãŒã·ã§ã³ãéããåã«æåŸã«äœ¿çšãããä¿åå€ã®èšå®ãå«ãŸããŸãã ã³ãŒãã¯æ¬¡ã®ãšããã§ãã
func configureView() { view?.setInputValue(with: inputValue) view?.setOutputValue(with: outputValue) view?.setInputCurrencyShortName(with: inputCurrencyShortName) view?.setOutputCurrencyShortName(with: outputCurrencyShortName) view?.addDoneOnInputCurrencyKeyboard() updateRateText() interactor.getAllCurrencies() }
UIã³ã³ããŒãã³ãã®åæå€ã®èšå®ã«å ããŠããã¹ãŠã®é貚ã®ãªã¹ãã®èŠæ±ãã€ã³ã¿ã©ã¯ã¿ãŒã«éä¿¡ãããŸãã ãã¬ãŒã³ã¿ãŒã¯ããã®ããŒã¿ã®åä¿¡å ãç¥ããŸããããå¿ èŠãªããšã¯ç¥ã£ãŠããŸãã ãŸããå€inputValue ã outputValue ã inputCurrencyShortNameããã³outputCurrencyShortNameãã€ã³ã¿ã©ã¯ã¿ãŒããèŠæ±ãããŸãã ãã®ä¿åãããããŒã¿ã®å ¥æå ãç¥ã£ãŠããã®ã¯åœŒã ãã§ãïŒ
var inputValue: String? { set { if let value = newValue { interactor.inputValue = Double(value) ?? 0.0 } } get { var input = String(interactor.inputValue) if input.hasSuffix(".0") { input.removeLast(2) } return input } } var outputValue: String? { get { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.maximumFractionDigits = 2 formatter.roundingMode = .down formatter.usesGroupingSeparator = false let number = NSNumber(value: interactor.outputValue) var output = formatter.string(from: number)! if output.hasSuffix(".00") { output.removeLast(2) } return output } } var inputCurrencyShortName: String { get { return interactor.inputCurrencyShortName } } var outputCurrencyShortName: String { get { return interactor.outputCurrencyShortName } }
VIPERã«é¢ããã³ã¡ã³ãã®äžã§ããã¬ãŒã³ã¿ãŒã¯ç¹å¥ãªããšã¯äœããããView Controllerããã€ã³ã¿ã©ã¯ã¿ãŒãžããŸãã¯ãã®éã«ããŒã¿ãåçŽã«è»¢éãããšããæèŠã«åºäŒããŸããã äžèšã®ã³ãŒãããããã¬ãŒã³ã¿ãŒã¯ã€ã³ã¿ã©ã¯ã¿ãŒã«ããŒã¿ãèŠæ±ããŠããã®ãŸãŸãæäŸããã ãã§ãªããããŒã¿ãå¿ èŠãªåœ¢åŒã§æºåããã³ãã©ãŒãããããããšãæããã«ãªããŸãã ãã¬ãŒã³ã¿ãŒã¯ãView Controllerã«è»¢éãããããŒã¿ã®çš®é¡ãšåœ¢åŒã«ã€ããŠè²¬ä»»ãè² ããŸãã View Controllerã¯ãã©ãŒããããæ°ã«ããå¿ èŠããªããªããå¿ èŠãªUIã³ã³ããŒãã³ãã«ã®ã¿å²ãåœãŠãŸãã
ãã¬ãŒã³ã¿ãŒã¯UIKitã«ã€ããŠäœãç¥ããã UIButton ã UILabelããã³ãã®ä»ã®ããžã¥ã¢ã«ã³ã³ããŒãã³ãã«ã€ããŠãç¥ããŸããã ããã¯éåžžã«éèŠã§ãã UIKitã®ãã¹ãŠã®åäœã¯ãView Controllerããã³ä»ã®Viewã³ã³ããŒãã³ãã§çºçããŸãã ãŸãããã¿ã³ãæŒããããšãã UIButtonãã©ã¡ãŒã¿ãŒãæž¡ãããšã¯ã§ããŸãã;ãã¬ãŒã³ã¿ãŒã¯ãããç¥ããªãã¯ãã§ãã ãããã£ãŠããã¿ã³ãæŒããŠå ¥åãã£ãŒã«ãã«ããã¹ããå ¥åãããšãView Controllerã§æ¬¡ã®ããã«åŠçãããŸãã
@IBAction func inputCurrencyButtonClicked(_ sender: UIButton) { presenter.inputCurrencyButtonClicked() } @IBAction func outputCurrencyButtonClicked(_ sender: UIButton) { presenter.outputCurrencyButtonClicked() } func textFieldDidBeginEditing(_ textField: UITextField) { presenter.textFieldDidBeginEditing() } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if textField == inputTextField { if textField.availableAdding(string: string) { textField.addString(string) self.presenter.inputValueChanged(to: textField.text ?? "") } return false } return true } func textFieldShouldClear(_ textField: UITextField) -> Bool { if textField == inputTextField { textField.clear() self.presenter.inputValueCleared() return false } return true }
ã«ã¹ã¿ã UIèŠçŽ ãèšè¿°ããããå®æããèŠçŽ ã«æ¡åŒµæ©èœãè¿œå ããå¿ èŠããããšããŸãããã ããšãã°ãã¡ã€ã³ã¢ãžã¥ãŒã«ã®UITextFieldãèããŸãã ã³ã³ããŒãã³ãã«ã¯ãããã ãã«é¢ããç¬èªã®å éšããžãã¯ãå«ããããšãã§ããŸãã ããšãã°ãé貚ã®å ¥åãã£ãŒã«ãã¯å°æ°ã§ãããå é ã«2ã€ã®ãŒããå ¥åããããšã¯ã§ããïŒã00ãïŒ ãè€æ°ã®ãã€ã³ããå ¥åããããšã¯ã§ããŸããïŒã0.11.2ãïŒ ãã«ã³ãã¯ãã€ã³ãã«å€æãããæ°åã®ã¿ãå ¥åã§ããŸããããŒããŒããªã© ãã®å Žåããã®ããžãã¯ãèŠçŽ èªäœã«å ¥ããããšãã§ããŸãã çµå±ã®ãšããããã®ããžãã¯ã¯ã¢ããªã±ãŒã·ã§ã³ã®ä»ã®ã³ã³ããŒãã³ãã®ããžãã¯ã«ã¯åœ±é¿ãããé©çšãããã ãã§ãã ããšãã°ã次ã®ããã«ïŒ
extension UITextField { func availableAdding(string: String) -> Bool { switch string { case "": return self.text != "" case "0"..."9": return self.text != "0" case ".", ",": return self.text!.count > 0 && self.text!.range(of: ".") == nil && self.text!.range(of: ",") == nil default: return false } } func addString(_ string: String) { var newValue: String = self.text ?? "" var addingString = string if addingString == "", newValue.count > 0 { newValue.removeLast() } else if addingString != "" { if addingString == "," { addingString = "." } newValue.append(addingString) } self.text = newValue } func clear() { self.text = "" } func addDoneOnKeyboard() { let keyboardToolbar = UIToolbar() keyboardToolbar.sizeToFit() let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissKeyboard)) keyboardToolbar.items = [flexBarButton, doneBarButton] self.inputAccessoryView = keyboardToolbar } @objc func dismissKeyboard() { self.resignFirstResponder() } }
å¥ã®ããšã¯ããã®ãããªããžãã¯ãå€éšããŒã¿ãããšãã°ç»é²äžã®ãŠãŒã¶ãŒã®ãã°ã€ã³ã®å¯çšæ§ã«åœ±é¿ãäžããå¯èœæ§ãããå Žåã§ãã ãµãŒããŒãŸãã¯ããŒã¿ããŒã¹ãžã®èŠæ±ããããŸãã ãŸãã¯ããã¹ã¯ãŒãã®ãªãã¬ã€ãããã¯å¥ã®ã³ã³ããŒãã³ãã«ãã§ã«åœ±é¿ããããã§ãã äžè¬ã«ãUIã³ã³ããŒãã³ãã«ã®ã¿é©çšãããããžãã¯ãUIã³ã³ããŒãã³ãã«è¿œå ã§ããŸãã ããã€ãã®ããã«ããã¯è°è«ã®äœå°ãããããã«èŠãããããããŸãããã
ãµãŒããŒããé貚ã®ããŒã¿ãåä¿¡ããæ¹æ³ãæ€èšããŠãã ããã ãã¬ãŒã³ã¿ãŒã§ã¯ã getAllCurrenciesïŒïŒã¡ãœããã®åŒã³åºããçºçããŸããã 次ã«äœããã¹ãããçºè¡šè ã¯ç¥ããŸããã ã€ã³ã¿ã©ã¯ã¿ãŒã«ã¯ããã«ããžãã¯ãæžã蟌ãŸããå¿ èŠã«å¿ããŠãå¿ èŠãªã³ãã³ãããã¬ãŒã³ã¿ãŒã«éä¿¡ãããŸãã å®è£ ã¯æ¬¡ã®ãšããã§ãã
func getAllCurrencies() { presenter.showHUD() serverService.getAllCurrencies { (dict, error) in if let error = error { self.presenter.hideHUD() self.presenter.showLoadCurrenciesButton() self.presenter.showAlertView(with: error.localizedDescription) return } if let dictResponse = dict { self.currencyService.saveAllCurrencies(with: dictResponse, completion: { (error) in if let error = error { self.presenter.hideHUD() self.presenter.showAlertView(with: error.localizedDesc) return } self.currencyService.sortAndUpdateCurrentCurrencies() self.getOutputCurrencyRatio(newCurrency: nil) }) } } }
ãã®ã€ã³ã¿ã©ã¯ã¿ãŒã«ã¯æ¢ã«2ã€ã®ãµãŒãã¹ãå«ãŸããŠããŸãã é貚ã®æäœãæ åœããCurrencyServiceãšããµãŒããŒã®æäœãæ åœããæ¢ç¥ã®ServerServiceã§ãã ãã¡ããã ServerServiceãããã€ãã®ãµãŒãã¹ã¯ã©ã¹ã«åå²ããŠãç¹å®ã®ãµãŒããŒã§ã¯ãªãããã¹ãŠã®ãµãŒããŒã§äœæ¥ããæ¹æ³ãåå©çšããæ¹ãé©åã§ãã ãã ãããã¹ãŠã100äžã®ã¯ã©ã¹ã«åçŽåããããã«ãããã§ã¯1ã€ã®ã¯ã©ã¹ã«éå®ããŸãããããã«ãããVIPERã¢ãžã¥ãŒã«ã®ã¢ãŒããã¯ãã£ãæãªãããããšã¯ãããŸããã
ãµãŒãã¹ã«ã€ããŠã¯ã SOLIDã®ååã®1ã€ã§ããäŸåæ§å転ã®ååã«åŸã£ãŠãç¹å®ã®ã¯ã©ã¹ã«çµã³ä»ããããªãããã«ãããã³ã«ãäœæããŠãããããåŠçããããšãéåžžã«æãŸããã§ãã
CurrencyServiceã¯ã Currencyãªã©ã®ããŒã¿æ§é ã®æäœã«åœ¹ç«ã¡ãŸãã 圌ã¯ãå©çšå¯èœãªãã¹ãŠã®é貚ãé貚ã«çŸåšå ¥åãããŠããå€ãé貚ã®çš®é¡ãæäŸãã2ã€ã®é貚ã«å¯Ÿããã¬ãŒããä¿åããœãŒããåä¿¡ããããšãã§ããŸãã 圌ã®ãããã³ã«ã¯æ¬¡ã®ããã«ãªããŸãã
protocol CurrencyServiceProtocol: class { var currencies: [Currency] { set get } var currencyNames: [String] { set get } var inputValue: Double { set get } var outputValue: Double { get } var inputCurrency: Currency { set get } var outputCurrency: Currency { set get } func saveAllCurrencies(with dict: [String: Any], completion: @escaping (CurrencyError?) -> Swift.Void) func sortAndUpdateCurrentCurrencies() func saveOutputCurrencyRatio(with dict: [String: Any], completion: @escaping (CurrencyError?) -> Swift.Void) }
CurrencyServiceãµãŒãã¹ã¯ã UserDefaultsã«ããŒã¿ãä¿åããå¥ã®StorageServiceãµãŒãã¹ã«ããŒã¿ãèŠæ±ããŸãã ã€ã³ã¿ã©ã¯ã¿ãŒã¯ãããŒã¿ã®ä¿åæ¹æ³ã¯èšããŸã§ããªããããŒã¿ãä¿åãããŠããããšãçãããããŸããã CurrencyServiceãã«ããŒãµãŒãã¹ã¯ãã¹ãŠã®äœæ¥ãè¡ã ã ã€ã³ã¿ã©ã¯ã¿ãŒã«ããŒã¿ãæäŸããã ããªã®ã§ã ã€ã³ã¿ã©ã¯ã¿ãŒã¯StorageServiceãµãŒãã¹ãããããšããç¥ããŸããã
ã¡ã€ã³ã¢ãžã¥ãŒã«ã®ã€ã³ã¿ã©ã¯ã¿ãŒã¯ãäž»ã«æœè±¡åãšãµãŒãã¹ãããã³ã«ã¡ãœããã®åŒã³åºãã§æ§æãããŠããããã次ã®ãããªã¬ã€ã€ãŒã®ãŠããããã¹ããæžãã®ã¯éåžžã«ç°¡åã§ãã ã¢ããšã¹ã¿ããäœæããã®ã¯é£ãããããŸããã ç¹å®ã®ã¯ã©ã¹ãžã®ãã€ã³ãã¯ãããŸããã
åã¡ãœãããšæ®ãã®ã¯ã©ã¹ã®åè¡ã詳现ã«èª¿ã¹ç¶ããã€ããã¯ãããŸããã ã¢ãŒããã¯ãã£ã®äžè¬çãªæ¬è³ªãšåå±€ã®åœ¹å²ã¯ãã§ã«æ確ã«ãªã£ãŠããã¯ãã§ãã æåŸã«èšãããã®ã¯ã ã»ã°ãšãä»ããå¥ã®ç»é¢ãžã®ç§»è¡ã§ãã
Appleã¯ãã®æ©èœãView Controlleråãã«èšèšããããããã®ã¢ãããŒãããé²ãå¿ èŠãããã navigationControllerïŒ.PushViewControllerïŒvcãanimatedïŒtrueïŒãééããå¿ èŠã¯ãããŸããã ãæ å ±ããã¿ã³ãã¯ãªãã¯ãããšã ãã¢ããªã±ãŒã·ã§ã³ã«ã€ããŠãç»é¢ãéããŸãã ãããã£ãŠããã¬ãŒã³ã¿ãŒã¯ãã¿ã³ãæŒãã€ãã³ããã«ãŒã¿ãŒã«éä¿¡ãã次ã®ã¡ãœãããåŒã³åºããŸãã
func showAboutScene() { viewController.performSegue(withIdentifier: viewController.selfToAboutSegueName, sender: nil) }
View Controllerã¯ãã·ã¹ãã æºåïŒã»ã°ãš...ïŒãåŒã³åºãããã§ã«ãã®ã€ãã³ããã«ãŒã¿ãŒã«çŽæ¥æž¡ããŸãã
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { presenter.router.prepare(for: segue, sender: sender) }
ãã®å Žåãçºè¡šè ã¯çµäºããŸããã 誰ãããã®éåãæ°ã«å ¥ããªãå Žåã¯ãã¡ãœããããã¬ãŒã³ã¿ãŒã«æž¡ãããUIèŠçŽ ããã©ã¡ãŒã¿ãŒãšããŠæž¡ãå¿ èŠããããŸããããããéåã«ãªããŸãã ãŸãã¯ãä»ã®äœããèãåºããŸãã ç§èªèº«ã¯ãŸã è¯ãéžæè¢ãèŠã€ããŠããŸããã prepareïŒforïŒsegueãsenderïŒsenderïŒã®ããªã²ãŒããèšå®ã§ããã°ããã¡ããã«ãŒã¿ãŒã«ãªããŸãã
ãããã«
瀺ãããã¢ãŒããã¯ãã£ã¯çæ³çã§ã¯ãããŸããã èšäºã®åé ã§ã誰ããèªåã®VIPERãæã£ãŠãããšèšã£ãã®ãäžæè°ã§ã¯ãããŸããã äœäººããšãŠãå€ãã®æèŠã è€æ°ã®ã¢ãžã¥ãŒã«ãåããŠãŒã¶ãŒã¹ããŒãªãŒå ã§ã°ã«ãŒãåãããè€æ°ã®ã¢ãžã¥ãŒã«ã«å¯ŸããŠ1ã€ã®ã«ãŒã¿ãŒãäœæãããšãã«ãªãã·ã§ã³ã«åºäŒããŸããã ãŸãã¯ãå¥ã®å®æœåœ¢æ ã§ã¯ãããã€ãã®ã¢ãžã¥ãŒã«ã«å¯Ÿãã1ã€ã®ã€ã³ã¿ã©ã¯ã¿ãŒã å€ãã¯å€å žçãªWireframeã䜿çšããŸãããä»ã®ãã®ã¯äœãä»ã®ãã®ãæãã€ããŸãã 誰ããEntity View Controllerã«æž¡ããŸãã ãã¡ãããåŸè ã¯ééã£ãŠããŸãã
æãããæžãããã¢ããªã±ãŒã·ã§ã³ãæã£ãŠããå Žåã§ããVIPERã䜿çšãããšããã¹ãŠãåŸã ã«æžãæããããšãã§ããŸãã View Controllerçšã®View Controllerã ããã¯ãã¬ãŒã³ããŒã·ã§ã³å±€ã§ãããåã¢ãžã¥ãŒã«ã¯ä»ã®ã¢ãžã¥ãŒã«ã®ã¢ãŒããã¯ãã£ããã³å®è£ ã«äŸåããŸããã ãµãŒãã¹ãžã®ããžãã¯ã®ç§»æ€ãåŸã ã«éå§ããŸãã View Controllerãã¢ã³ããŒãããŸãã ããã«ã³ãŒãããµããŒãããããšã§ããã®ãããªã¬ã€ã€ãŒã«ããåé¢ã¯äœåãææãäžããŸãã
ãã®èšäºã§ã¯ãäŸãã°Typhoonãªã©ãiOSçšã®ã¢ãžã¥ãŒã«ã§ã®äŸåæ§æ³šå ¥ã«ã€ããŠã¯è§ŠããŸããã§ããã ãããŠãéçºãä¿é²ããè¿œå ã®æçšãªãã®ã®å€ãã®
ããªãã®VIPERãäœã§ãããã¬ã€ã€ãŒéã®è²¬ä»»ã®æ確ãªåå²ã«åŸããæœè±¡åïŒãããã³ã«ïŒãæ±ãããšãéèŠã§ãã VIPERã¢ãžã¥ãŒã«ã®ãã¹ããæžãããšã¯ããèããããŸãããããã®ãããªã³ãŒãã®å Žåããã¹ããæžãã®ã¯ã¯ããã«ç°¡åã§ãã
ãã®èšäºã¯ããããå°ãé¢åã§ããªã¥ãŒã ããããŸãããããã®ããã«èªåã§ç解ã§ããããã«ãã¹ãŠã®ãœãŒã¹ã³ãŒããæäŸããŸããã建èšçãªæ¹å€ãšè°è«ãæè¿ããŸããäœãééã£ãããšãæžããã®ãããããŸãããã³ã¡ã³ããæžããŠãã ããã
ãªããžããªãžã®ãªã³ã¯ã