Post

UIKit - URLSession, @escaping 활용 방법

URLSession을 통해 네트워킹을 처리할 때 dataTask 메서드를 사용해서 처리할 작업을 정의함.

이때, dataTask 메서드는 비동기적으로 실행되기 때문에 요청 성공/실패 결과를 그대로 반환할 수 없음.

1
2
3
4
5
6
7
8
9
10
11
12
13
session.dataTask(with: request) { data, response, error in
  if let error = error{
      return nil // 불가능함.
  }

  if let data = data{
      guard let result = try? JSONDecoder().decode(ExampleResult.self, from: data) else{
          return nil // 불가능함.
      }
      
      return result // 불가능함.
  }
}.resume()

이런 이유 때문에 @escaping을 통해서 비동기 처리가 끝났을 때 전달받은 클로저를 실행하여 처리함.

구현 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import UIKit

// MARK: - 응답 객체
struct ResponseWrapper<T: Codable>: Codable {
    let status: Int
    let success: Bool
    let message: String
    let result: T
    let timestamp: String
}

struct RegisterResult: Codable {
    let userSeq: Int
    let email, role, nickname, provider: String
    let createdAt, modifiedAt: String
}

// MARK: - 요청 객체
struct RegisterRequest: Codable{
    let email: String
    let password: String
    let nickname: String
}

// MARK: - 네트워킹 처리 서비스
final class AuthService{
    
    // URLSession 객체 생성
    let session = URLSession.shared
    
    func fetchRegister(data: RegisterRequest, completion: @escaping (RegisterResult?) -> Void){
        
        // URLRequest 생성
        var request = URLRequest(url: URL(string: "http://localhost:9000/api/v1/auth/register")!)
        
        // 매개변수로 전달된 RegisterRequest 직렬화
        let body = try? JSONEncoder().encode(data)
        
        // HTTP Method, Header, Body 설정
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = body
        
        // 네트워킹 작업 정의
        let task = session.dataTask(with: request) { data, response, error in
            // dataTask 메서드가 비동기로 실행되기 때문에 응답받은 데이터를 바로 리턴할 수 없음.
            // 따라서 클로저를 매개 변수로 받은 후 요청이 성공하거나 실패했을 때 호출하여 콜백 함수 구조로 처리함.
            
            if let error = error{
                completion(nil)
                return
            }
            
            if let data = data{
                // 응답 데이터 역직렬화
                guard let result = try? JSONDecoder().decode(ResponseWrapper<RegisterResult>.self, from: data) else{
                    completion(nil)
                    return
                }
                
                // 콜백 함수 호출
                completion(result.result)
            }
        }
        
        task.resume() // 작업 시작
    }
}

// MARK: - 테스트용 ViewController
final class DummyViewController{
    private let authService = AuthService()
    
    func register(request: RegisterRequest){
        authService.fetchRegister(data: request) { result in
            dump(result)
        }
    }
}

// MARK: - 테스트
let request = RegisterRequest(email: "test2@gmail.com", password: "test1234!", nickname: "test2gmail")

let vc = DummyViewController()

vc.register(request: request)

결과

1
2
3
4
5
6
7
8
...
    - userSeq: 15
    - email: "test2@gmail.com"
    - role: "ROLE_USER"
    - nickname: "test2gmail"
    - provider: "LIBRONOTE"
    - createdAt: "2025-11-04T09:24:29"
    - modifiedAt: "2025-11-04T09:24:29"
This post is licensed under CC BY 4.0 by the author.