---
만국박람회 [STEP3] Jeremy, 준호
안녕하세요 ***`올라프`*** ☃️
@1Consumption
STEP3 PR 입니다. 잘 부탁드립니다.
## ✏️ 구현 내용
---
---
#### ViewController AutoLayout
오토레이아웃을 적용해서 이미지 뷰의 크기를 잡아주고, 가로로 회전했을 때도 정상적으로 표시하도록 했습니다.
| ExpositionViewController| ExpositionEntriesViewController | EntryDetailViewController |
| -------- | -------- | -------- |
| <img src="https://i.imgur.com/QNczrXi.jpg" width="170px"/> | <img src="https://i.imgur.com/LwSUILC.png" width="170px"/> | <img src="https://i.imgur.com/h1tH8Wx.jpg" width="170px"/> |
|<center>storyboard</center>|<center>code</center>|<center>storyboard</center>|
| ExpoEntriesViewController(.Landscape) | EntryDetailVeiwController(.Landscape) |
| -------- | -------- |
| <img src="https://i.imgur.com/SeOGx2D.png" width="300px"/> | <img src="https://i.imgur.com/uBK1K4Y.png" width="300px"/> |
---
#### Acessability
사용자가 원하는 크기로 텍스트를 읽을 수 있도록 Label과 Button에 Dynamic Type을 적용했습니다.
| ExpositionViewController | ExpoEntriesViewController | EntryDetailViewController |
| -------- | -------- | -------- |
| <img src="https://i.imgur.com/PA69s8W.png" width="200px"/> | <img src="https://i.imgur.com/B7Wgb7L.png" width="200px"/> | <img src="https://i.imgur.com/phW1qey.jpg" width="200px"/> |
## 🧐 코드를 작성할 때 고민되었던 점
뷰 구성을 스토리보드와 코드 방식을 둘 다 사용해보았습니다.
`ExpositionViewController`,`EntryDetailViewController` -> Storyboard
`ExpoEntryCell` -> Code
* 스토리보드 UI 장단점
- 장점 : 뷰를 쉽게 추가할 수 있고, 추가한 뷰가 바로 시각화되기 때문에 작업 내용을 확인하기 편함.
- 단점 : 뷰가 많아지고 화면이 복잡해지면 가독성이 떨어짐.
* 코드 UI 장단점
- 장점 : 코드로 작성하면 변경사항을 추적하기 쉬움.
- 단점 : 실제 뷰가 어떻게 그려질 지 바로 확인하기 어렵다.
* 이번엔 간단히 뷰를 구성할 수 있고 결과를 바로 확인할 수 있는 스토리보드를 우선적으로 사용했습니다.
* CustomCell(ExpoEntryCell)의 contentView의 sub view는 코드를 사용해서 구성해 보았습니다. 스토리보드로 만들다 보니 많은 설정들을 한눈에 보기 어려워서 코드로 작성하는 방법을 써보았습니다.
## 조언을 얻고 싶은 부분
___
`ExpositionManager`,`ExpoEntriesManager` 의 기능을 분리하기위해 아래와 같이 [🔗 테스트 브랜치](https://github.com/junho15/ios-exposition-universelle/commit/4ac8350ab730295a4ea1cd815d8770e7c09927b3)에서 Manager타입을 구현했습니다.
```swift!
typealias Manager = Decoder & ImageMaker
// protocol Decoder extension
extension Decoder {
func configureFromJson<T: Decodable>(assetName: String, type: T?) -> T? {
guard let dataAsset: NSDataAsset = NSDataAsset(name: assetName) else { return nil }
let jsonDecoder: JSONDecoder = JSONDecoder ()
guard let data = try? jsonDecoder.decode(T?.self, from: dataAsset.data) else { return nil }
return data
}
}
// protocol ImageMaker extension
extension ImageMaker {
func makeImage(name: String) -> UIImage? {
return UIImage(named: name)
}
func downloadImage(url: Data) -> UIImage? {
return UIImage(data: url)
}
}
```
#### 1.1) 이떄 아래의 코멘트에서 남겨주신 내용은 위의 예제와 같이 메소드롤 만들어보라는 방향성을 잡아주신 것 같다는 생각이 드는데 맞게 이해한걸까요? ( 아직 본 브랜치에 적용하지 않았습니다. )

#### 1.2) 위의 기능분리 방식에 대한 방향성이 올바른지 궁금합니다.
관련 질문 끝 ---
___
#### 2.1) 커스텀 셀의 contentView의 imageView와 label을 코드로 만들었습니다. 아래와 같이 awakeFromNib() 메서드를 override 하였습니다. 여러 뷰들을 한 곳에서 만들다 보니 코드가 길어지는 데, 여기서도 따로 기능 분리를 하는 게 맞을까요?
#### 2.2) 한다면 entryImageView, entryNameLabel, entryShortDescriptionLabel, stackView 별로 각각 메서드(인스턴스를 만들고 필요한 속성을 잡아준 뒤 return하는 메서드)를 추가하는 게 좋을까요?
```swift
// ExpoEntryCell.swift
override func awakeFromNib() {
super.awakeFromNib()
entryImageView = UIImageView()
entryImageView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(entryImageView)
entryNameLabel = UILabel()
entryNameLabel.translatesAutoresizingMaskIntoConstraints = false
entryNameLabel.font = UIFont.preferredFont(forTextStyle: .title1)
entryNameLabel.adjustsFontForContentSizeCategory = true
entryNameLabel.numberOfLines = 0
entryShortDescriptionLabel = UILabel()
entryShortDescriptionLabel.translatesAutoresizingMaskIntoConstraints = false
entryShortDescriptionLabel.font = UIFont.preferredFont(forTextStyle: .callout)
entryShortDescriptionLabel.adjustsFontForContentSizeCategory = true
entryShortDescriptionLabel.numberOfLines = 0
stackView = UIStackView(arrangedSubviews: [entryNameLabel, entryShortDescriptionLabel])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.alignment = .fill
stackView.distribution = .fill
stackView.contentMode = .scaleAspectFit
stackView.axis = .vertical
self.contentView.addSubview(stackView)
NSLayoutConstraint.activate([
entryImageView.widthAnchor.constraint(equalTo: entryImageView.heightAnchor),
entryImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
entryImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15.0),
entryImageView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.2),
stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 10),
stackView.leadingAnchor.constraint(equalTo: entryImageView.trailingAnchor, constant: 8.0),
stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10)
])
}
```
---

#### 1. [🌏 프로젝트 소개](#About)
#### 2. [👥 팀원](#Team)
#### 3. [🏞 구현 내용](#Features)
#### 4. [🔥 고민한 점](#Troubleshooting)

* 만국박람회의 정보와 정보를 조회하는 앱입니다.

| <center> Jeremy | <center> 준호 |
| -------- | ---------|
| <a href="https://ibb.co/K6tWhrT"><img src="https://i.imgur.com/RbVTB47.jpg" border="0" width="200"></a> | <img src="https://user-images.githubusercontent.com/88357373/197145292-c806a131-bd9d-47ca-8b2a-8842f748f63f.png" width="200"/>
| <center>[*@yjjem*](https://github.com/yjjem)</center> |[<center>*@junho15*](https://github.com/junho15) </center> |
---

| <img src="https://i.imgur.com/e1qEwlf.png"/> | <img src="https://i.imgur.com/5MFQy5D.png"/>|
| -------- | -------- |
| <center><img src="https://i.imgur.com/3DBiTTf.gif" height="500"/></center> | <center><img src="https://i.imgur.com/YKtrn2J.gif" height="500"/></center> |
| |사용자가 원하는 크기로 텍스트를 읽을 수 있도록 Label과 Button에 Dynamic Type을 적용|
---

#### 1. Cell Constraint
`문제` stackView가 imageView보다 작아질 때, imageView가 ContentView에 붙어버리는 문제 발생했습니다.
`해결 방안` imageView의 top, bottom에 greaterThen으로 최소값을 10을 주어서 해결했습니다.
| <center> 셀의 AutoLayout 제약 시각화 </center> |
| -------- |
| <center><img src="https://i.imgur.com/oMLrCVf.png" width="700px"/></center> |
#### 2. 기본 Cell의 레이아웃 조정 한계
`문제` Cell의 style을 Subtitle로 해서 구현할 수 있을 것 같았지만, cell contentView의 기본 subview들에게 직접적으로 Constraint를 설정하는 것에 있어 한계가 있었습니다.
`해결 방안` Table View Cell의 style을 Custom으로 바꿔서 code로 Contet View를 구성하고 constraint를 추가했습니다.
|<center><img src="https://i.imgur.com/O4NS6Iz.png" width="300px"/>👎</center>| <center><img src="https://i.imgur.com/TKIYEW3.png" width="300px"/>👍</center>|
| -------- | -------- |
| <center><img src="https://i.imgur.com/JlMnXqV.jpg" height="500"/></center> | <center><img src="https://i.imgur.com/LwSUILC.png" height="500"/></center>|
#### 3. 코드의 중복성
`문제` 첫번째 화면과 두번째 화면에 같은 역할을 하지만 중복되는 메소드가 있습니다.
`해결 방안`
중복되는 코드를 제거하기 위해 JSONDecoder의 extension에 decode 메서드를 추가했습니다. 제네릭 타입을 사용해서 두 화면 모두에서 사용할 수 있도록 했습니다.
```swift
extension JSONDecoder {
func decode<T: Decodable>(from fileName: String, to: T) -> T?
guard let dataAsset: NSDataAsset = NSDataAsset(name: filName) else { return nil }
do {
return try self.decode(T.self, from: datAsset.data)
} catch {
return nil
}
}
}
```
#### 4. UI 구성 방법
`문제` 이번엔 간단히 뷰를 구성할 수 있고 결과를 바로 확인할 수 있는 스토리보드를 우선적으로 사용했습니다. 하지만 스토리보드로 만들다보니 뷰가 많아지고 constraint를 계속 추가하다보니 한눈에 보기 어렵고 변경내역을 추적하기 힘들었습니다.
`해결 방안` CustomCell(ExpoEntryCell)의 contentView의 sub view는 코드를 사용해서 구성했습니다.
* 스토리보드 UI 장단점
- 장점 : 뷰를 쉽게 추가할 수 있고, 추가한 뷰가 바로 시각화되기 때문에 작업 내용을 확인하기 편함.
- 단점 : 뷰가 많아지고 화면이 복잡해지면 가독성이 떨어짐.
* 코드 UI 장단점
- 장점 : 코드로 작성하면 변경사항을 추적하기 쉬움.
- 단점 : 실제 뷰가 어떻게 그려질 지 바로 확인하기 어렵다.
<img src="https://github.com/junho15/ios-exposition-universelle/blob/step2/expo_main_221028.gif?raw=true">