HIT해

[Swift 기초문법 - 21] 프로토콜 본문

Swift/Swift 기초문법

[Swift 기초문법 - 21] 프로토콜

힛해 2024. 7. 16. 04:25
728x90

Swift에서 프로토콜(Protocol)은 클래스, 구조체 및 열거형에 특정 속성이나 메서드가 반드시 구현되도록 강제하는 데 사용됩니다. 프로토콜을 통해 코드의 일관성을 유지하고, 여러 타입이 동일한 기능을 제공하도록 할 수 있습니다. 이번 포스팅에서는 Swift 프로토콜의 기본 개념과 사용법을 예제와 함께 알아보겠습니다.

프로토콜의 기본 개념

프로토콜은 특정 속성이나 메서드를 정의하지만, 실제 구현은 하지 않는다.

이를 채택하는 타입이 프로토콜에서 정의한 요구사항을 반드시 구현해야 합니다.

프로토콜은 Swift의 강력한 기능 중 하나로, 코드의 일관성과 재사용성을 높일 수 있습니다!

// 약속
/// **delegate
/// **able, **ing 와 같은 명칭을 사용해야한다

protocol Describable {
	// 우리는 이런 변수를 가지고 있을겁니다 라고 약속
    var description: String { get set }
    
    // 우리는 이런 메소드를 가지고 있을 겁니다 라고 약속
    func describe() -> String
}

// 약속해둔 프로토콜을 사용한다
struct Person: Describable {
    var name: String
    var age: Int

    var description: String {
        return "\\(name)은(는) \\(age)살입니다."
    }

    func describe() -> String {
        return description
    }
}

let person = Person(name: "철수", age: 25)
print(person.describe())
// 출력: 철수은(는) 25살입니다.

 

위 예제에서 Describable 프로토콜은 description 속성과 describe 메서드를 정의하고 있습니다. Person 구조체는 이 프로토콜을 채택하고, 요구된 속성과 메서드를 구현한다.

Flutter 에서 사용했던 인터페이스와 유사하다.

 

그리고 Struct Person : Describable 과 같이 프로토콜을 세팅하는 것을 Protocol Implement 또는 프로토콜을 준수한다 라고 한다.

프로토콜의 주요 기능

프로토콜은 여러 타입이 공통의 기능을 제공하도록 할 수 있으며, 이를 통해 다형성을 구현할 수 있습니다.

프로토콜 상속

프로토콜은 다른 프로토콜을 상속받을 수 있습니다. 이를 통해 더 복잡한 요구사항을 정의할 수 있습니다.

protocol Identifiable {
    var id: String { get }
}

protocol Named: Identifiable {
    var name: String { get }
}

struct User: Named {
    var id: String
    var name: String
}

let user = User(id: "12345", name: "영희")
print("ID: \\(user.id), Name: \\(user.name)")
// 출력: ID: 12345, Name: 영희

 

위 예제에서 Named 프로토콜은 Identifiable 프로토콜을 상속받아 id 속성과 name 속성을 요구합니다. User 구조체는 Named 프로토콜을 채택하고, 두 속성을 모두 구현합니다.

 

또는 이런 식으로 구현해도 된다

protocol Identifiable {
    var id: String { get }
}

protocol Named {
    var name: String { get }
}

protocol Something : Named, Identifiable {

}

struct User: Something {
    var id: String
    var name: String
}

let user = User(id: "12345", name: "영희")
print("ID: \\(user.id), Name: \\(user.name)")
// 출력: ID: 12345, Name: 영희

프로토콜 준수 여부 확인

타입이 특정 프로토콜을 준수하는지 확인할 수 있습니다.

if user is Named {
    print("\\(user.name)은(는) Named 프로토콜을 준수합니다.")
} else {
    print("\\(user.name)은(는) Named 프로토콜을 준수하지 않습니다.")
}
// 출력: 영희은(는) Named 프로토콜을 준수합니다.

프로토콜의 확장

프로토콜의 기본 구현을 제공하기 위해 프로토콜 확장을 사용할 수 있습니다. 이를 통해 프로토콜을 채택하는 모든 타입이 기본 구현을 상속받을 수 있습니다.

extension Describable {
    func describe() -> String {
        return description
    }
}

struct Animal: Describable {
    var name: String

    var description: String {
        return "\\(name)입니다."
    }
}

let animal = Animal(name: "강아지")
print(animal.describe())
// 출력: 강아지입니다.

 

위 예제에서 Describable 프로토콜을 확장하여 describe 메서드의 기본 구현을 제공합니다. Animal 구조체는 Describable 프로토콜을 채택하지만 describe 메서드를 따로 구현하지 않아도 기본 구현을 상속받아 사용할 수 있습니다.

 

프로토콜을 선언 단계에서 로직을 세울 수 없어서 protocol 메소드 부분에 로직을 넣으려 하면 오류가 발생하는데.

extension을 활용하면 넣을 수 있게 된다.

구체적으로 다시 살펴보자.

 

protocol Naming {
	var lastname : String { get set }
    var firstname : String { get set }
    func getName() -> String // 함수명과 반환타입 매개변수만 선언이 가능하고 로직부분 불가
}

// protocol을 확장
extenstion Naming {
	func getFullname() -> String{
    	return self.lastname = " " + self.firstname
    }
}

// extenstion에 선언해둔 함수를 작성하지 않아도 된다.
struct Friend : Naming {
	var lastname : String
    var firstname : String
    func getName() -> String {
    	return self.lastname
    }
}

let myFriend = Friend(lastname: "안" , firtname: "상준")

myFriend.getName() // 안
myFriend.getFullName() // 안 상준

associatedType

protocol에서 제네릭 타입을 활용할 수 있게 하는 도구다.

사용예시는 아래와 같다.

import UIKit

protocol PetHaving {
    associatedtype T
    var pets: [T] {get set}
    mutating func getNewPet(_ newPet : T)
}

extension PetHaving {
    mutating func getNewPet(_ newPet: T){
        self.pets.append(newPet)
    }
}

enum Animal {
    case cat, dog, bird
}

struct Friend : PetHaving {
    var pets: [Animal] = []
}

struct Family : PetHaving {
    var pets: [String] = []
}

var myFriend = Friend()

myFriend.getNewPet(Animal.dog)
myFriend.getNewPet(Animal.cat)
myFriend.getNewPet(Animal.bird)
myFriend.pets

 

결론

Swift의 프로토콜은 코드의 일관성과 재사용성을 높이는 중요한 개념이다.

프로토콜을 통해 여러 타입이 동일한 기능을 제공하도록 할 수 있으며, 이를 통해 다형성을 구현할 수 있다.

'Swift > Swift 기초문법' 카테고리의 다른 글

[Swift 기초문법 - 22] 별칭 typealias  (0) 2024.08.14
Extenstion  (0) 2024.08.07
[Swift 기초문법 - 20] Struct Method  (0) 2024.07.16
[Swift 기초문법 - 19] Set  (0) 2024.07.16
[Swift 기초문법 - 18] Struct mutating  (0) 2024.07.12