[swift] BASIC_10. URLSession


웹 통신과 Protocol

웹 통신

  • 인터넷 상에서의 통신을 말함
  • 많은 정보들이 주고 받기에 인터넷에는 엄격한 규약이 존재한다. 이를 Protocol이라 한다.




HTTP

HTTP

HTTP란 Hyper Text Transfer Protocol의 약자이다.
말 그대로 Hyper Text를 전송하기 위한 Protocol이다.

HTTP 통신은 기본적으로 요청(Request)와 응답(Response)로 이루어져있다.

http


http



HTTP Packet

HTTP 통신에서는 정보를 Packet에 넣어 보내게 된다.
Packet은 Header와 Body로 나누어져 있다. Hader에는 보내는 사람의 주소, 받는 사람의 주소가 담겨져 있다.
Body에는 보내려는 정보가 담겨져 있다.

packet




HTTP Method, Status

Http Method

HTTP 요청을 하려면 URL 주소와 HTTP 메소드를 지정해줘야 한다.

  • GET: 클라이언트가 서버에 리소스를 요청할 때 사용
  • POST: 클라이언트가 서버의 리소스를 새로 만들 때 사용
  • PUT: 클라이언트가 서버의 리소스를 전체 수정할 때 사용
  • PATCH: 클라이언트가 서버의 리소스를 일부 수정할 때 사용
  • DELETE: 클라이언트가 서버의 리소스를 삭제할 때 사용
  • HEAD: 클라이언트가 서버의 정상 작동 여부를 확인할 때 사용
  • OPTIONS: 클라이언트가 서버에서 해당 URL이 어떤 메소드를 지원하는지 확인할 때 사용
  • CONNECT: 클라이언트가 프록시를 통하여 서버와 SSL 통신을 하고자할 때 사용
  • TRACE: 클라이언트와 서버간 통신 관리 및 디버깅할 때 사용



HTTP Status

서버는 클라이언트 요청에 응답하면서, 요청을 성공적으로 이루어졌는지를 알려준다.

  • 100번 대 Informational: 요청 정보를 처리 중
  • 200번 대 Success: 요청을 정상적으로 처리함
  • 300번 대 Redirection: 요청을 완료하기 위해 추가 동작 필요
  • 400번 대 Client Error: 서버가 요청을 이해하지 못함
  • 500번 대 Server Error: 서버가 요청 처리 실패함




URLSession

URLSession

특정한 URL을 이용하여 데이터를 다운로드하고 업로드하기 위한 API

  • URLSessionConfiguration: URLSession 생성
  • URLSessionTask: 실제 Server와 통신



세션 종류

  • Shared Session(공유 세션) - URLSession.shared()
    • 싱글톤으로 사용할 수 있다.
    • 기본 요청을 위해 사용하는 세션이다.
    • 맞춤 설정을 할 수는 없다.
    • 쉽게 만들어 사용할 수 있다.
  • Default Session(기본 세션) - URLSession(configuration: .default)
    • 공유 세션과 비슷하게 작동한다.
    • 직접 원하는 맞춤 설정을 할 수 있다.
    • 캐시와 쿠키, 인증 정보 등을 디스크에 저장한다.
    • 순차적으로 데이터를 처리하기 위해 Delegate를 지정할 수 있다.
  • Ephemeral Session(임시 세션) - URLSession(configuration: .ephemeral)
    • 공유 세션과 비슷하게 작동한다.
    • 캐시와 쿠키, 인증 정보 등을 디스크가 아닌 메모리에 저장한다.
    • 세션 만료시 데이터가 사라진다.
  • Background Session(백그라운드 세션) - URLSession(configuration: .background)
    • 앱이 실행되지 않는 동안, 백그라운드에서 컨텐츠 업로드 및 다운로드를 수행할 수 있다.



URLSession Task

  • URLSessionDataTask
    • 데이터 객체를 사용하여 데이터를 요청하고 응답받는다.
    • 짧고 빈번하게 요청할 때 사용한다.
  • URLSessionUploadTask:
    • 데이터 객체 또는 파일 형태의 데이터를 업로드하는 작업을 수행한다.
    • 앱이 실행되지 않았을 때 백그라운드 업로드를 지원한다.
  • URLSessionDownloadTask:
    • 데이터를 다운로드 받아 파일의 형태로 저장하는 작업을 수행한다.
    • 앱이 실행되지 않았을 때 백그라운드 다운로드를 지원한다.
  • URLSessionStreamTask:
    • TCP/IP 연결을 생성할 때 사용한다.
  • URLSessionWebSocketTask:
    • HTTP 통신을 할 때 사용한다.



URLSession Life Cycle

  1. Session Configuration을 결정하고, Session을 생성한다.
  2. 통신할 URL과 Request 객체를 설정한다.
  3. 사용할 Task를 결정하고 그에 맞는 Completion Handler나 Delegate 메소드들을 작성한다.
  4. 해당 Task를 실행한다.
  5. Task 완료 후, Completion Handler 클로저가 호출이 된다.

[swift] BASIC_09. DispatchSourceTimer, UIView Animation


DispatchSourceTimer

특정 시간이 지난 뒤 이벤트를 발생시킨다거나, 반복적인 주기로 특정 작업을 수행하는 등의 행위를 할 때 사용

swift에서 timer class를 이용하여 타이머를 구현할 수 있지만, pomodoroTimer에서는 DispatchSourceTimer를 이용하여 구현하였다.

var timer: DispatchSourceTimer?

func startTimer() {
    if self.timer == nil {
        self.timer = DispatchSource.makeTimerSource(flags: [], queue: .main) // UI를 수정해야 하므로 .main(ios에서 오직 한 개만 존재하는 스레드)
        self.timer?.schedule(deadline: .now(), repeating: 1)
        self.timer?.setEventHandler(handler: { [ weak self] in
        guard let self = self else { return } // strong reference
        self.currentSeconds -= 1
        
        let hour = self.currentSeconds / 3600
        let minutes = (self.currentSeconds % 3600) / 60
        let seconds = (self.currentSeconds % 3600) % 3600
        self.lblTimer.text = String(format: "%02d:%02d:%02d", hour, minutes, seconds)

        self.progressView.progress = Float(self.currentSecnods) / Float(self.duration)

        if self.currentSeconds <= 0 {
            self.stopTimer()
            AudioServicesPlaySystemSound(1005)
        }
        })
    }
}

func stopTimer() {
    // 일시정지 상태에서 timer에 nil을 대입하면 에러가 난다. 그렇기에 resume() 메서드를 사용해야 한다.
    if self.timerStatus == .pause {
        self.timer?.resum()
    }
    self.timerStatus = .end
    self.timer?.cancel()
    self.timer = nil    // 타이머를 종료할 때 nil을 사용하여 해제시켜야 메모리를 소모하지 않는다.
}

@IBAction func tapStart(_ sender: UIButton) {
        self.duration = Int(self.datePicker.countDownDuration) // 2분 -> 120초와 같이 저장해줌.
//        debugPrint(self.duration)
        
        switch self.timerStatus {
        case .end:
            self.currentSeconds = self.duration
            self.timerStatus = .start
            self.startTimer()
        case .start:
            self.timerStatus = .pause
            self.timer?.suspend()   // 타이머 일시정지
        case .pause:
            self.timerStatus = .start
            self.timer?.resume()
        }
    }




UIView Animation

UIView 클래스는 Animation에서 사용되는 api를 타입 메서드로 제공하고, 이 메서드를 활용하여 비교적 단순한 코드로 애니메이션을 구현하였다.
pomodoroTimer에서 버튼을 hidden으로 구현하지 않고, alpha 값으로 구현하여 자연스럽게 구현하였다.
또한, 타이머가 진행될 때 imageView를 회전시키는 애니메이션을 구현하였다.

enum TimerStatus {
    case start
    case pause
    case end
}

class ViewController: UIViewController {
    func setTimerInfoViewVisible(isHidden: Bool) {
        if isHidden {
            UIView.animate(withDuration: 0.5, animations: {
                self.lblTimer.alpha = 0
                self.progressView.alpha = 0
                self.datePicker.alpha = 1
                self.imgPomodoro.transform = .identity
            })
        } else {
            UIView.animate(withDuration: 0.5, animations: {
                self.lblTimer.alpha = 1
                self.progressView.alpha = 1
                self.datePicker.alpha = 0
            })
        }

        // hidden 사용
//        self.lblTimer.isHidden = isHidden
//        self.progressView.isHidden = isHidden
        
        self.btnStart.isSelected = !isHidden
        self.btnCancel.isEnabled = !isHidden
        self.datePicker.isHidden = !isHidden
    }

    @IBAction func tapStart(_ sender: UIButton) {
        self.duration = Int(self.datePicker.countDownDuration) // 2분 -> 120초와 같이 저장해줌.
//        debugPrint(self.duration)
        
        switch self.timerStatus {
        case .end:
            self.currentSeconds = self.duration
            self.timerStatus = .start
            self.setTimerInfoViewVisible(isHidden: false)
            self.startTimer()
        case .start:
            self.timerStatus = .pause
            self.btnStart.isSelected = false
            self.timer?.suspend()   // 타이머 일시정지
        case .pause:
            self.timerStatus = .start
            self.btnStart.isSelected = true
            self.timer?.resume()
        }
    }
}

[swift] BASIC_08. UITabBar


UITabBar

UITabber

앱에서 서로 다른 하위작업, 뷰, 모드 사이의 선택을 할 수 있도록, 탭바에 하나 혹은 하나 이상의 버튼을 보여주는 컨트롤



UITabBarController

다중 선택 인터페이스를 관리하는 컨테이너 뷰 컨트롤러로, 선택에 따라 어떤 자식 뷰 컨트롤러를 보여줄 것인지가 결정




UICollectionView

데이터 항목의 정렬된 컬렉션을 관리하고 커스텀한 레이아웃을 사용해 표시하는 객체를 말한다.



Cell

컬렉션 뷰의 콘텐츠를 표시



Supplementary View

섹션에 대한 정보를 표시



Decoration View

컬렉션 뷰에 대한 배경을 꾸밀 때 사용




CollectionView Layouts

CollectionView Layouts

  • UICollectionViewLayout
  • UICollectionViewFlowLayout



UICollectionViewFlowLayout

  1. Flow 레이아웃 객체를 작성하고 컬렉션 뷰에 이를 할당한다.
  2. 셀의 width, height를 정한다.
  3. 필요한 경우 셀들 간의 좌우 최소 간격, 위아래 최소 간격을 설정한다.
  4. 섹션에 header와 footer가 있다면 이것들의 크기를 지정한다.
  5. 레이아웃의 스크롤 방향을 설정한다.



Spacing

spacing.png



Inset

inset.png




UICollectionViewDataSource

컬렉션 뷰로 보여지는 콘텐츠들을 관리하는 객체

public protocol UICollectionViewDataSource: NSObjectProtocol {
    
    // 지정된 섹션에 표시할 셀의 개수를 묻는 메서드
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int

    // 컬렉션뷰의 지정된 위치에 표시할 셀을 요청하는 메서드
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

    // 섹션의 개수를 묻는 메서드
    eptional func numberOfSections(in collectionView: UICollectionView) -> Int
}




UICollectionViewDelegate

콘텐츠의 표현, 사용자와의 상호작용과 관련된 것들을 관리하는 객체

[swift] BASIC_07. UITableView


UITableView

데이터들을 목록 형태로 보여줄 수 있는 가장 기본적인 UI 컴포넌트
또한 UIScrollView를 상속해 스크롤을 통해 리스트 형태로 많은 정보를 보여줄 수 있다.

  • 여러 개의 Cell을 가지고 이고 하나의 열과 여러 줄의 행을 지니고 있으며, 수직으로만 스크롤 가능하다.
  • 섹션을 이용해 행을 그룹화하여 컨텐츠를 좀 더 쉽게 탐색할 수 있다.
  • 섹션의 헤더와 푸터에 View를 구성하여 추가적인 정보를 표시할 수 있다.



Delegate

  • TableView의 동작과 외관을 담당한다.



DataSource

  • Data를 받아 View를 보여주는 담당




UITableViewDataSource

  • UITableViewDataSource는 테이블 뷰를 생성하고 수정하는데 필요한 정보를 테이블 뷰 객체에 제공
public protocol UITableViewDataSource: NSObjectProtocol {
    
    // 각 세션에 표시할 행의 개수를 묻는 메서드
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

    // 특정 인덱스 Row의 Cell에 대한 정보를 넣어 Cell을 반환하는 메서드
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

    // 총 섹션 개수를 묻는 메서드
    optional func numberOfSections(in tableView: UITableView) -> Int

    // 특정 섹션의 헤더 타이틀을 묻는 메서드
    optional func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?

    // 특정 세션의 풋터 타이틀을 묻는 메서드
    optional func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String?

    // 특정 위치의 행이 편집 가능한지 묻는 메서드
    optional func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
    
    // 특정 위치의 행을 재정렬 할 수 있는지 묻는 메서드
    optional func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool

    // 테이블 뷰 섹션 인덱스 타이틀을 묻는 메서드
    optional func sectionIndexTitles(for tableView: UITableView) -> [String]?

    // 인덱스에 해당하는 섹션을 알려주는 메서드
    optional func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int

    // 스와이프 모드, 편집 모드에서 버튼을 선택하면 호출 되는 메서드
    // 해당 메서드에서는 행에 변경사항을 Commit 해야 함
    optional func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStle, forRowAt indexPath: IndexPath)

    // 행이 다른 위치로 이동되면 어디에서 어디로 이동했는지 알려주는 메서드
    optional func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
}




UITableViewDelegate

  • UITableViewDelegate는 테이블 뷰의 시각적인 부분을 설정하고, 행의 액션 관리, 엑세서리 뷰 지원, 그리고 테이블 뷰의 개별 행 편집을 도와준다.
public protocol UITableViewDelegate: UiScrollViewDelegate {

    // 행이 선택되었을 때 호출되는 메서드
    optional func tableView(_ tableView: UITableview, didSelectRowAt indexPath: IndexPath)

    // 행이 선택 해제되었을 때 호출되는 메서드
    optional func tableView(_ tableView: UITableview, didDeselectRowAt indexPath: IndexPath)

    // 특정 위치 행의 높이를 묻는 메서드
    optional func tableView(_ tableView: UITableview, heightForRowAt indexPath: IndePath) -> CGFloat

    // 지정된 섹션의 헤더뷰 또는 푸터뷰에 표시할 View가 어떤 것인지 묻는 메서드
    optional func tableView(_ tableView: UITableview, viewForHeaderInSection section: Int) -> UIView?
    optional func tableView(_ tableView: UITableview, viewForFooterInSection section: Int) -> UIView?

    // 지정된 섹션의 헤더뷰 또는 푸터뷰의 높이를 묻는 메서드
    optional func tableView(_ tableView: UITableview, heightForHeaderInSection section: Int) -> CGFloat
    optional func tableView(_ tableView: UITableview, heightForFooterInSection section: Int) -> CGFloat

    // 테이블 뷰가 편집 모드에 들어갔을 때 호출되는 메서드
    optional func tableView(_ tableView: UITableview, willBeginEditingRowAt indexPath: IndexPath)

    // 테이블 뷰가 편집 모드에서 빠져나왔을 때 호출되는 메서드
    optional func tableView(_ tableView: UITableview, didEndEditingRowAt indexPath: IndexPath?)

    // 테이블 뷰가 셀을 사용하여 행을 그리기 직전에 호출되는 메서드
    optional func tableView(_ tableView: UITableview, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)

    // 텡븗 ㅠ로부터 셀이 화면에 사라지면 호출되는 메서드
    optional func tableView(_ tableView: UITableview, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
}

[swift] BASIC_06. UIStackView


UIStackView

열 또는 행에 View 들의 묶음을 배치할 수 있는 간소화된 인터페이스

UIStackView를 사용하지 않으면 제약조건이 많이 필요하다. 하지만 UIStackView를 사용하면 복잡한 제약조건 없이 구성이 가능하다.



Vertical Stack View, Horizontal Stack View

stackView



UIStackView Attribute

stackViewAttribute




UIStackView Distribution

StackView 안에 들어가는 뷰들의 사이즈를 어떻게 분배할지 설정하는 속성


Fill: UIStackView의 방향에 따라 가능한 공간을 각 SubView의 우선순위를 따져 모두 채우게 된다.

  • UIStackView안에 들어있는 SubView들의 크기가 더 크다면, 우선순위가 낮은 SubView의 크기를 감소시킨다.
  • UIStackView안에 들어있는 SubView들의 크기가 더 작다면, 우선순위가 큰 SubView의 크기를 증가시킨다.

fill


Fill Equally: UIStackView의 방향에 따라 가능한 공간을 각 SubView의 크기를 동일하게 하여 모두 채우게 된다.

fillEqually


Fill Proportionally: UIStackView의 방향에 따라 가능한 공간을 비율에 맞춰 모두 채운다.

fillProportionally


Equal Spacing: 슬라이드와 같이 View 간 간격이 일정하게 설정된다.

equalSpacing


Equal Centering: StackView의 반영에 따라서 각 SubView의 Center와 Center의 길이를 동일하게 설정한다.

equalCentering




UIStackView Alignment

StackView의 SubView들을 어떤 식으로 정렬할지 결정하는 속성


Fill: 방향이 horizontal일 경우 위, 아래의 공간을 모두 채운다.

alignmentFill


Leading: SubView들이 왼쪽에 정렬된다.

alignmentLeading


Top: SubView들이 위쪽에 정렬된다.

alignmentTop


Center: StackView 방향에 따라 SubView의 Center를 StackView의 Center에 맞춰 정렬한다.

alignmentCenter


Trailing: SubView들이 오른쪽에 정렬된다.

alignmentTrailing


Bottom: SubView들이 아래쪽에 정렬된다.

alignmentBottom


First Baseline: SubView들의 First Baseline에 맞춰 정렬된다. StackView가 Horizontal일 경우에만 사용 가능하다.

alignmentFirstBaseline


Last Baseline: SubView들의 Last Baseline에 맞춰 정렬된다. StackView가 Horizontal일 경우에만 사용 가능하다.




UIStackView Spacing

StackView 안에 들어가는 뷰들의 간격을 조정하는 속성

spacing