SwiftUI의 프로토콜
스위프트를 학습하다보면 많은 프로토콜들이 나온다 클래스, 구조체등에서 공통된 속성이나 메서드를 정의하기 위한 구조이다 또한 스위프트에서는 다중 상속을 지원하지 않지만, 한 클래스 또는 구조체가 여러 프로토콜을 사용해서 다중 상속과 유사한 동작을 구현할 수 있다 스위프트에서 사용하는 대표적인 프로토콜을 정리한다
Equatable
- 두 개체가 동등한지 비교할 수 있다
==를 사용해서 두 값이 같은지 비교한다
1
2
3
4
5
6
7
8
9
10
11
struct Person: Equatable {
let name: String
let age: Int
}
let person1 = Person(name: "Alice", age: 25)
let person2 = Person(name: "Alice", age: 25)
if person1 == person2 {
print("Same person")
}
위 코드 실행시 Same person이 출력된다 또한 Equatable 프로토콜을 제거한다면 위 코드는 ==으로 비교할 수 없기 때문에 오류가 발생한다
Comparable
- 두값을 비교한다 대소 비교(연산자 사용)
- <, >, >=, <= 연산자를 사용하며 값을 크기순으로 정렬할때 유용하다
1
2
3
4
5
6
7
8
9
10
struct Product: Comparable {
let price: Double
static func < (lhs: Product, rhs: Product) -> Bool {
return lhs.price < rhs.price
}
}
let products = [Product(price: 99.99), Product(price: 149.99),Product(price: 199.99),Product(price: 99.00)]
let sortedProducts = products.sorted()
print로 출력시 [__lldb_expr_15.Product(price: 99.0), __lldb_expr_15.Product(price: 99.99), __lldb_expr_15.Product(price: 149.99), __lldb_expr_15.Product(price: 199.99)] 이 결과가 나온다 만약에 내림차순으로 sorted를 사용하고 싶다면 return 부분을 rhs.price < lhs.price 이렇게 바꾸면 된다
static func 부분이 왜 있는지 잘 몰랐는데 저부분이 하나의 프로토콜의 구성요소가 되기 때문에 해당 프로토콜을 준수하기 위해 꼭 필요한 부분이었다 이해가 잘안가서 gpt에게 물어보았다
요약
static: 타입 메서드를 정의하며, Comparable 프로토콜이 요구하는 static func < 메서드를 구현하기 위해 사용됩니다. 이는 타입의 모든 인스턴스 간 비교를 위해 타입 차원에서 제공됩니다.
func: 메서드 정의를 위한 기본 키워드로, 여기서는 Comparable 프로토콜을 준수하기 위해 사용됩니다.
따라서,
static func <는Comparable프로토콜에서 요구하는<연산자를 구현하여 타입 간의 비교를 가능하게 하고, 이를 통해sorted()와 같은 메서드를 사용할 수 있게 합니다.
한마디로 Comparable 프로토콜을 사용할려면 꼭 필요한 부분이다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
struct Product: Comparable {
let price: Double
// '<' 연산자를 구현하면 나머지 연산자들은 자동으로 제공됨
static func < (lhs: Product, rhs: Product) -> Bool {
return lhs.price < rhs.price
}
// '==' 연산자는 Equatable 프로토콜을 구현하는 부분이며 필수임
static func == (lhs: Product, rhs: Product) -> Bool {
return lhs.price == rhs.price
}
}
let product1 = Product(price: 99.99)
let product2 = Product(price: 149.99)
// '<' 연산자
print(product1 < product2) // true
// '>' 연산자 (자동 제공)
print(product1 > product2) // false
// '<=' 연산자 (자동 제공)
print(product1 <= product2) // true
// '>=' 연산자 (자동 제공)
print(product1 >= product2) // false
// '==' 연산자
print(product1 == product2) // false
Codable(Encodable & Decoable)
- 데이터를 인코딩 또는 디코딩해서 Json등과 같은 형식으로 변환한다
- 데이터를 쉽게 외부 파일로 저장하거나 네트워크 통신에서 데이터를 주고 받을 때 사용한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import SwiftUI
struct User: Codable {
let name: String
let age: Int
}
let user = User(name: "Alice", age: 25)
// 인코딩: User 객체를 JSON 데이터로 변환
let jsonData = try? JSONEncoder().encode(user)
print(jsonData!)
// 25 bytes
// 디코딩: JSON 데이터를 User 객체로 변환
let decodedUser = try? JSONDecoder().decode(User.self, from: jsonData!)
print(decodedUser!)
//User(name: "Alice", age: 25)
Hashable
- 객체를 해시 가능한 값으로 만들어 Set, Dictionary 등 컬렉션에서 사용된다 객체가 고유한 해시 값을 가져야 할 때 사용된다
1
2
3
4
5
6
7
8
struct User {
let name: String
let id: Int
}
let myDict: [String: Int] = ["sodeul": 28] // 컴파일러에 의해서 자동으로 Hashable 프로토콜
let myDict2: [User: Int] // 오류 Type 'User' does not conform to protocol 'Hashable'
위 코드에서 myDict는 기본 자료형인 String와 Int를 사용해서 자동으로 Hashable 프로토콜이 적용됬다 하지만 내가 만든 구조체 User는 내부에 String과 Int형이 존재하지만 어떤 값을 기준으로 해시를 해야할지 몰라서 Hashable 프로토콜을 따르지 않는다고 오류가 발생한다
1
2
3
4
struct User: Hashable {
let name: String
let id: Int
}
구조체 선언시 프로토콜을 작성한다면 오류가 발생하지 않는다
Identifiable
- SwiftUI에서 객체가 고유한 식별자를 가지도록 요구할 때 사용된다 주로 리스트 항목을 렌더링할 때 사용
- 각 객체가 고유의
id값을 가져야 하며, SwiftUI의List,ForEach와 같은 뷰에서 사용
1
2
3
4
5
6
7
8
9
10
11
12
import SwiftUI
struct User: Identifiable {
let id: UUID
let name: String
}
let users = [User(id: UUID(), name: "Alice"), User(id: UUID(), name: "Bob")]
List(users) { user in
Text(user.name)
}
View
- SwiftUI에서 화면 요소를 정의할 때 사용되는 프로토콜
- 모든 SwiftUI 화면 요소(View)는
View프로토콜을 채택하며,body속성에서 화면에 렌더링할 뷰를 반환
1
2
3
4
5
6
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, World!")
}
}