본문 바로가기

학습활동

URL Loading System

URL Loading System

  • 표준 Internet 프로토콜(ex HTTP)을 사용하여 URL과 상호 작용하고 서버와 통신
  • URL Loading System은 비동기이기 때문에, 앱이 응답을 하면서 데이터나 오류를 별도 처리 가능
  • URL Session 인스턴스로 하나 이상의 URLSession Task 인스턴스를 생성
  • → 이것으로 데이터를 앱에 반영, 파일을 다운로드, 데이터와 파일을 원격 위치에 업로드를 함

  • private browsing의 경우 Ephemeral Configuration을 사용해야함
  • 각 Session은 주기적 업데이트를 위해 Delegate와 연결되어있음
  • → Custom Delegate를 사용하면 사용자가 지정한 Completion handler를 호출 X
  • → 만약 Default Delegate를 사용하면 사용자가 지정한 Completion handler를 호출

Fetching Website Data into Memory

웹사이트 데이터를 메모리로 가져오기

  • Session에서 Data Task를 생성하여 데이터를 메모리로 직접 수신
  • 원격 서버와 상호작용 하는 경우, URLSessionDataTask을 사용하여 데이터를 메모리로 수신해라
  • web Service의 endpoint와 같은 곳에서 사용하는 것이 이상적임
  • Endpoint : API가 서버에서 리소스에 접근할 수 있도록 가능하게 하는 URL, 커뮤니케이션 채널의 한 쪽 끝
  • → 서로 역할이 중첩되는 경우가 생길 수 있음
  • API : 두 시스템(어플리케이션)이 상호작용할 수 있게 하는 프로토콜의 총집합. 프로그램들이 서로 상호작용하는 것을 도와주는 매개체
  • Session은 필요한만큼만 생성하라. 비슷한 구성의 Session은 퉁쳐라

Receive Results with a Completion Handler

Completion Handler로 결과 받기

  • 데이터를 가져오는 가장 간단한 방법
  • Completion Handler를 사용하여 Data task를 만드는 방식으로 서버의 응답, 데이터 및 오류를 전달

func startLoad() {
    let url = URL(string: "<https://www.example.com/>")!
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            self.handleClientError(error)
            return
        }
        guard let httpResponse = response as? HTTPURLResponse,
            (200...299).contains(httpResponse.statusCode) else {
            self.handleServerError(response)
            return
        }
        if let mimeType = httpResponse.mimeType, mimeType == "text/html",
            let data = data,
            let string = String(data: data, encoding: .utf8) {
            // UI를 업데이트는 main에서 해야하니까~
            DispatchQueue.main.async {
                self.webView.loadHTMLString(string, baseURL: url)
            }
        }
    }
    task.resume()
}

Receive Transfer Details and Results with a Delegate

  • 진행중인 작업에 대한 높은 수준의 접근을 제공하기 위해 completion handler 대신 delegate를 설정할 수 있음
  • → delegate는 작업 중간에 끼어들 수 있기 때문
  • delegate는 전송 과정이 진행되는 동안에도 다른 종류의 이벤트를 수신할 수 있음
  • → delegate를 사용할 땐 sharedSession은 delegate를 사용할 수 없기 때문에, customizable Session을 만들어서 사용해야함
  • init(configuration:delegate:delegateQueue:)
  • → 만약 waitsForConnectivity를 true로 하면, 필요한 연결을 사용할 수 없는 경우 즉시 실패하지 않고 세션이 적절한 연결을 기다림
  • → 사용자가 Session을 인스턴스화 할 때 customize가 가능
private lazy var session: URLSession = {
    let configuration = URLSessionConfiguration.default
    configuration.waitsForConnectivity = true
    return URLSession(configuration: configuration,
                      delegate: self, delegateQueue: nil)
}()

Delegate callback 함수

urlSession(_:dataTask:didReceive:completionHandler:)

  • 응답에 성공적인 HTTP 상태 코드가 있고 MIME 유형이 text/html 또는 text/plain인지 확인합니다. 둘 중 하나라도 해당되지 않으면 작업이 취소됩니다. 그렇지 않으면 계속 진행할 수 있습니다.

urlSession(_:dataTask:didReceive:)

  • 태스크에서 수신한 각 Data 인스턴스를 받아서 receivedData라는 버퍼(임시저장소. 큐와 유사. 변기..의..뒤에 물탱크..가..버퍼)에 추가

urlSession(_:task:didCompleteWithError:)

  • 먼저 전송 수준 오류가 발생했는지 확인합니다. 오류가 없으면 receivedData 버퍼를 문자열로 변환하고 webView의 내용으로 설정하려고 시도합니다.

 

// 버퍼
var receivedData: Data?

func startLoad() {
    loadButton.isEnabled = false
    let url = URL(string: "<https://www.example.com/>")!
    receivedData = Data()
    let task = session.dataTask(with: url)
    task.resume()
}

// delegate methods
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse,
                completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
    guard let response = response as? HTTPURLResponse,
        (200...299).contains(response.statusCode),
        let mimeType = response.mimeType,
        mimeType == "text/html" else {
        completionHandler(.cancel)
        return
    }
    completionHandler(.allow)
}

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
    self.receivedData?.append(data)
}

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    DispatchQueue.main.async {
        self.loadButton.isEnabled = true
        if let error = error {
            handleClientError(error)
        } else if let receivedData = self.receivedData,
            let string = String(data: receivedData, encoding: .utf8) {
            self.webView.loadHTMLString(string, baseURL: task.currentRequest?.url)
        }
    }
}

 

URL Loading System | Apple Developer Documentation

Fetching Website Data into Memory | Apple Developer Documentation

728x90

'학습활동' 카테고리의 다른 글

Swift Performance (2)  (0) 2023.12.11
Swift Performance (1)  (0) 2023.12.11
동시성 프로그래밍  (0) 2023.11.08
Swift Concurrency II  (0) 2023.09.28
Swift Concurrency I  (0) 2023.09.28