본문 바로가기

iOS 앱 개발자 프로젝트/Swift 문법 정복하기

[Swift] protocol, associatedtype, typealias

메서드, 속성 및 기타 요구사항의 청사진을 정의하여 클래스, 구조체 또는 열거형에서 구현할 수 있는 일종의 인터페이스인 프로토콜에 대해 공부해 봅니다.

 

#1. protocal

#2. associatedtype


#1. protocal

 

☑️  protocol

 

    • 프로토콜에서는 이름과 타입 그리고 gettable, settable을 명시한다.
    • 프로토콜은 설계된 조건만 정의를 하고 제시를 할 뿐 스스로 기능을 구현하지 않는다.
    • class, structure, enum이 프로토콜을 ‘채택’하고 요구사항을 충족하면 프로토콜을 ‘준수’했다고 한다.
    • 프로퍼티는 항상 var로 선언해야 한다.
    • 메서드를 정의할 때 메서드 이름과 리턴값을 지정할 수 있고, ****{}(구현 코드)는 적지 않는다.
    • 상속과 유사하다고 볼 수도 있겠지만 class 이외에 struct나 enum도 프로토콜을 채택할 수 있다는 특징이 있습니다
    • 상속은 다중 상속이 불가능하지만 프로토콜은 다중 상속이 가능합 (확장성이 높음)
    protocol 프로토콜이름 {
     // 프로토콜 정의
    }
    
    // 상속받는 클래스의 프로토콜 채택
    class 클래스이름: 슈퍼클래스, 프로토콜1, 프로토콜2 {
     // 클래스 정의
    }
    
    protocol Vehicle {
        var speed: Double { get set } // get과 set을 모두 요구하는 가변 속성
        var manufacturer: String { get } // 읽기 전용 속성
    }
    
    class Car: Vehicle {
        var speed: Double = 0.0 // get과 set이 요구되는 속성을 구현
        var manufacturer: String = "Toyota" // 읽기 전용 속성을 구현
    }
    
    class Bicycle: Vehicle {
        var speed: Double = 0.0 // get과 set이 요구되는 속성을 구현
        var manufacturer: String { return "Giant" } // 읽기 전용 속성을 연산 프로퍼티로 구현
    }
    
    let car = Car()
    car.speed = 60.0 // set 가능
    print(car.speed) // get 가능
    print(car.manufacturer) // get 가능
    
    let bike = Bicycle()
    bike.speed = 20.0 // set 가능
    print(bike.speed) // get 가능
    print(bike.manufacturer) // get 가능
    
    // 예시
    protocol Student {
        var studentId: Int { get set }
        var name: String { get }
        func printInfo() -> String
    }
    
    struct UnderGraduateStudent: Student {
        var studentId: Int
        var name: String
        var major: String
        
        func printInfo() -> String {
            return "\\(name), whose student id is \\(studentId), is major in \\(major)"
        }
    }
    
    struct GraduateStudent: Student {
        var studentId: Int
        var name: String
        var degree: String
        var labNumber: Int
        
        func printInfo() -> String {
            return "\\(name), member of lab no.\\(labNumber), has a \\(degree) degree"
        }
    }
    
    // 프로토콜은 타입으로서도 사용가능
    let underGraduate: Student = UnderGraduateStudent(studentId: 1, name: "홍길동", major: "computer")
    let graduate: Student = GraduateStudent(studentId: 2, name: "김철수", degree: "master", labNumber: 104)
    
    let studentArray: [Student] = [underGraduate, graduate]
    
    // 프로토콜의 다중상속
    protocol Coordination
     {
        var top: String { get set }
        var pants: String { get set }
    
        init(top: String, pants: String)
    
        func checkCoordination()
    }
    
    protocol Hair {
        var hair: String { get }
    
        func checkHairStyle()
    }
    
    struct Person: Coordination, Hair {
        var top: String
        var pants: String
        let hair: String = "포마드"
    
        func checkHairStyle() {
            print("오늘의 헤어스타일은 \\(hair)스타일")
        }
    
        func checkCoordination() {
            print("상의: \\(top)\\n하의: \\(pants)")
        }
    
        init(top: String, pants: String) {
            self.top = top
            self.pants = pants
        }     
    }
    
    let safari: Person = Person(top: "긴팔", pants: "반바지")
    safari.checkHairStyle()
    safari.checkCoordination()
    //오늘의 헤어스타일은 포마드스타일
    //상의: 긴팔
    //하의: 반바지
    
#2. associatedtype, typealias

 

 

☑️  associatedtype

  • 프로토콜 내에서 실제 타입을 명시하지 않고, 해당 프로토콜을 채택하는 타입에서 실제 타입을 결정하도록 하는데 사용
  • 프로토콜에서 특정 메서드, 속성 또는 서브스크립트의 반환 타입이나 매개변수 타입으로 구체적인 타입을 명시하지 않고 대신 associatedtype으로 선언하여 프로토콜을 채택하는 타입에서 실제 타입을 정의할 수 있다.

☑️  typealias

  • typealias는 기존 타입에 대해 새로운 이름을 지정하거나 복잡한 타입에 대한 간결한 별칭을 생성할 때 사용됩니다.
  • 코드를 읽기 쉽게 만들거나 여러 번 사용되는 긴 타입 이름을 간략하게 대체할 때 유용합니다.
protocol Container {
    associatedtype Item // 연관 타입
    var count: Int { get }
    mutating func append(_ item: Item)
    func item(at index: Int) -> Item
}

struct IntContainer: Container {
    typealias Item = Int // 연관 타입을 Int로 typealias하여 구현
    var items = [Item]()
    
    var count: Int {
        return items.count
    }
    
    mutating func append(_ item: Item) {
        items.append(item)
    }
    
    func item(at index: Int) -> Item {
        return items[index]
    }
}

var intBox = IntContainer()
intBox.append(5)
intBox.append(10)
print(intBox.item(at: 0)) // 출력: 5

/*
위의 예시에서 Container 프로토콜은 Item이라는 연관 타입을 가지고 있습니다. 
이 연관 타입은 Container 프로토콜을 채택하는 구체적인 타입에서 실제 타입으로 정의됩니다. 
IntContainer 구조체에서 Item을 Int로 typealias하여 실제 타입을 정의하고, 
이를 사용하여 배열에 Int 값을 저장하고 반환하는 메서드를 구현합니다.
*/