From 0deb696107d20381462707bbb2177c7854668ee6 Mon Sep 17 00:00:00 2001 From: Elon Park Date: Tue, 21 Jun 2022 23:11:00 +0900 Subject: [PATCH 1/5] fix image path in ko_KR GENERATOR.md --- Documents/ko_KR/GENERATOR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documents/ko_KR/GENERATOR.md b/Documents/ko_KR/GENERATOR.md index 19ec7f6..c46f6f3 100644 --- a/Documents/ko_KR/GENERATOR.md +++ b/Documents/ko_KR/GENERATOR.md @@ -60,7 +60,7 @@ brew install needle Needle의 제너레이터는 명령줄에서 호출할 수 있지만 빌드 시스템과 직접 통합될 때 가장 편리합니다. Uber에서는 CI 빌드에 [BUCK](https://buckbuild.com/)를 사용하고 로컬 개발에 Xcode를 사용합니다. 따라서 우리에게 Needle은 BUCK와 통합됩니다. 그런 다음 Xcode가 코드 생성을 위해 BUCK Needle 대상을 호출하도록 합니다. 대부분의 Swift 애플리케이션이 Xcode를 빌드 시스템으로 사용하기 때문에 여기서는 이를 다룰 것입니다. 1. [Releases page](https://github.com/uber/needle/releases)에서 수동으로 다운로드 혹은 [Carthage](https://github.com/Carthage/Carthage) 또는 [Homebrew](https://github.com/Homebrew/brew)를 사용하여 최신 제너레이터 바이너리를 다운로드 하십시오. -2. Xcode에서 앱의 executable target's의 "Build Phases" 섹션의 "Run Script"를 추가합니다. ![](Images/build_phases.jpeg) +2. Xcode에서 앱의 executable target's의 "Build Phases" 섹션의 "Run Script"를 추가합니다. ![](https://raw.githubusercontent.com/uber/needle/master/Images/build_phases.jpeg) 3. "Shell"의 값이 `/bin/sh`으로 되어 있는지 확인합니다. 4. 스크립트 입력란에 제너레이터를 호출하는 shell script를 추가합니다. 예를 들어 샘플 TicTacToe 앱은 다음 스크립트를 사용합니다. `export SOURCEKIT_LOGGING=0 && ../Carthage/Checkouts/needle/Generator/bin/needle generate Sources/NeedleGenerated.swift Sources/ --header-doc ../../copyright_header.txt`. From 01713b46165aeecfa1337efde982c49680f61794 Mon Sep 17 00:00:00 2001 From: Elon Park Date: Tue, 21 Jun 2022 23:11:30 +0900 Subject: [PATCH 2/5] fix image path in ko_KR API.md --- Documents/ko_KR/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documents/ko_KR/README.md b/Documents/ko_KR/README.md index e3534bb..004bebe 100644 --- a/Documents/ko_KR/README.md +++ b/Documents/ko_KR/README.md @@ -1,4 +1,4 @@ -# ![](Images/logo.png) +# ![](https://raw.githubusercontent.com/uber/needle/master/Images/logo.png) [![Build Status](https://travis-ci.com/uber/needle.svg?branch=master)](https://travis-ci.com/uber/needle?branch=master) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) From 0ef6a26d1ffb6006dc791ba5da46084b55c16a5a Mon Sep 17 00:00:00 2001 From: Elon Park Date: Tue, 21 Jun 2022 23:24:03 +0900 Subject: [PATCH 3/5] Add dynamic dependency documentation in ko_KR API.md --- Documents/ko_KR/API.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documents/ko_KR/API.md b/Documents/ko_KR/API.md index 6595c62..027fabd 100644 --- a/Documents/ko_KR/API.md +++ b/Documents/ko_KR/API.md @@ -87,6 +87,28 @@ protocol LoggedInDependency: Dependency { } ``` +## Dynamic dependencies + +동적 의존성은 런타임에 얻은 의존성을 나타냅니다. 좋은 예는 AuthenticatedUser 객체입니다. User 객체가 항상 존재하는 것은 아닙니다. 사용자가 로그인한 후에만 존재합니다. 앱에 로그아웃 및 로그인 `Scope`가 있다고 가정하면 이 User 객체는 로그인 `Scope`와 하위 `Scope` 내에서만 사용할 수 있어야 합니다. 생성자 주입을 통해 로그인 `Scope`에 AuthenticatedUser 객체를 제공하는 한 가지 방법은 다음과 같습니다: + ``` + class LoggedInComponent: Component { + let user: AuthenticatedUser + init(parent: Scope, user: AuthenticatedUser) { + self.user = user + super.init(parent: Parent) + } + } + ``` + + 그런 다음 로그인 `Scope`의 상위 `Scope`에서 일반적으로 사용하는 computed `var` 대신 메소드를 통해 `LoggedInComponent`를 인스턴스화할 수 있습니다: + ``` + class RootComponent: Component { + func loggedInComponent(user: AuthenticatedUser) { + return LoggedInComponent(parent: self, user: user) + } + } + ``` + # Component 사용하기 좋은 점은 Needle command-line 코드 제너레이터를 실행할 준비가 되지 않았더라도 코드를 작성하고 컴파일할 준비가 되었다는 것입니다. 우리는 또한 `imageCache`와 `networkService`가 어느 상위 `Component`에서 왔는지 시스템에 알리지 않았습니다. From 8597ac279af40818062d8574be3abee880fc131e Mon Sep 17 00:00:00 2001 From: Elon Park Date: Tue, 21 Jun 2022 23:34:49 +0900 Subject: [PATCH 4/5] fix WHY_DI.md link in ko_KR API.md --- Documents/ko_KR/API.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documents/ko_KR/API.md b/Documents/ko_KR/API.md index 027fabd..0c834f8 100644 --- a/Documents/ko_KR/API.md +++ b/Documents/ko_KR/API.md @@ -37,7 +37,7 @@ targets: [ ## Basics -의존성 주입(Dependency Injection, 이하 DI로 표기)을 사용하는 주요 이유는 별도의 [문서](/WHY_DI.md)에 설명되어 있습니다. 당신의 앱이 DI의 혜택을 받을 수 있는지 확실하지 않은 경우 계속하기 전에 이 내용을 읽어보십시오. +의존성 주입(Dependency Injection, 이하 DI로 표기)을 사용하는 주요 이유는 별도의 [문서](./WHY_DI.md)에 설명되어 있습니다. 당신의 앱이 DI의 혜택을 받을 수 있는지 확실하지 않은 경우 계속하기 전에 이 내용을 읽어보십시오. ## 핵심 요소 @@ -70,7 +70,7 @@ class LoggedInComponent: Component { 예제의 `shared` 구문은 저희가 (`Component` 기본 클래스 내부에서) 제공하는 유틸리티 함수로 이 `var`에 액세스할 때마다 단순하게 동일한 인스턴스를 반환합니다. (아래에 선언된 프로퍼티는 대조적으로 새로운 매번 인스턴스를 반환합니다). 이렇게 하면 이 프로퍼티의 라이프사이클이 Component의 라이프사이클에 연결됩니다. -Component를 사용하여 이 component와 쌍을 이루는 `ViewController`를 구성할 수도 있습니다. 위의 예제에서 볼 수 있듯이, 이것은 `ViewController`가 프로젝트에서 DI 시스템을 사용하고 있다는 사실을 모르고도 `ViewController`가 필요로 하는 모든 의존성을 전달할 수 있도록 합니다. **"DI의 이점"** 문서에서 언급했듯이 구체적인 클래스나 구조체 대신 프로토콜을 전달하는 것이 가장 좋습니다. +Component를 사용하여 이 component와 쌍을 이루는 `ViewController`를 구성할 수도 있습니다. 위의 예제에서 볼 수 있듯이, 이것은 `ViewController`가 프로젝트에서 DI 시스템을 사용하고 있다는 사실을 모르고도 `ViewController`가 필요로 하는 모든 의존성을 전달할 수 있도록 합니다. [**"DI의 이점"**](./WHY_DI.md) 문서에서 언급했듯이 구체적인 클래스나 구조체 대신 프로토콜을 전달하는 것이 가장 좋습니다. # Dependencies From 11cea4cc13019910704eda1ca61c9f2c94237226 Mon Sep 17 00:00:00 2001 From: Elon Park Date: Tue, 21 Jun 2022 23:40:28 +0900 Subject: [PATCH 5/5] Change to commonly used text --- Documents/ko_KR/WHY_DI.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documents/ko_KR/WHY_DI.md b/Documents/ko_KR/WHY_DI.md index 565a312..3460045 100644 --- a/Documents/ko_KR/WHY_DI.md +++ b/Documents/ko_KR/WHY_DI.md @@ -4,9 +4,9 @@ ## 설명하기 위한 다소 현실적인 예 -패턴을 추상적인 용어로 설명하는 대신 간단한 뷰 컨트롤러 기반 예를 사용하여 패턴을 이해해 보겠습니다. 추상적인 설명에 관심이 있으시면 Wikipedia에는 [훌륭한 기사](https://en.wikipedia.org/wiki/Dependency_injection)가 있습니다. +패턴을 추상적인 용어로 설명하는 대신 간단한 뷰 컨트롤러 기반 예를 사용하여 패턴을 이해해 보겠습니다. 추상적인 설명에 관심이 있으시면 Wikipedia에는 [훌륭한 글](https://en.wikipedia.org/wiki/Dependency_injection)이 있습니다. -서버에서 검색한 사진 세트를 표시하는 ViewController가 있는 사진 검색 앱을 개발 중이라고 가정해 보겠습니다. 이 매우 간단한 앱에는 사진을 표시하는 `PhotosViewController`와 서버에서 사진을 요청하는 로직를 캡슐화하는 `PhotosService`가 있습니다. `PhotosViewController`는 보기 로직을 구현하고 `PhotosService`는 HTTP 요청 전송 및 응답 분석 로직을 포함합니다. DI를 사용하지 않으면 `PhotosViewController`는 `init` 또는 `viewDidLoad` 메소드에서 `PhotosService`의 새 인스턴스를 인스턴스화 합니다. 그런 다음 서비스 객체를 사용하여 적합하다고 판단될 때 사진을 요청할 수 있습니다. +서버에서 검색한 사진 세트를 표시하는 ViewController가 있는 사진 검색 앱을 개발 중이라고 가정해 보겠습니다. 이 매우 간단한 앱에는 사진을 표시하는 `PhotosViewController`와 서버에서 사진을 요청하는 로직를 캡슐화하는 `PhotosService`가 있습니다. `PhotosViewController`는 뷰 로직을 구현하고 `PhotosService`는 HTTP 요청 전송 및 응답 분석 로직을 포함합니다. DI를 사용하지 않으면 `PhotosViewController`는 `init` 또는 `viewDidLoad` 메소드에서 `PhotosService`의 새 인스턴스를 인스턴스화 합니다. 그런 다음 서비스 객체를 사용하여 적합하다고 판단될 때 사진을 요청할 수 있습니다. 이제 한 번 코드를 분석해 보겠습니다. 현재 상태에서는 `PhotosViewController`와 `PhotosService`가 밀접하게 결합되어 있습니다. 여기에는 몇 가지 문제가 있습니다. 1. `PhotosViewController`도 변경하지 않고는 `PhotosService`를 변경할 수 없습니다. 두 개의 클래스만 있으면 괜찮아 보일 수 있지만 수백 개의 클래스가 있는 실제 시나리오에서는 앱 개발 속도가 크게 느려집니다.