본문 바로가기

iOS

Fetching website data into memory

Fetching website data into memory

Receive data directly into memory by creating a data task from a URL session

  • URLSession에서 DataTask를 생성하여 데이터를 메모리로 직접 수신한다.

For small interactions with remote servers, you can use the URLSessionDataTask class to receive response data into memory (as opposed to using the URLSessionDownloadTask class, which stores the data directly to the file system)

  • 원격서버와 소규모 상호 작용의 경우 URLSessionDataTask 클래스를 사용하여 응답 데이터를 메모리로 수신할 수 있다.(데이터를 파일 시스템에 직접 저장하는 URLSessionDownloadTask 클래스를 사용하는 것과 반대로)

A data task is ideal for uses like calling a web service endpoint

  • 데이터 작업은 웹 서비스 엔드포인트 호출과 같은 사용에 이상적입니다.
  • 엔드포인트(Endpoint): 웹 애플리케이션에서 클라이언트가 서버에 요청을 보내는 특정 URL

You use a URL session instance to create the task

  • URLSession 인스턴스를 사용하여 작업을 만들 수 있다.

If your needs are fairly simple, you can use the shared instance of the URLSession class

  • 니즈가 꽤 단순하다면,  URLSession 클래스의 shared 인스턴스를 사용할 수 있다.

If you want to interact with the transfer through delegate callbacks, you’ll need to create a session instead of using the shared instance

  • Delegate 콜백들을 통한 전송과 상호작용 하려면, shared 인스턴스를 사용하는 대신 세션을 생성해야 한다.

You use a URLSessionConfiguration instance when creating a session, also passing in a class that implements URLSessionDelegate or one of its subprotocols

  • 세션을 생성할 때 URLSessionConfiguration 인스턴스를 사용하고 URLSessionDelegate 또는 해당 하위 프로토콜 중 하나를 구현하는 클래스도 전달한다.

Sessions can be reused to create multiple tasks, so far each unique configuration you need, create a session and store it as a property

  • 세션은 여러 작업을 만드는데 재사용 될 수 있으므로 필요한 고유한 구성마다 세션을 만들고 속성으로 저장합니다.

Note

  • Be careful to not create more sessions than you need
  • For Example, if you have several parts of your app that need a similarly configured session, create one session and share it among them
  • 필요 이상의 session을 만들지 않도록 주의하세요.
  • 예를 들어, 앱의 여러 부분에서 유사하게 구성된 세션이 필요한 경우, 하나의 세션을 만들고 공유하도록 하세요.

Once you have a session, you create a data task with one of the dataTask() methods

  • 세션이 있다면, dataTask()메서드들 중 하나를 사용하여 데이터 작업을 생성합니다.

Tasks are created in a suspended state, and can be started by calling resume()

  • 작업들은 일시 정지 상태에서 생성되고, resume()호출과 함께 시작됩니다.

 

Receive results with a completion handler

The simplest way to fetch data is to create a data task that uses a completion handler

  • 데이터를 받는 간단한 방법은 완료 핸들러를 사용한 데이터 작업을 생성하는 것 입니다.

With this arrangement, the task delivers the server’s response, data, and possibly errors to a completion handler block that you provide

  • 이 방식을 사용하면, 작업이 서버의 응답이나 데이터, 가능한 에러들을 제공된 완료 핸들러 블럭으로 전달합니다.

Shows the relationship between a session and a task, and how results are delivered to the completion handler.

  • 세션과 작업 사이의 관계도를 보여주고 결과가 어떻게 완료 핸들러로 배달되는지를 보여줍니다.

To create a data task that uses a completion handler, call the dataTask(with:) method of URLSession

  • 완료핸들러를 사용하여 데이터 작업을 생성하기 위해,URLSession의 dataTask(with:) 메서드를 호출합니다.

 

Your completion handler needs to do three things:

  1. Verify that the error parameter is nil. If not, a transport error has occurred; handle the error and exit.
  2. Check the response parameter to verify that the status code indicates success and that the MIME type is an expected value. If not, handle the server error and exit.
  3. Use the data instance as needed.
  • 완료 핸들러는 3가지를 충족합니다.
  • 1. 에러 파라미터가 nil인지 검증합니다. 만약 아니라면, 통신 오류가 발생됩니다. 에러를 대응하고 종료합니다..
  • 2. 응답 파라미터를 확인합니다. 상태 코드가 성공을 나타내는지, 그리고 MIME 형식이 기대된 값과 맞는지 검증합니다. 만약 아니라면 서버 에러를 대응하고 종료합니다.
  • 3. 필요한 데이터 인스턴스를 사용합니다.
  • MIME 형식이란 문서, 파일 또는 바이트 집합의 성격과 형식을 나타낸다.
  • 메세지 내부에 다른 파일을 전송할 수 있도록 하는 전자메일 프로토콜

 

Listing 1 shows a startLoad() method for fetching a URL’s contents.

  • 그림 1은 URL의 콘텐츠를 가져오기 위한 startLoad() 메서드를 보여줍니다.

It starts by using the URLSession class’s shared instance to create a data task that delivers its results to a completion handler.

  • 결과를 완료 핸들러로 전달하는 데이터 작업을 생성하기 위해 URLSession 클래스의 shared 인스턴스를 사용하면서 시작합니다.

After checking for local and server errors, this handler convert the data to a string, and uses it to populate a WKWebView outlet.

  • 로컬과 서버의 에러들을 확인한 후, 핸들러는 데이터를 문자열로 변환합니다. 그리고 이를 사용하여 WKWebView를 채웁니다.

Of course, your app might have other uses for fetched data, like parsing it into a data model.

  • 물론, 앱이 가져온 데이터를 다른 곳에 사용할 수 있습니다. (데이터 모델로 파싱하는 것과 같은)

Listing 1 Creating a completion handler to receive data-loading results

  • 그림 1: 데이터 로딩 결과를 받는 완료 핸들러를 생성
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) {
            DispatchQueue.main.async {
                self.webView.loadHTMLString(string, baseURL: url)
            }
        }
    }
    task.resume()
}

 

Important

The completion handler is called on a different Grand Central Dispatch queue than the one that created the task. Therefore, any work that uses data or error to update the UI — like updating webView — should be explicitly placed on the main queue, as shown here

  • 중요
  • 완료 핸들러는 작업이 생성된 곳과 다른 GCD queue에서 호출됩니다.
  • 그러므로 데이터나 에러를 사용하여 UI를 업데이트 하는 모든 작업은 위에 예시처럼 명시적으로 메인 큐에서 배치해야합니다.

 

Receive transfer details and results with a delegate

  • Delegate를 통한 전송 세부 정보 및 결과를 받아보세요.

For a greater level of access to the task’s activity as it proceeds, when creating the data task, you can set a delegate on the session, rether than providing a completion handler.

  • 진행되는 작업 활동보다 더 높은 수준의 액세스를 위해 데이터 작업을 생성할 때 완료 핸들러를 제공하는 대신 세션에 delegate를 설정할 수 있습니다.

Shows this arrangement

With this approach, portions of the data are provided to the urlSession( : dataTask: didReceive: ) method of URLSessionDataDelegate as they arrive, until the transfer finishes or fails with an error.

  • 이러한 접근방식을 사용하면, 전송이 완료되거나 오류로 인해 실패할 때까지 데이터의 일부가 도착하는대로 URLSessionDataDelegate의 urlSession(: dataTask: didReceive: ) 메서드를 통해 데이터가 제공됩니다.

The delegate also receives other kinds of events as the transfer proceeds.

  • delegate는 전송이 진행됨에 따라 다른 종류의 이벤트들도 수신합니다.

You need to create your own URLSession instance when using the delegate approach, rather than using the URLSession class’s simple shared instance.

  • Delegate 방식을 사용할 땐, URLSession 클래스의 간단한 shared 인스턴스를 사용하는 것 보다 자신만의 URLSession 인스턴스를 생성할 필요가 있습니다.

Creating a new session allows you to set your own class as the session’s delegate, as shown in Listing 2.

  • 새로운 세션을 생성하는 것은 그림 2와 같이 자신만의 클래스를 세션의 delegate로 설정할 수 있습니다.

Declare that your class implements one or more of the delegate protocols(URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate, and URLSessionDownloadDelegate)

  • 하나이상의 delegate 프로토콜을 구현한 클래스를 정의하세요.(URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate, 그리고 URLSessionDownloadDelegate)

Then create the URL session instance with the initializer init(configuration: delegate: delegateQueue: )

  • 그다음 생성자를 통해 URLSession 인스턴스를 생성하세요. (Configuration: delegateL delegateQueue: )

You can customize the configuration instance used with this initializer

  • 생성자를 통해 configuration 인스턴스를 커스터마이징할 수 있습니다.

For example, it’s a good idea to set waitsForConnectivity to true.

  • 예를들어, waitsForConnectivity를 true로 설정하는 것이 좋습니다.

That way, the session waits for suitable connectivity, rather than failing immediately if the required connectivity is unavailable.

이렇게 하면 필요한 연결을 사용할 수 없는 경우 세션이 즉시 실패하지 않고 적절한 연결을 기다립니다.

 

Listing 2 Creating a URLSession that uses a delegate

private lazy var session: URLSession = {
    let configuration = URLSessionConfiguration.default
    configuration.waitsForConnectivity = true
    return URLSession(configuration: configuration,
                      delegate: self, delegateQueue: nil)
}()

 

Listing 3 shows a startLoad() method that uses this session to start a data task, and uses delegate callbacks to handle received data and errors.

  • 그림 3은 데이터 작업을 시작하는 세션을 사용하고 전달받은 데이터와 에러들을 핸들링하는 delegate 콜백을 사용하는 startLoad() 메서드를 보여줍니다.

This listing implements three delegate callbacks:

  • urlSession( :dataTask :didReceive: completionHandler: ) verifies that the response has a successful HTTP status code, and that the MIME type is text/html or text/plain. If either of these is not the case, the task is canceled otherwise it’s allowed to proceed
  • urlSession( : dataTask :didReceive: ) takes each Data instance received by the task and appends it to a buffer called receivedData.
  • urlSession( :task :didCompleteWithError: ) first looks to see if a transport-level error has occurred. If there is no error, It attempts to convert the receivedData buffer to a string and set it as the contents of webView.
  • urlSession( :dataTask :didReceive :compeltionHandler: )는 응답이 성공 HTTP 상태 코드를 갖고 있는지, MIME 형식이 text/html 혹은 text/plain 인지 검증합니다. 둘 중 하나라도 해당되지 않는다면 작업이 취소되고 그렇지 않으면 게속 진행됩니다.
  • urlSession( :dataTask :didReceive: )는 작업에서 수신한 각 Data 인스턴스를 받고, receivedData로 호출된 버퍼에 저장됩니다.
  • urlSession( :task :didCompleteWithError:)은 먼저 전송 수준 오류가 발생했는지 확인합니다. 에러가 없다면 receivedData 버퍼를 문자열로 변환하여 webView의 컨텐츠로 설정하도록 시도합니다.

 

Listing 3 Using a delegate with a URL session data task

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)
        }
    }
}

 

The various delegate protocols offer methods beyond those shown in the above code, for handling authentication challenges, following redirects, and other special cases.

  • 다양한 delegate 프로토콜은 현재 코드에서 보여주는 것보다 더 많은 메서드들을 제공합니다. 인증 문제 처리, 리디렉션 추적, 기타 특수 사례 등등

Using a URL Session, in the URLSession discussion, describes the various callbacks that may occur during a transfer.

  • URLSession 토론에서 URLSession 사용은 전송중에 발생하는 다양한 콜백을 설명합니다

'iOS' 카테고리의 다른 글

iOS Combine  (0) 2025.02.19
URLSession 번역  (0) 2024.12.13
URL Loading System 번역  (2) 2024.12.10
SwiftGen 사용  (0) 2024.11.26
[iOS][버그해결] 이중으로 들어간 CollectionViewCell안 CollectionViewCell이 재사용되는 버그  (0) 2024.11.16