### (전)Step3 피드백에 대한 커멘트
#### extension에서의 init()구현
extension에서 struct의 커스텀 init()을 구현하면 멤버와이즈 init()도 사용할 수 있어 굳이 멤버와이즈 init()까지 선언해줄 필요가 없는 것을 확인했습니다!
- 다음과 같이 extension에서 커스텀 init()을 선언하도록 했고 멤버와이즈 init()의 선언은 제거했습니다 🙏
```swift
struct Address {
let city: String
let stree1: String
var combined: String {
return [self.city, self.stree1].joined(separator: " ")
}
}
extension Address {
init() {
self.city = ""
self.stree1 = ""
}
}
```
#### hashable
- 자료를 키-값으로 저장하여 키를 넣어주면 해당하는 값을 반환하는 것을 해시 테이블이라고 이해했습니다.
- 자료는 실제로 해시 테이블에 저장되는데 키를 넣어야 해시테이블에 저장된 값의 주소를 알 수 있고 최종적으로 값을 받아올 수 있는 것이라 생각했습니다.
- 그리고 이렇게 키를 받아 해시테이블의 값을 반환하는 역할을 하는 것이 hasher라고 이해했습니다.
- 그리고 같은 키를 넣으면 같은 값을 반환해야하고 특정 키를 넣으면 항상 해당하는 값을 반환받아야합니다. 이처럼 키끼리 구분이 가능해야해서 Hashable은 Equatable을 채택하고 있고 그 때문에 `==` 연산자로 키가 같은 상황을 정의해주었습니다.
#### UIKit, Foundation
말씀하신대로 UIImage만 import하기 위해 UIKit.UIImage를 import 해보았습니다!
Foundation은 기본 데이터 타입이랑 각종 계산과 네트워킹을 지원한다고 알고있습니다.
#### URLCache
- 메모리 크기는 참고한 예제들에서 흔히 보이는 512 메가바이트로 키워주었습니다.
- URLSessionConfiguration은 URLSession에서 데이터 데이터를 업로드하거나 다운로드할 때의 설정을 의미하며 캐싱 policy나 여러 요구사항 등을 설정할 수 있습니다. shared는 싱글턴으로 기본적인 요청을 수행할 때 사용하며 default와는 달리 커스터마이징을 할 수 없습니다.
- ImageManager는 데이터를 이미지로 변환하는 작업을 하고 있고 request아닌 url로 요청을 보냅니다. 원래는 캐시를 들고 있는 싱글턴 구조도 생각했었는데 URLCache를 사용하게되면서 기존의 NetworkModule과 로직이 거의 흡사해진 것 같습니다. MediaNetworkable 프로토콜을 따르도록 하여 각종 미디어들을 다운/변환/가공하는 작업을 해줄 예정이었는데 엘림의 말씀을 듣고보니 중복코드를 최소화하는 식으로 리팩토링을 할 수 있는지 고민해보면 좋을 것 같습니다 🤩
#### SceneDelegate
- 이 부분은 엘림의 블로그를 우연찮게 보고 따라해봤어요ㅎㅎ
- iOS12까지는 Process LifeCycle과 UI Lifecycle App Delegate에서 모두 관여했습니다.
- 멀티태스킹을 위하여 iOS13부터는 Process LifeCycle과 Session Lifecycle만 App Delegate가 맡으며, Scene Delegate가 UI Lifecycle 부분만 담당하게 바뀌되어 SceneDelegate에서 RootViewController를 만들어 첫 화면으로 보이도록 설정하였습니다.
- `makeKeyAndVisible()`을 실행해주어야 윈도우가 나타났습니다. 더 찾아보니 key로 만들어준 윈도우는 다른 윈도우보다 앞에 배치되며 키보드 입력 등을 받는다는 것을 알게되었습니다.
1) 연결될 scene을 `scene(_:willConnectTo:option:)`메서드로부터 전달받으면 그것을 윈도우에 담아줍니다.
2) scene을 UIWindowScene으로 다운캐스팅하여 UIWindow을 생성합니다.
3) window.rootViewController에 보여주고자 하는 ViewController를 대입시켜줍니다.
4) makeKeyAndVisible()로 보여주게 합니다.
```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let mainViewController = SomeViewController()
let navigationController = UINavigationController(rootViewController: mainViewController)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
}
```
#### fatal 동작이 일어나지 않게 하는 방법은 없을까요?😀
Failable Initializers는 초기화를 실패했을떄를 대비하는 이니셜라이저로 알고 있습니다.
그래서 default로 fatal Error가 발생하도록 구현이 되어있었는데요.
initializers가 실패했을때는 fatalError로 앱이 종료되는게 아닌 에러를 보여주는것이 좋다고 생각이 됬습니다. 그래서 이전에 배운 assertionFailure를 사용해봤습니다.
```swift
required init?(coder: NSCoder) {
super.init(coder: coder)
assertionFailure(WeatherConstants.initFailure.text)
}
```
#### formatter에서 extension하는건 어때요?
좋은것 같습니다. formatter를 extension으로 분리하여 Cell이 formatter를 안들고 있게되어 역할을 분리할수도 있고, 타입메서드로 구현하여 굳이 인스턴스화를 하지 않아도 되는 장점이 생긴것 같아요!
#### lazy를 선택하는 기준
self를 통해 다른 프로퍼티에 접근하거나 인스턴스 메서드를 사용하여 초기화 하는 프로퍼티의 경우 lazy로 선언을 하였습니다. 하지만 해당 코드를 다시보니 프로퍼티에 lazy가 필요없는 프로퍼티에 lazy가 붙어있어 lazy가 필요없는 프로퍼티들은 lazy를 삭제 하였습니다.
#### super.init을 해야하는 이유
* 생각해보면 부모 클래스의 프로퍼티들이 모두 초기화 해야 자식 클래스에서 사용할수 있다고 생각합니다.
* 자식 클래스가 부모 클래스의 메서드를 오버라이드하고 있는 경우 부모 클래스가 해당 메서드에서 정의한 내용을 super.init()으로 실행해주어 부모 클래스가 의도한 부분도 온전히 실행되도록 해야한다고 생각합니다. 그래야만 부모 클래스에서 필수적으로 해주어야하는 기초 세팅을 마무리해 자식 클래스에서 버그나 오작동 없이 실행할 수 있다고 알고 있습니다.
* 그리고 viewDidLoad()의 경우 [super.init()을 호출하라고](https://developer.apple.com/documentation/appkit/nsviewcontroller/1434476-viewdidload#:~:text=If%20you%20override%20this%20method%2C%20call%20this%20method%20on%20super) 되어 있는 것 같습니다.
* Swift의 class 초기화 과정은 Two Phase Initialization 과정을 거칩니다.
* Phase1에서는 각 저장된 프로퍼티를 정해진 초기값으로 초기화하는 과정입니다.
* Phase2에서는 새로운 인스턴스의 사용이 준비됐다고 알려주기 전에 저장된 프로퍼티에 대해 수정할수 있습니다.
