
프로토콜은 특정 작업이나 기능의 청사진(blueprint)을 정의하는 것입니다. 클래스, 구조체, 열거형이 반드시 구현해야 할 요구사항들을 명시합니다.
// 프로토콜 정의
protocol Flyable {
var altitude: Double { get set }
func fly()
func land()
}
// Swift는 클래스 다중 상속 불가능
class Vehicle { }
class FlyingVehicle: Vehicle { } // ✅ 가능
// class AmphibiousVehicle: Vehicle, WaterVehicle { } // ❌ 불가능
// 하지만 프로토콜은 여러 개 채택 가능
protocol Flyable { }
protocol Swimmable { }
class Duck: Flyable, Swimmable { } // ✅ 가능!
protocol Drawable {
func draw()
}
class Circle: Drawable {
func draw() {
print("원을 그립니다")
}
}
class Rectangle: Drawable {
func draw() {
print("사각형을 그립니다")
}
}
// 프로토콜 타입으로 배열 생성
let shapes: [Drawable] = [Circle(), Rectangle()]
shapes.forEach { $0.draw() } // 각각의 draw() 메서드 호출
protocol PersonProtocol {
var name: String { get } // 읽기 전용
var age: Int { get set } // 읽기/쓰기
static var species: String { get } // 타입 프로퍼티
}
struct Person: PersonProtocol {
let name: String // get만 요구하므로 let 가능
var age: Int // get set 요구하므로 var 필요
static let species = "Homo sapiens"
}
protocol Calculable {
func add(_ a: Int, _ b: Int) -> Int
mutating func reset() // 구조체에서 프로퍼티 변경시 mutating 필요
static func getVersion() -> String
}
struct Calculator: Calculable {
var result: Int = 0
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
mutating func reset() {
result = 0
}
static func getVersion() -> String {
return "1.0"
}
}
protocol Initializable {
init(name: String)
}
class MyClass: Initializable {
let name: String
required init(name: String) { // required 키워드 필요
self.name = name
}
}
protocol NetworkService {
func fetchData(from url: String) -> Data?
}
class APIService: NetworkService {
func fetchData(from url: String) -> Data? {
// REST API 호출 로직
return Data()
}
}
class MockService: NetworkService {
func fetchData(from url: String) -> Data? {
// 테스트용 가짜 데이터 반환
return Data("test data".utf8)
}
}
// 의존성 주입으로 유연한 설계
class DataManager {
private let service: NetworkService
init(service: NetworkService) {
self.service = service
}
func loadData() {
let data = service.fetchData(from: "https://api.example.com")
// 데이터 처리
}
}
protocol TableViewCellDelegate: AnyObject {
func didTapButton(in cell: CustomTableViewCell)
}
class CustomTableViewCell: UITableViewCell {
weak var delegate: TableViewCellDelegate?
@IBAction func buttonTapped(_ sender: UIButton) {
delegate?.didTapButton(in: self)
}
}
class ViewController: UIViewController, TableViewCellDelegate {
func didTapButton(in cell: CustomTableViewCell) {
// 버튼 탭 처리
print("셀의 버튼이 탭되었습니다")
}
}
protocol Loggable {
func log(_ message: String)
}
extension Loggable {
func log(_ message: String) {
print("[\(type(of: self))] \(message)")
}
func logError(_ error: String) {
print("🚨 ERROR: \(error)")
}
}
class NetworkManager: Loggable {
func connect() {
log("연결을 시도합니다") // 기본 구현 사용
logError("연결 실패") // 확장에서 추가된 메서드 사용
}
}
protocol Identifiable {
var id: String { get }
}
struct User: Identifiable {
let id: String
let name: String
}
struct Product: Identifiable {
let id: String
let title: String
}
class Repository<T: Identifiable> {
private var items: [T] = []
func find(by id: String) -> T? {
return items.first { $0.id == id }
}
func add(_ item: T) {
items.append(item)
}
}
let userRepo = Repository<User>()
let productRepo = Repository<Product>()
// UITableViewDataSource, UITableViewDelegate
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 셀 구성
return UITableViewCell()
}
}
protocol UserServiceProtocol {
func login(email: String, password: String) async throws -> User
func logout() async throws
func getCurrentUser() -> User?
}
class FirebaseUserService: UserServiceProtocol {
func login(email: String, password: String) async throws -> User {
// Firebase 로그인 로직
return User(id: "123", name: "John")
}
func logout() async throws {
// Firebase 로그아웃 로직
}
func getCurrentUser() -> User? {
// 현재 사용자 정보 반환
return nil
}
}
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
// 여러 프로토콜을 조합
func greet(_ person: Named & Aged) {
print("안녕하세요, \(person.age)세 \(person.name)님!")
}
@objc protocol OptionalProtocol {
@objc optional func optionalMethod()
func requiredMethod()
}
class MyClass: NSObject, OptionalProtocol {
func requiredMethod() {
print("필수 메서드")
}
// optionalMethod는 구현하지 않아도 됨
}
프로토콜은 다음과 같은 상황에서 사용합니다:
프로토콜을 잘 활용하면 확장 가능하고 유지보수하기 쉬운 코드를 작성할 수 있습니다! 🚀