+) 프로토콜 타입제약은 Associated type을 써야 한다는데…. 프로토콜 공부하고 다시 배워갈게용

🪄 마법 같은 Swift 제네릭 이야기

intro) 갑자기(?) Generic을 한 이유..

사실 정식 커리큘럼대로라면 아직 나오기엔 너무 이르지만, 서버통신을 부시기 위해서 저 T가 너무 걸리적거려서 먼저 제네릭 타입을 정리하려고 한다. 나중에 야우쓰 시즌 2 커리큘럼 만들때 어케 하는게 좋을까..? 고민을 해봐야겠당!

class BaseAPI{
    public func judgeStatus<T: Codable>(by statusCode: Int, _ data: Data, _ object: T.Type) -> NetworkResult<Any> {
        let decoder = JSONDecoder()
        guard let decodedData = try? decoder.decode(GenericResponse<T>.self, from: data)
        else {
            return .pathErr
        }
        
        switch statusCode {
        case 200..<205:
            guard decodedData.data != nil else {
                print("⛔️ \\(self)애서 디코딩 오류가 발생했습니다 ⛔️")
                return .decodedErr
            }
            return .success(decodedData.data as Any)
        case 400..<500:
            return .requestErr(decodedData.message ?? "요청에러")
        case 500:
            return .serverErr
        default:
            return .networkFail
        }
    }

1. Generic

Apple 공식문서 왈 “Swift에서 가장 강력한 기능 중 하나”라고 평가를 받는 Generic은

타입에 의존하지 않는 범용 코드를 작성할 때 사용한다

제네릭을 사용하면 중복을 피하고, 코드를 유연하게 작성할 수 있다

라고 설명되어있으며, 실제 Swift의 표준 라이브러리가 대다수 제네릭으로 선언된다. 감이 안 잡힐게 뻔하니까 예시를 들어서 설명하도록 하겠다.

⇒ 다양한 객체에 대해 구현이 동일한 메서드나 타입을 컴파일 타임에 확인해 주는 강력한 도구

1-1. Generic 함수

: 제네릭을 이용한 함수

자 우리는 두 개의 Int 타입 변수 값을 바꿔주는 swap함수를 구현을 해볼것이다.

func swapToInt(_ a: inout Int, _ b: inout Int) {
		let tempA = a
		a = b
		b = tempA
}

근데 여기서 내가 String 타입 변수를 바꿔주는 함수를 구현하고 싶다. 그러면 새로운 함수를 만들어야겠쬬? 뭐 오버로딩을 하는 방법도 있겠고

func swapToInt(_ a: inout Int, _ b: inout Int) {
		let tempA = a
		a = b
		b = tempA
}

func swapToString(_ a: inout String, _ b: inout String) {
		let tempA = a
		a = b
		b = tempA
}

아니 그럼 여기서 개발자라면 (사실 난 그렇지 않은데) 짜증이 나야된다. ”아니 내가 같은 기능을 쓰는 함수를 여러개 만들어서 메모리를 낭비시켜야돼?” (이렇게 생각하는 놈이 변태다.)

그래서 Swift는 Generic 타입을 제공해서 아래와 같이 중복을 피하고 유연하게 코드를 짤 수 있게 해준다!

저렇게 T를 써줘서 만들어줄 수 있는데, 저 T는 타입 파라미터라고 불린다.

func swapToVariable<T>(_ a: inout T:, _ b: inout T) {
		let tempA = a
		a = b
		b = tempA
}

1-2. 타입 파라미터

<T>라고 불렸던 타입 파라미터는 새로운 형식으로 생성되는 것이 아니라, 실제 함수가 호출될 때 해당 매개변수의 타입으로 대체되는 Placeholder이다.