1. 프로젝트 소개
2. 팀원
3. 타임라인
4. 시각화된 프로젝트 구조
5. 실행 화면
6. 트러블 슈팅
7. 참고 링크
팀 회고
쥬스 메이커 앱에서는 버튼을 통해 원하는 쥬스를 선택하여 만들 수 있습니다.
Harry | kokkilE |
---|---|
Github 링크 | Github 링크 |
- 23.01.02(월) ~ 23.01.04(수)
- 과일 가게 클래스 구현
- 쥬스 메이커 구조체 구현
- 23.01.06(금)
- 메인화면에서 재고 수정화면으로 화면전환 구현
- 쥬스 제조시 성공, 실패 alert 구현
- 23.01.09(월) ~ 23.01.10(화)
- Autolayout 적용
- 과일의 개수를 나타내는 레이블에 개수 표시 구현
- 재고 수정화면에서 재고 수정 기능 구현
- 화면 전환 시 과일의 개수를 나타내는 레이블 업데이트 구현
- 23.01.16(월) ~ 23.01.17(화)
- Autolayout, 스토리보드 스택뷰 속성 변경
- 변수명 및 프로퍼티 속성 변경
├── Controller
| ├── AppDelegate
| ├── SceneDelegate
| ├── JuiceMakeViewController
| └── StockManagerViewController
├── Model
| ├── FruitStore
| ├── JuiceMaker
| ├── Juice
| ├── JuiceMakerError
| ├── Fruit
| └── UpdateLabelsDelegate
└── View
├── Main
└── Assets
func addStock(fruit: Fruit, quantity: Int) throws {
guard let selectedFruitStock = fruitStock[fruit] else {
throw FruitStoreError.invalidFruitInput
}
fruitStock.updateValue(selectedFruitStock + quantity, forKey: fruit)
}
- 위 메서드를 예시로
fruitStock[fruit]
딕셔너리 값을 가져올때, 옵셔널 바인딩이 필요했다. - 저 부분에서
fruitStock
에서 인덱스로Fruit
타입을 받고, 후에 버튼 입력으로 해당 메서드를 기능하게 한다고 가정했을때 저 부분에서 옵셔널 바인딩이 되지않아 에러를 던져주는 경우는 없을거라 생각이 된다. - 따라서 guard let 을 통해 옵셔널 바인딩이 되지않을 경우 return 을 해주어 그냥 함수를 종료시키는 것이 맞을지, 아니면 저런식으로 일어날 가능성이 없는 에러를 던져주는 것이 맞는지 고민을 했다.
- 결론적으로, 에러를 던져서 "이 흐름은 내가 의도한 방향이 아니다, 올바른 흐름이 아니다" 라고 표시하는 것이 협업하는 팀원과 미래의 내가 봤을 때 명확할 것이라 판단해 에러처리를 했다.
enum Juice {
case strawberryJuice
case bananaJuice
case kiwiJuice
case pineappleJuice
case strawberryBananaJuice
case mangoJuice
case mangoKiwiJuice
var recipe: [Fruit: Int] {
switch self {
case .strawberryJuice:
return [.strawberry: 16]
case .bananaJuice:
return [.banana: 2]
case .kiwiJuice:
return [.kiwi: 3]
case .pineappleJuice:
return [.pineapple: 2]
case .strawberryBananaJuice:
return [.strawberry: 10, .banana: 1]
case .mangoJuice:
return [.mango: 3]
case .mangoKiwiJuice:
return [.mango: 2, .kiwi: 1]
}
}
}
- 이전에는 주스 레시피를 case를 사용하지 않고 static let 키워드로 사용해 딕셔너리를 저장했다.
- 주스의 레시피는 메서드의 파라미터로 들어가기 때문에 하나의 타입으로써 표현하는 것이 메서드를 사용하기에 더 좋을 것 같아주스 각각의 메뉴명을 케이스로 지정하고 연산 프로퍼티를 통해 딕셔너리를 반환하는 방식으로 바꾸었다.
두번째 화면에서 재고 수정작업이 끝나고 화면이 dismiss
될때, 변경사항을 첫번째 화면의 레이블을 업데이트 하기위해 세 가지 방법을 고려했다.
- delegate 패턴 적용
- Notification
추가적으로 이벤트 전달 방식은 아니지만, UIViewController
의 State Method 활용하여 첫 번째 화면이 Appear될 때 마다 실행하게 할 수 있으므로 편하게 적용이 가능했다. 하지만 이번 프로젝트에서는 이벤트 전달을 구현해보고자 이 방법은 채택하지 않았다.
Notification 방식은 이벤트를 전달받는 수신지가 여러 객체일 경우 적용하기 좋지만, 발신지의 post만 보고 코드의 흐름을 파악하기 어렵다는 단점이 있습니다.
delegate 패턴은 delegate가 nil일 경우 crash가 날 수 있고, 여러 객체에 이벤트를 알리기 어렵다는 단점이 있습니다.
이번 프로젝트는 이벤트 수신지가 한 군데 뿐이고, delegate 패턴을 적용하는 것이 가독성이 좋다고 생각해 delegate 패턴을 적용했다.
- Swift Language Guide - Type Casting
- Swift Language Guide - Access Control
- Swift Langauge Guide - Nested Types
- Swift Language Guide - Error Handling
- Swift Language Guide - Protocol
- 여러 방법을 고려하고 장단점을 분석해서 좋은 코드를 작성하고자 노력한 점
- 하나의 문제를 해결하기 위해 여러방면에서 시도를 해보았던 점
- 같이 공식문서를 열심히 읽으면서 공부했던 것 !
- 유지보수가 가능한 코드를 작성하도록 노력하자! 현재는 과일종류 하나만 추가되어도 코드 이곳저곳에 과일종류를 사용하기 때문에 수정하기가 매우 번거롭다. 프로젝트가 끝나더라도 꾸준히 고민해보기.
-
해리 -> 코낄이
- 코낄이 3주간 정말 고생많았습니다. 코낄이를 보면서 여러가지 방향에서 문제를 바라보는 시각에 한번씩 놀라기도 했고 같이 문제를 해결하면서 많이 배운것 같습니다. 항상 여유있는 모습과 적극적인 자세로 프로젝트를 함께 해주셔서 감사했습니다 ! 다음에 또 봐요 😄
-
코낄이 -> 해리
- 학습할 주제가 발생하면 이해할 때 까지 파고드는 성실함이 있습니다.
- 알고 있는 지식을 잘 설명해줍니다. 👍
- 의견을 잘 수용해줍니다.
- 상대방에게 칭찬을 많이 해줍니다.
- 대화를 잘 이끌어줍니다.