본문 바로가기

iOS/STUDY

[iOS] Generic 오류 (URLSession과 Decode를 곁들인)

URLSession의 요청이 많아지다보니 공통화를 하고싶어서 Generic에 손을 댔는데

 

생각지도 못한 오류 때문에 시간을 많이 잡아 먹었다.

 

해결책도 사실 근본적인 해결책이라고 볼 순 없지만.. 적어놓고 나중에 완전히 이해되면 다시 볼 생각으로 글을 적어보려고한다.

 

 

오류상황

현재 NetworkManager에 모든 URLSession 작업과 Encode, Decode 함수를 넣어놨는데 

 

Decode 함수를 제네릭으로 만들고 request 함수에서 호출하려고 보니 오류가 발생했다.

 

처음으로 발생한 오류 : 일반 매개변수 T를 유추할 수 없습니다.

Generic parameter 'T' could not be inferred
private func decode<T: Decodable>(data: Data?) -> T? {
    let decoder = JSONDecoder()
    guard let data = data else { return nil }

    do {
        return try decoder.decode(T.self, from: data)
    } catch {
        print(error.localizedDescription)
    }
    return nil
}

private func request<T: Decodable>(requestType: RequestType,
                                   url: URL,
                                   data: Data? = nil,
                                   completion: @escaping (T) -> Void) {
    let request = makeRequest(requestType: requestType, url: url, data: data)

    URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Network Error: \(error.localizedDescription)")
            return
        }

        guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else {
            print("Error: HTTP request failed")
            return
        }

        if let data = data,
           let decodedData = self.decode(data: data) { // 오류발생 !
            completion(decodedData)
        }
    }.resume()
}

 

 

 

 

그래서 생각한 해결책

if let data = data,
   let decodedData = self.decode(data: data) {
    completion(decodedData)
}

----->

if let data = data,
   let decodedData = self.decode<T>(data: data) {
    completion(decodedData)
}

 

 

오류 : 일반 함수를 명시적으로 특수화할 수 없습니다.

Cannot explicitly specialize a generic function

 

ㅇㅅㅇ? 

if let data = data,
   let decodedData = self.decode<T>(data: data) {
    completion(decodedData)
}

if let data = data,
   let decodedData = self.decode<User>(data: data) {
    completion(decodedData)
}

if let data = data,
   let decodedData = self.decode<User.self>(data: data) {
    completion(decodedData)
}

if let data = data,
   let decodedData = self.decode<User.Type>(data: data) {
    completion(decodedData)
}

 

그래서 잠시 별짓을 다해봤는데 안돼서 열심히 구글링을 한 결과..

 

 

 

https://codegrepr.com/question/cannot-explicitly-specialize-a-generic-function/

 

Cannot explicitly specialize a generic function - Codegrepr

I have issue with following code: func generic1<T>(name : String){ } func generic2<T>(name : String){ generic1<T>(name) } the

codegrepr.com

 

여기서 설명과 해결책을 주었는데

최소한 매개변수나 반환값에 T를 사용하거나 타입을 명시해주어야한다..? 여서

매개변수에 type을 지정하게 해주니 오류가 사라졌다.

 

제네릭을 다시 상세하게 문서를 찾아봐야겠다..

private func decode<T: Decodable>(data: Data?, type: T.Type) -> T? {
    let decoder = JSONDecoder()
    guard let data = data else { return nil }

    do {
        return try decoder.decode(T.self, from: data)
    } catch {
        print(error.localizedDescription)
    }
    return nil
}

private func request<T: Decodable>(genericType: T.Type,
                                   requestType: RequestType,
                                   url: URL,
                                   data: Data? = nil,
                                   completion: @escaping (T) -> Void) {
    let request = makeRequest(requestType: requestType, url: url, data: data)

    URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Network Error: \(error.localizedDescription)")
            return
        }

        guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else {
            print("Error: HTTP request failed")
            return
        }

        if let data = data,
           let decodedData = self.decode(data: data, type: T.self) {
            completion(decodedData)
        }
    }.resume()
}