Post

Troubleshooting - Capture of 'completion' with non-sendable type '(RegisterResult?) -> Void' in a @Sendable closure 경고

Troubleshooting - Capture of 'completion' with non-sendable type '(RegisterResult?) -> Void' in a @Sendable closure 경고

에러

URLSession을 통해 네트워킹을 처리하는 것을 공부하던 중 아래와 같은 경고가 나타남.

발생 경고 image

원인

구현했던 코드

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
final class AuthService{
    
    let session = URLSession.shared
    
    func fetchRegister(data: RegisterRequest, completion: @escaping (RegisterResult?) -> Void){
        
        var request = URLRequest(url: URL(string: "http://localhost:9000/api/v1/auth/register")!)
        
        let body = try? JSONEncoder().encode(data)
        
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = body
        
        let task = session.dataTask(with: request) { data, response, error in

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

dataTask 메서드는 비동기적으로 실행되는데, 이것은 메인 쓰레드가 아닌 백그라운드 쓰레드가 접근할 수 있고 여러 쓰레드가 동시에 접근할 수도 있다는 뜻임.

이런 이유 때문에 매개 변수로 받는 completionHandler는 자동으로 Swift 컴파일러에서 @Sendable 클로저로 간주함.

@Sendable 클로저란 여러 스레드나 동시성 컨텍스트에서 안전하게 공유되거나 접근될 수 있는 타입에 클로저를 뜻함.

@escaping이 붙어 있는 completion@Sendable로 처리되지 않음.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let task = session.dataTask(with: request) { data, response, error in
    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)
    }
}

dataTask@Sendable로 간주되는 클로저 내부에서 escaping 타입의 클로저를 호출하고 있음.

이때, 컴파일러는 여러 쓰레드에서 호출될 수 있는 dataTask 메서드에서 Thread-safe 하지 않은 completion 클로저를 호출하는 것에 경고를 하는 것임.

This post is licensed under CC BY 4.0 by the author.