# ios-cantact-manager
----
<a href ="#1-Step1---사용자 입력 수신 및 검증">Step1 - 사용자 입력 수신 및 검증</a>
<a href ="#2-Step2---사용자 메뉴 표기">Step2 - 사용자 메뉴 표기</a>
<a href ="#3-Step3---목록/검색 기능 구현">Step3 - 목록/검색 기능 구현</a>
----
## 프로젝트 파일 구조
<img src="https://user-images.githubusercontent.com/71758542/210035621-ba5e2146-cc9a-416f-93ab-ed3f77235cba.png" width="1000">
---
## 역할 분배
|struct/class|역할|
|:---|:---|
|`ContactManager`|- 프로그램이 실행될 때 가장 먼저 수행되는 부분</br>- startProcess를 사용하여 메뉴가 실행되도록 하며, 메서드 내의 반복문을 통해 한 가지 기능을 수행한 후 다시 메뉴 선택 화면을 보여줄 수 있도록 한다.
|`ContactInformation`|- ContactInformation을 사용하여 사용자로부터 입력받은 정보들을 구조화하여 저장할 수 있도록 하였다.|
|`Converter`|- string <-> [Character]의 변환을 수행한다.|
|`Detector`|- 공백문자를 제거하는 역할을 수행한다.|
|`Checker`|- 사용자로부터 입력된 연락처가 주어진 제약사항에 위배되는지를 확인한다.|
|enum|역할|
|:---|:---|
|`PrintMessage`|- 메뉴, 오류 메세지 등 메세지 출력을 관장하는 부분이다.</br>- validUserInput, searchContact를 타입 메서드로 선언하여 별도의 인스턴스 생성 없이 외부에서 사용할 수 있도록 구현하였다.|
|`RegularExpression`|- Checker에서 사용자 입력 확인 시 필요한 정규식을 담고 있다.|
|protocol|역할|
|:---|:---|
|`InputPossible`|- 해당 프로토콜을 채택하는 경우 입력의 기능을 수행할 수 있도록 하였다.|
|`SystemMenuWorkable`|- 해당 프로토콜을 채택하는 경우 시스템 메뉴의 구성요소를 모두 수행할 수 있도록 하였다.|
---
## Step1 - 사용자 입력 수신 및 검증
[PR #2 | Step1 - 사용자 입력 수신 및 검증](https://github.com/tasty-code/ios-contact-manager/pull/2)
- 사용자 입력 형태 검증
- 이름, 나이, 연락처 구분
- 정규식
사용자의 연락처 정보 입력을 수신 받아 정규식을 통해 입력값을 검증하여 Console 화면에 출력하는 단계로
입력 순서는 이름, 나이, 연락처로 구분되어지며 각 항목의 조건으로는 아래와 같다.
1. 이름: 띄어쓰기를 구분하지 않으며 특수문자 및 숫자 그리고 영문이름만 사용할 수 있다.
2. 나이: 세자리 수 이하로만 사용할 수 있다.
3. 연락처: 앞 자리는 지역 번호 및 핸드폰(010) 번호만 사용 가능하도록 2~3자리 수만 사용할 수 있으며
연락처의 기본 형식을 따라 `-`를 2개 사용하여 분리하여 입력하는 것만 사용할 수 있다.
### 적용해보려고 노력해본 점
최대한 객체화를 해보려고 노력하였다. 하여 위 표를 확인하면 `struct/class`의 Custom Type으로
문자와 문자열의 타입을 변환해주는 역할만 할 수 있는 `Converter`, Space(_) 값을 검출해내는 역할만 할 수 있는 `Dectector`, 정규식 표현과 일치하여 검출하는 역할만 하는 `Checker`를 객체화를 시도해보았다.
또한 프로토콜을 사용하여 `InputPossible`과 `SystemMenuWorkable` 프로토콜을 준수하게끔 하여
해당 기능을 구현할 수 있도록 하였다.
## Step2 - 사용자 메뉴 표기
[PR #13 | Step2 - 사용자 메뉴 표기](https://github.com/tasty-code/ios-contact-manager/pull/13)
- 프로그램 종료 기능 구현
- 반복문을 통한 프로그램 재실행
사용자의 메뉴 선택 입력을 받아 시스템 메뉴 구성에 맞춰 분기하여 일을 수행할 수 있도록 관리하는
ContactManager를 업데이트 하였으며 검색을 원하는 이름값을 사용자에게 입력받아 `filter`
고차함수를 사용하여 처리하도록 구현하였다.
## Step3 - 목록/검색 기능 구현
- 중복된 데이터는 저장되지 않도록 구현
- 이름으로 연락처 검색
앞서 선택할 수 있도록 제공된 메뉴 중 연락처 목록보기 기능과 사용자로부터 검색할 이름으로 검색할
이름을 입력받아 검색할 수 있는 기능을 구현하는 단계이다.
**[연락처 목록보기]**
1. 프로그램 실행 시 `2`를 입력하여 연락처 목록 메뉴를 선택한다.
2. `- 이름 / 나이 / 연락처` 형식으로 연락처 목록을 출력한다.
**[연락처 검색]**
1. 프로그램 실행 시 `3`을 입력하여 연락처 검색 메뉴를 선택한다.
2. 사용자로부터 검색할 이름을 입력받는다.
3. 이름이 일치하는 연락처를 `- 이름 / 나이 / 연락처` 형식으로 출력한다.
이름이 중복되는 경우 함꼐 출력한다.
기존에 연락처를 저장하던 방식은 Custom type `ContactInformation`을 요소로 갖는 Array Type
이었으나, Set Type으로 변경하여 사용하였다. Set을 사용하면서 Dictionary와 같이 Key 값을 가지는
`Hashable`한 기본 타입이 아닌 Custom type을 사용하면 `Hashable 하지 않기 때문에` ContactInformation에 Hashable을 채택하여 해결하였다.
타입을 변경하면서 느낀점은 다음과 같다.
1. `Array`에서 요소를 추가할 때 `append`를 사용하였으나 `Set`의 경우 `insert`로 값을 추가한다.
2. 값을 추가할 때 `Array`의 경우 중복된 값을 추가하더라도 문제 없이 추가되지만
`Set`의 경우 `insert`로 요소를 추가할 때 중복된 값이 있으면 추가하지 않는다.
3. 연락처 목록 출력 시 중복된 값은 출력되지 않아야 하므로 중복값을 아예 넣지 않거나
제거했어야 했는데, `Set`을 사용하여 중복값 제거의 과정을 별도로 수행하지 않아서 효율적이다.
## 순서도
<img src="https://user-images.githubusercontent.com/71758542/210042473-17ae81e9-4f11-45f5-9462-49b596420b71.png" width="1500">
## 연락처 추가 출력 화면
<img src="https://user-images.githubusercontent.com/92699723/210034468-700b70ea-796b-4dac-b741-182cc6dc6d57.png" width="455">
### 연락처 목록보기 출력 화면
<img src="https://user-images.githubusercontent.com/92699723/210034466-6b26de10-4165-4e54-a9a6-4a9ed14acbf4.png" width="419" >
### 연락처 검색 출력 화면
<img src="https://user-images.githubusercontent.com/92699723/210034464-de2babaa-e26f-4f5f-b5e2-5b25a5917475.png" width="422">