7주차 기록: URLSession, Access Control, ARC
🧐 무엇을 배웠나?
- 코드 쪼개기 (Base ViewController, View, TableView, CollectionView)
- 역으로 값전달
- Access Control 접근 제어자
- WKWebView
- URLSession
- ARC
- Any vs AnyObject : Any (모든 타입을 받음), AnyObject (클래스에서만 프로토콜을 정의할 수 있도록 제약)
(+) viewController Naming 하는 법: main, detail 같은 이름 짓기는 지양하기. 훗날 업데이트 과정에서 그 역할이 바뀔 수도 있기 때문에 다른 이름을 지을 것을 고려해볼 것.
🔨 예제
- Photogram
- Media Project 응용 + 개선
📚 과제
- Photogram 역으로 값전달, URLSession 응용해보기
- Media Project (multiple Cell로 각기 다른 API 통신 + UI 적용)
💦 복기
✔️ MultipleCell
from Media Project
고민 했던 부분:
- 간단하게 UI를 구성해보는 것도 과제의 일부였는데, 이것도 은근 어려웠다. 영화 검색 했을 때 어떻게 해야 보기 좋았지? 하는 걸 고민하다 보니 UI도 한 두 번 정도 수정했던 것 같다.
- 과제엔 Base로 각 역할별로 나누어서 구성했고, section을 활용했다. if문 좀 그만 쓰고 싶었는데 이번에도 어김없이 if문 구구절절 코드로 구성하고 말았다. 그 덕분에 쓰다가 괄호 체크만 한 세 번은 한 모양. 나도 ... 짧고 간결한 코드를 쓰고 싶은데 언제쯤..!!
- section 나누는 걸 어떻게 할지 고민했었다. 검색해보니 셀의 내용이 같은 것끼리 묶는 게 좋다고 해서, API 내용 그대로 movie, people, TV 세 개로 섹션을 나누어 셀을 구성했다.
- 이상하게 Out of range 오류를 테이블뷰 만들때마다 뜨는데, count 해줬는데 뭐가 문제야! 외치면서 indexPath.row < movieList.results.count 이런 식으로 고쳐 썼다. 덕분에 if 문 쓰는 나의 코드는 속절없이 길어지고.....
- 그리고 섹션 UI도 고민을 했었는데, 수업에선 header..... 그 이름 긴 걸로 xib 파일로 만들어서 섹션 내 폰트와 높이 지정을 했던 기억이 나서 그걸 코드베이스로 해서 삽입하려니 너무 복잡하게 느껴졌었다. 왜냐면 난 지금 테이블뷰와 컬렉션뷰를 만들면 이게 화면에 안나올까봐 빌드 누를 때마다 긴장하기 때문에 조금... 이것만큼은.. 쉽게하고 싶었던 마음. => 섹션에 대해 검색하다가 heightForHeaderInSection, titleForHeaderInSection 란 걸 알 게 되어서 이 두 개를 써서 정말 간결하게 만들었다. 근데 이건 높이 지정이라던가 폰트 크기 등 조절이 수업 때 섹션 UI로 배웠던 것에 비해 자유롭지가 않아서 별로였던 듯. 몇 외국 블로그에 나온 걸 쓰려고 하니 '이거 곧 기능에서 뺄 예정이야~' 하는 문구가 뜨는 걸 보아 그냥 여러모로 안 쓰는 게 나을 것 같다.
- URLSession을 적용해보려고 했다가, 이미지 파일 외엔 도저히 못 넘기겠어서 + 아직 URLSession을 개념 외 응용은 수업 코드보고 따라치기... 정도 밖에 안되서 일단 보류했다. 2주..뒤엔.. 할 수 있을지도.
✔️ Base
- override의 개념 숙지가 필요했던, base를 나눠서 클래스 생성하기. 부모 클래스를 그대로 활용해서 좋았던 점은 view.background = .white를 꼬박꼬박 해주지 않아도 되었단 것과 하나의 파일 당 쓰이는 코드가 줄어들었다는 것. 다마고치만 떠올리면 내 코드길이에 멀미가 나는데, base를 쓰고나면서부터 길이의 압박이 좀 줄어들었다.
- 오픈소스까지 임포트 해서 쓸 수 있다. → 단, 상속받는 모든 뷰가 사용하고 있어야 함. (ex.하나의 뷰만 alamofire를 사용할 땐 base에 임포트 하는 건 적합하지 않다)
- BaseView
let mainView = SearchView()
override func loadView() {
self.view = mainView
}
baseView를 활용할 땐 꼭 loadView 해주는 걸 잊지 말자. loadView를 해주는 이유 = 애플이 만든 뷰 말고 커스텀뷰를 사용하려면 세팅해주어야 함.
✔️ 역으로 값전달
- property
- closure
- notification
- delegate pattern
- 난.. 사실 아직도 notification 활용은 잘 못 하겠다... ㅎㅎ... 뭔가 개념과 정의를 보면 + 블로그 예시를 보면 대충 알겠는데 모르겠어. 이런 상태. 배열, 딕셔너리를 활용할때마다 좀 많이 헤매는 편인데 값을 딕셔너리로 받아서 그런 것 같기도. 일단은 클로저랑 딜리게이트 위주로 값전달 하기로 했다. 꼭! notification을 써야한다면 어떻게든 해보겠지만...
✔️ Access Control (은닉화)
- 코드에 대한 접근을 제한하거나 조건을 걸고 싶을 때 활용.
- (가장 제한 없음) open > public > internal > fileprivate > private (가장 제한적)
- 사용하는 이유? 결합도가 낮아지고 응집도는 높아짐.
- 비슷한 기능을 하는 요소들끼리 묶기 때문에 관련된 기능들을 하나로 확인/관리할 수 있음. → 프레임워크와 라이브러리의 활용.
- 모듈과 타겟을 기준으로 접근제어자를 다룬다.
- 모듈의 기준 중요
- import를 해야만 접근할 수 있음.
- 각각의 모듈은 각각의 타겟을 가지고 있음.
- open, public : 모듈 밖의 것에 접근할때 사용.
- overriding이 되냐 안 되냐의 차이.
- open은 overriding 가능
- 상속이 가능하다, 클래스에서만 오픈 사용 가능 → 상속의 구조 = 클래스, open 제어자를 쓸 수 있는 건 결국 class뿐.
- public은 다른 모듈에 접근할 때 의미가 있음.
- internal, private, fileprivate : 모듈과 모듈 사이에서의 접근 레벨이 되지 않음. 접근제어가 모듈을 벗어날 수 없음.
- open, public → 다른 모듈에서 접근해서 import를 통해 사용할 때. 애플이 만든 라이브러리와 내가 만든 라이브러리 사용이 가능한 이유. → module로 접근 (내 프로젝트에선 쓰일 일이 없음))
- internal, private, filePrivate → sourcefile로 접근, internal(프로젝트내 모듈내 다 접근 가능하다!) internal class 이 디폴트 설정임. 다른 파일에서 호출하지마! = private
- private이 가장 많이 쓰임.
✔️ WKWebView
- 애플이 제공해주는 코드를 활용하면 된다.
- UINavigationBarAppearance 에 대해서도 배웠다. 스크롤 할때 네비게이션 영역이 사라질 수도, 투명해질 수도 있기 때문.
import UIKit
import WebKit
class WebViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string:"https://www.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}
func reloadButtonclicked() {
webView.reload()
}
func goBackButtonClicked() {
if webView.canGoBack {
webView.goBack()
}
}
func goForwardButtonClicked() {
if webView.canGoForward {
webView.goForward()
}
}
}
https://developer.apple.com/documentation/webkit/wkwebview
✔️ UIResponder
- 사용자의 액션을 감지
- UIView가 상속 받고 있음.
//창을 키자마자 서치바가 올라와서 검색할 수 있게 함.
override func viewDidLoad() {
super.viewDidLoad()
mainView.searchBar.becomeFirstResponder()
}
//서치버튼 누르면 내려갓
extension SearchViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
mainView.searchBar.resignFirstResponder()
}
}
✔️ URLSession
URLSession
- 데이터를 다운로드 하거나 업로드 하는 등의 API를 제공해주는 클래스로 URL이 가리키는 엔드포인트를 가지고 있다.
- URLSession API를 통해 타임아웃, 캐시 정책, 백그라운드 데이터 전송 등 활용할 수 있음.
- 간단하고 기본적인 요청인 경우에는 Shared Session, 별도로 커스텀을 하려면 Session Configuration.
- session Configuration를 활용하면 목적에 따라 Default, Ephemeral, Background Session로 생성 할 수 있음.
URLSessionConfiguration
- 환경설정 (네트워크 통신을 하기위한 설정)
- 시크릿모드
- 보안, 캐싱, 세션
- sharedSession : 가장 기본적으로 구성된 환경세팅. (ex.alamofire)
- 싱글턴 패턴 구조로 기본 설정
- 단순한 네트워트 요청을 할때 주로 사용
- 커스터마이징 X
- DefaultSession : 진행률을 보여주고 싶으면, defaultSession을 사용한다. (shared랑 거의 비슷함...)
- URLSessionConfiguration을 통해 직접 생성하는 세션으로, Shared Session과 기본 설정이 유사.
- 커스터마이징 O
- EphemeralSession (보안)
- shared Session과 기본 설정이 비슷하게 되어 있지만, 쿠키, 캐시, 인증 정보 등을 디스크에 기록하지 않음.
- private 기능 등을 구현할 때 사용 (ex. 시크릿 모드)
- BackgroundSession
- URLSessionConfiguration을 통해 직접 생성하는 세션으로 앱이 실행중이지 않을 때나 백그라운드 상태에서도 데이터를 다운로드 하거나 업로드 할 수 있음.
URLSessionTask
- 세션이 생성된 이후에는 Task를 생성하게 되는데, URLSession을 통해 생성되는 개별 요청 = Task.
- 요청 - 응답 리소스 : (제이슨 )데이터가 적게 듦. 데이터를 전달하는 방식과 구현하려는 목적에 따라 테스크 타입 결정.
- task
- Task는 suspended 상태로 시작하기 때문에, Task를 생성한 이후에는 resume 메서드를 통해 task를 시작할 수 있고, 따라서 resume을 호출해야 네트워크 통신을 시작할 수 있음.
- data : 가장 많이 사용.
- upload
- download : 데이터양이 큰 것.
- stream : 소켓.
- task
URLRequest
- 네트워크 요청에 대한 정보를 표현
- 네트워크에 요청을 하기 위해선 URLSession이 필요.
URLResponse
- 서버로부터 응답 받은 테이터를 처리할 수 있는 방법은 completionHandler 또는 SessionDelegate.
- completionHandler:
- task 다 끝나고 실행. 단 한번만 실행 된다. 이미지 데이터가 크거나 하면 한계가 있기 때문에 delegate 사용을 한다. (shared)
- 서버로부터 전달 받은 data와 HTTP Header, 응답에 대한 메타데이터 등의 정보가 들어있는 response, 요청이 실패했을 때에 대한 error 값을 전달받을 수 있습니다.
- sessionDelegate :
- Task가 실행되는 동안 발생할 수 있는 다양한 상황에 대해서 세부적으로 처리하고자 할때 사용.
- 서버로부터 최초로 응답을 받았을 때, 서버로부터 데이터를 받을 때마다, 데이터 전송을 다 받은 시점 등에 대한 이벤트 처리가 가능.
- 최초응답 / 10%, 20% 중간과정 … 진행률에 대한 대응이 가능하다. (shared X) 응답 중간중간 얼만큼 받았는지 확인하고 싶음 (이게 shared를 사용할 수 없는 이유.)
- Task가 실행되는 동안 발생할 수 있는 다양한 상황에 대해서 세부적으로 처리하고자 할때 사용.
- completionHandler:
? :
- alamofire, kingfisher를 사용하지 않고도 네트워크통신을 할 수 있단 점이 정말 매력적이라고 생각하지만!..... 너무 어렵다. 역시 네트워크 통신 ^^... 들어오자마자 급격히 떨어지는 이해력이란. 주말 내내 URLSession 으로 바꾸는 과제를 해보려고 수업 코드를 봤지만, 프로토콜 + dispatchQueue의 재등장 + 잊고 있던 do-try-catch 활용 등 따로 보면 알겠는 코드가 종합선물세트처럼 함께 있으니 계속 물음표 상태만 되어서 그냥 수업코드를 보고 비슷하게 구현하는 방법으로 일요일 되서야 과제를 해결했다. 그래서 구현한 코드는 searchbar query의 있고 없고 차이 정도였지만.
- 일단 이해한 건, image와 같은 UI적 요소는 main thread가 해결해주어야 한다는 것 (이 부분 일부러 빼놓고 빌드 해보니 보라색 경고가 뜬다. 아마 빼먹어도 이건 보라색 경고 보고 해결하는 방법으로 일단 디스패치 활용 타이밍 잡아도 나쁘지 않을 것 같고... ).
- 한동안은 API Manager 관련 코드는 수업 코드 참고 해야할 것 같다..ㅎ.ㅎㅎㅎ...
✔️ ARC
* 애플 공식 문서 기반으로 정리
ARC는 Automatic Reference Counting의 약자로, Swift란 프로그램 내에서 사용자의 앱 메모리 사용을 추적하고 관리하는 기능이다. ARC는 더이상 필요하지 않는 인스턴스를 메모리에서 자동으로 없애주는 역할을 수행한다. ARC 등장 이전엔 MRC를 사용했는데, MRC는 수동으로 관리해주는 기능이라 개발자가 retain - release (추가-삭제)를 1:1로 다 대응 해주어야 했다.
- Reference Counting (참고 카운팅, RC)는 only 클래스 인스턴스에만 적용된다.
- 인스턴스가 더이상 필요하지 않을 때, ARC는 그 인스턴스가 사용하고 있던 메모리를 지워버리는데, 이는 그 메모리 공간을 다른 용도로 사용하기 위해서이다. 그러니까 필요하지 않는 클래스 인스턴스가 불필요하게 자리를 차지하고 있지 않도록 그 인스턴스와 관련된 메모리를 비워서 메모리를 확보하는 역할을 수행한다.
- 단, 이때 서로를 참조하고 있는 인스턴스들이 있으면 강한 순환 참조가 발생하는 문제가 있다. 아무리 Automatic이라지만 이런 상황에선 reference count가 0이 되지 않아서 떠돌이 인스턴스가 메모리에 남게 되고, 즉 메모리 누수 현상이 되고 만다.
강한 순환참조를 해결할 수 있는 방안 두가지 :
weak vs Unowned
공통점
참조하는 인스턴스의 RC를 증가시키지 않는다.
차이점
- weak : 참조가 메모리에서 해제되면 nil값 (연결고리를 따라서 저장되어있는 값을 모두 nil로 바꿈), 옵셔널 선언 필요, 참조하는 인스턴스가 더 짧은 lifetime을 가질 때 활용할 것
- unowned : 참조가 메모리에서 해제되면 별다른 대응 없음. (메모리에 대한 주소값을 그대로 가지고 있음, 메모리에서 인스턴스가 사라졌다고 하더라도 인스턴스를 참조하고 있는 오너라는 곳에선 여전히 보유하고 있기 때문에, 오너를 호출하면 유저값을 가지고 오려고 함), 참조하는 인스턴스와 lifetime이 같거나 더 길 때 활용할 것, 초기화 필요 없음!
Closure capture
- 값이 아닌 reference를 caputre한다.
- 생명주기가 끝나고도 살아있는 인스턴스가 있어서 캡쳐 기능이 필요하다.
..... 이부분은 좀 더 이해되면 추가하기로. 요즘 수업에서 클로저 코드 작성이 잦아져서 자연스럽게 나도 클로저를 쓰게 되었는데, 딱 액기스 반절만 이해하고 쓰는 기분이라 캡쳐 내용을 배우면서 클로저는... 왜... 다 해내지? 싶어서 조금 혼란스러웠다.
'SeSAC iOS 3기' 카테고리의 다른 글
🌱 새싹 영등포 iOS 앱개발자 데뷔과정 3기 후기 (3) | 2024.06.25 |
---|---|
[SeSAC] iOS 개인앱 <직관로그> 출시 회고 (10) | 2023.10.24 |
🌱 6주차: NotificationCenter, CLLocationManager, MKMapView, UIPageViewController (1) | 2023.08.27 |
🌱 5주차: API 통신, Codable, DispatchGroup, 복습 (1) | 2023.08.20 |
🌱 4주차: 네트워크 통신 (0) | 2023.08.13 |