티스토리 뷰
프로토콜
protocol Name {property method...}
메소드, 프로퍼티, 어떠한 일이나 기능을하는 것들의 청사진입니다. 클래스, 구조체, 열거형 등에 채택되어 구현에 대한 요구사항을 제공합니다. 프로토콜의 요구사항을 만족하는 타입을 이 프로토콜에 *conform 한다고 말합니다.
(*따르다, 순응하다)
프로토콜은 특정한 이름과 타입으로 인스턴스, 타입 프로퍼티를 요구합니다. 저장 프로퍼티인지 계산 프로퍼티인지는 필요하지 않습니다. 프로토콜은 프로퍼티들이 gettable 또는 gettable and settable 인지 명시해줘야 합니다.
(*gettable: 읽기, settable: 쓰기)
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
이렇게 정의된 프로토콜은 다음 예제와 같이 사용됩니다.
protocol FullyNamed {
var fullName: String { get }
}
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
// john.fullName is "John Appleseed"
Fully Named 프로토콜을 만들고 구조체 Person을 정의할 때 ' : ' 콜론 옆에 프로토콜의 이름을 적습니다.
또한 프로토콜은 또 다른 프로토콜을 따를 수 있습니다.
protocol Messagable {
var message: String? { get }
}
protocol Sendable: Messagable {
// ...
}
Extension과 Protocol
extension과 protocol을 함께 사용하면 프로토콜의 요구사항을 미리 구현해둘 수 있습니다. 이를 프로토콜 초기구현이라고 합니다.
(*extension은 계산 프로퍼티와 계산 타입프로퍼티 새로운 이니셜라이져 등을 존재하는 클래스, 구조체, 열거형, 프로토콜에 새롭게 추가합니다)
extension Some Type { // new functionality to add to SomeType goes here }
protocol Talkable {
var topic: String { get set }
func talk(to: Self)
}
// 익스텐션을 사용한 프로토콜 초기 구현
extension Talkable {
func talk(to: Self) {
print("\(to)! \(topic)")
}
}
이렇게 사용한다면 새로운 인스턴스가 Talkable 프로토콜을 conform 한다면 인스턴스내에서 func talk를 구현하지 않아도 사용할 수 있습니다.
클래스 (class) 와 구조체 (struct)
class Name {property method...}
struct Name {property method...}
클래스와 구조체는 *인스턴스의 값을 저장하거나 기능을 제공하고 이를 캡슐화 할 수 있는 타입입니다.
(*An instance of a class is traditionally known as an object. However, Swift structures and classes are much closer in functionality than in other languages)
클래스와 구조체가 공통적으로 할 수 있는 것
- 값을 저장할 프로퍼티를 선언할 수 있습니다.
- 함수적 기능을 하는 메서드를 선언 할 수 있습니다.
- 서브스크립트를 선언하여 서브스크립트 문법으로 내부 값들에 접근할 수 있습니다.
- 생성자를 사용해 초기 상태를 설정할 수 있습니다.
- extension을 사용하여 기능을 확장할 수 있습니다.
- Protocol을 채택하여 기능을 설정할 수 있습니다.
클래스만 가능한 것
- 상속이 가능합니다.
- 타입 캐스팅을 통해 런타임에서 클래스 인스턴스의 타입을 확인할 수 있습니다.
- deinit을 사용하여 클래스 인스턴스의 메모리 할당을 해제할 수 있습니다.
- *참조 카운트를 통해 다른 인스턴스에 하나 이상의 참조를 가능하게 합니다.
(*ARC가 인스턴스의 참조 갯수를 파악하여 추적하고 관리함. ARC: Auto Reference Counting)
메모리 할당
클래스는 ARC를 통해 인스턴트들을 관리합니다. 클래스는 Heap 메모리에 할당됩니다.
(*stack에 reference인 주소값을 할당하고, 실질적인 데이터는 heap에 할당합니다.)
구조체는 Stack 메모리에 할당됩니다. 그러나 *가변 길이 Collection들은 Heap 메모리에 할당됩니다.
(*Array, Dictionary, Set, String 이는 참조카운트를 가짐)
클래스와 구조체 사용전략
구조체 내에 *참조카운트가 1개를 초과할 경우 *오버헤드가 발생하기 때문에 이 경우에는 클래스가 유리함.
(*구조체 안에 클래스, 가변 길이 Collection 등)
(*오버헤드: 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간, 메모리)
Stack 메모리의 처리가 Heap 보다 빠르기 때문에 단순 값, 구조체로 구현 가능한 것들은 구조체가 유리함.
열거형
enum SomeEnumeration { case Name1, case Name2 ... }
관련된 값들을 그룹화 하여 정의하고 값들을 *type-safe 하게 처리할 수 있도록 하는 타입
(*타입 값을 명시하여 명확하게 하는것. enum 내에서의 값들은 동일한 타입이여야 한다.)
enum 내의 case 에 관련 값들의 타입을 명시하여 사용할 수도 있습니다. 아래는 switch와 함께 사용한 예시입니다.
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
// Prints "QR code: ABCDEFGHIJKLMNOP."
제네릭
func Name<T>( _: T , _: T ... ) { some action }
(*T 는 실제 타입이 아닌 placeholder이다. 실제 타입은 함수가 호출되는 순간 결정된다. )
제네릭은 메소드 구현 시 기능은 같은데 자료형이 다를 때 쓰는 일반화 방법입니다. 자료형을 placeholder로 추상화 하여 실제 타입을 명시하지 않고 포괄적으로 함수 인자를 받습니다.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
(*swift 내의 함수 인자는 상수이다. 함수 내부에서 인자값을 변경하기 위해서는 inout을 써서 값을 변경하고 함수 호출이 종료된 후에도 지속되도록 해야한다.)
두개의 placeholder는 다음과 같이 사용합니다.
func someFunction<T, U>(someT: T, someU: U) {
// function body goes here
}
제약
func findIndex<T>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
이 코드는 컴파일 되지 않습니다. 왜냐하면 Swift의 모든 타입이 == 연산자를 사용할 수 있는 것이 아니기 때문입니다. 예를들어 제가 임의의 클래스나 구조체를 만들었을 때 그것을 == 연산 할 수 있는지 Swift가 판별할 수 없습니다.
그래서 이때는 Equatable 이라는 프로토콜을 제약하여 타입이 conform 하도록 만들어야 합니다.
(*Equtable은 equal 연산을 보장하는 프로토콜)
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
Reference
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html Structures and Classes
https://docs.swift.org/swift-book/LanguageGuide/Protocols.html Protocols
https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html# Enumerations
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Generics
https://icksw.tistory.com/256 Class와 Struct의 차이점
https://corykim0829.github.io/swift/Understanding-Swift-Performance/# [Swift] 스위프트 성능 이해하기 (1) - struct와 class의 성능 차이
'iOS-Development' 카테고리의 다른 글
Lottie (0) | 2022.05.08 |
---|---|
CoreData (0) | 2022.04.24 |
UserDefaults (0) | 2022.04.19 |
SwiftUI와 Storyboard (0) | 2022.04.03 |
Swift : 개요 (0) | 2022.03.08 |