Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 자바스크립트
- FileOwner
- MainScheduler
- 웹
- 맥
- 개발기록
- Swift
- 계산기앱만들기
- 파이썬서버
- 스위프트
- spring
- Python
- 딩동말씀
- subscript
- iOS배포
- JavaScript
- iOS앱배포
- Xcode
- FLASK
- DispatchGroup
- AJAX
- 앱배포
- iOS계산기
- ios
- Xib
- 계산기앱
- 스프링
- 앱버전구하기
- jQuery
- customclass
Archives
- Today
- Total
개발하는 뚝딱이
[swift] 프로토콜 초기구현 본문
책 <스위프트 프로그래밍 3판 ;야곰 지음> 을 정리한 글입니다.
1. 프로토콜 초기구현
//
// main.swift
// hello
//
// Created by Jin on 2020/09/28.
//
import Foundation
protocol Receiveable {
func received(data: Any, from: Sendable)
}
extension Receiveable {
// 메시지를 수신합니다
func received(data: Any, from: Sendable) {
print("\(self) received \(data) from \(from)")
}
}
// 무언가를 발신할 수 있는 기능
protocol Sendable {
var from: Sendable { get }
var to: Receiveable? { get }
func send(data: Any)
static func isSendableInstance(_ instance: Any) -> Bool
}
extension Sendable {
// 발신은 발신 가능한 객체, 즉 Sendable 프로토콜을 준수하는 타입의 인스턴스여야 함
var from: Sendable {
return self
}
// 메시지를 발신
func send(data: Any) {
guard let receiver: Receiveable = self.to else {
print("Message has no receiver")
return
}
// 수신 가능한 인스턴스의 received 메서드를 호출
receiver.received(data: data, from: from)
}
static func isSendableInstance(_ instance: Any) -> Bool {
if let sendableInstance: Sendable = instance as? Sendable {
return sendableInstance.to != nil
}
return false
}
}
// 수신, 발신이 가능한 Message 클래스
class Message: Sendable, Receiveable {
var to: Receiveable?
}
// 수신, 발신이 가능한 Mail 클래스
class Mail: Sendable, Receiveable {
var to: Receiveable?
}
// 두 Message 인스턴스를 생성
let myPhoneMessage: Message = Message()
let yourPhoneMessage: Message = Message()
myPhoneMessage.send(data: "Hello") // Message has no receiver
myPhoneMessage.to = yourPhoneMessage
myPhoneMessage.send(data: "Hello") // Message received Hello from Message
// Mail 인스턴스를 두 개 생성합니다
let myMail: Mail = Mail()
let yourMail: Mail = Mail()
myMail.send(data: "Hi") // Message has no receiver
myMail.to = yourMail
myMail.send(data: "Hi") // Mail received Hi from Mail
myMail.to = myPhoneMessage
myMail.send(data: "Bye") // Message received Bye from Mail
// String은 Sendable 프로토콜을 준수하지 않음
Message.isSendableInstance("Hello") // false
// Message와 Mail은 프로토콜을 준수함
Message.isSendableInstance(myPhoneMessage) // true
// yourPhoneMessage는 to 프로퍼티가 설정되지 않아서 보낼 수 없는 상태
Message.isSendableInstance(yourPhoneMessage) // false
Mail.isSendableInstance(myPhoneMessage) // true
Mail.isSendableInstance(myMail) // true
- 프로토콜을 정의할 때는 그 프로토콜을 채택한 타입에서 구현해줘야 하는 프로토콜의 요구사항을 구현할 수 없음
- 단지 요구사항을 정의만 할 수 있음
- 그러나 프로토콜의 익스텐션에는 프로토콜이 요구하는 기능을 실제로 구현해줄 수 있음
- 다만 익스텐션에는 저장 프로퍼티를 구현할 수 없으므로 저장 프로퍼티는 각각의 타입에 직접 구현해줘야 함
- 프로토콜과 익스텐션을 결합하면 코드의 재사용이 월등히 증가함
- 프로토콜의 요구사항을 익스텐션을 통해 구현한 것을 프로토콜 초기구현 (Protocol Default Implementations)이라고 함
- 만약 프로토콜의 익스텐션에서 구현한 기능을 사용하지 않고 타입의 특성에 따라 조금 변경해서 구현하고 싶다면 재정의하면 됨
- 특정 프로토콜을 준수하는 타입에 프로토콜의 요구사항을 찾아보고 이미 구현되어 있다면 그 기능을 호출,
그렇지 않다면 프로토콜 초기 구현의 기능을 호출
// 익스텐션을 통해 구현된 메서드 정의
class Mail: Sendable, Receiveable {
var to: Receiveable?
func send(data: Any) {
print("Mail의 send 메서드는 재정의되었습니다")
}
}
let mailInstance: Mail = Mail()
mailInstance.send(data: "Hello") // Mail의 send 메서드는 재정의되었습니다
- 제네릭, 프로토콜, 익스텐션을 통한 재사용 가능한 코드 작성
protocol SelfPrintable {
func printSelf()
}
extension SelfPrintable where Self: Container {
func printSelf() {
print(items)
}
}
protocol Container: SelfPrintable {
associatedtype ItemType
var items: [ItemType] { get set }
var count: Int { get }
mutating func append(item: ItemType)
subscript(i: Int) -> ItemType { get }
}
extension Container {
mutating func append(item: ItemType) {
items.append(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> ItemType {
return items[i]
}
}
protocol Popable: Container {
mutating func pop() -> ItemType?
mutating func push(_ item: ItemType)
}
extension Popable {
mutating func pop() -> ItemType? {
return items.removeLast()
}
mutating func push(_ item: ItemType) {
self.append(item: item)
}
}
protocol Insertable: Container {
mutating func delete() -> ItemType?
mutating func insert(_ item: ItemType)
}
extension Insertable {
mutating func delete () -> ItemType? {
return items.removeFirst()
}
mutating func insert(_ item: ItemType) {
self.append(item: item)
}
}
struct Stack<Element>: Popable {
var items: [Element] = [Element]()
}
struct Queue<Element>: Insertable {
var items: [Element] = [Element]()
}
var myIntStack: Stack<Int> = Stack<Int>()
var myStringStack: Stack<String> = Stack<String>()
var myIntQueue: Queue<Int> = Queue<Int>()
var myStringQueue: Queue<String> = Queue<String>()
myIntStack.push(3)
myIntStack.printSelf() // [3]
myIntStack.push(2)
myIntStack.printSelf() // [3, 2]
myIntStack.pop() // 2
myIntStack.printSelf() // [3]
myStringStack.push("A")
myStringStack.printSelf() // ["A"]
myStringStack.push("B")
myStringStack.printSelf() // ["A", "B"]
myStringStack.pop() // "B"
myStringStack.printSelf() // ["A"]
myIntQueue.insert(3)
myIntQueue.printSelf() // [3]
myIntQueue.insert(2)
myIntQueue.printSelf() // [3, 2]
myIntQueue.delete() // 3
myIntQueue.printSelf() // [2]
myStringQueue.insert("A")
myStringQueue.printSelf() // ["A"]
myStringQueue.insert("B")
myStringQueue.printSelf() // ["A", "B"]
myStringQueue.delete()
myStringQueue.printSelf() // ["B"]
2. 맵, 필터, 리듀스 직접 구현해보기
// Array 타입의 맵 사용
let items: Array<Int> = [1, 2, 3]
let mappedItems: Array<Int> = items.map { (item: Int) -> Int in
return item * 10
}
print(mappedItems) // [10, 20, 30]
struct Stack<Element>: Popable {
var items: [Element] = [Element]()
func map<T>(transform: (Element) -> T) -> Stack<T> {
var transformedStack: Stack<T> = Stack<T>()
for item in items {
transformedStack.items.append(transform(item))
}
return transformedStack
}
}
var myIntStack: Stack<Int> = Stack<Int>()
myIntStack.push(1)
myIntStack.push(5)
myIntStack.push(2)
myIntStack.printSelf() // [1, 5, 2]
var myStrStack: Stack<String> = myIntStack.map{ "\($0)" }
myStrStack.printSelf() // ["1", "5", "2"]
// Array 타입의 필터 사용
let filteredItems: Array<Int> = items.filter { (item: Int) -> Bool in
return item % 2 == 0
}
print(filteredItems) // [2]
struct Stack<Element>: Popable {
var items: [Element] = [Element]()
func filter(includeElement: (Element) -> Bool) -> Stack<Element> {
var filteredStack: Stack<ItemType> = Stack<ItemType>()
for item in items {
if includeElement(item) {
filteredStack.items.append(item)
}
}
return filteredStack
}
}
let filteredStack: Stack<Int> = myIntStack.filter { (item: Int) -> Bool in
return item < 5
}
filteredStack.printSelf() // [1, 2]
// Array 타입의 리듀스 사용
let items: Array<Int> = [1, 2, 3]
let combinedItems: Int = items.reduce(0) { (result: Int, next: Int) -> Int in
return result + next
}
print(combinedItems) // 6
let combinedItemsDoubled: Double = items.reduce(0.0) { (result: Double, next: Int) -> Double in
return result + Double(next)
}
print(combinedItemsDoubled) // 6.0
let combinedItemsString: String = items.reduce("") { (result: String, next: Int) -> String in
return result + "\(next) "
}
print(combinedItemsString) // 1 2 3
struct Stack<Element>: Popable {
var items: [Element] = [Element]()
func reduce<T>(_ initialResult: T, nextPartialResult: (T, Element) -> T) -> T {
var result: T = initialResult
for item in items {
result = nextPartialResult(result, item)
}
return result
}
}
let combinedInt: Int = myIntStack.reduce(100) { (result: Int, next: Int) -> Int in
return result + next
}
print(combinedInt) // 108
let combinedDouble: Double = myIntStack.reduce(100) { (result: Double, next: Int) -> Double in
return result + Double(next)
}
print(combinedDouble) // 108.0
let combinedString: String = myIntStack.reduce("") { (result: String, next: Int) -> String in
return result + "\(next)"
}
print(combinedString) // 152
3. 기본 타입 확장
protocol SelfPrintable {
func printSelf()
}
extension SelfPrintable {
func printSelf() {
print(self)
}
}
extension Int: SelfPrintable { }
extension String: SelfPrintable { }
extension Double: SelfPrintable { }
1024.printSelf() // 1024
3.14.printSelf() // 3.14
"hana".printSelf() // "hana"
'swift' 카테고리의 다른 글
[swift] 프로답게 스위프트로 코딩하기 (0) | 2021.08.17 |
---|---|
[swift] 스위프트를 더 스위프트스럽게 사용하기 (0) | 2021.03.11 |
[swift] 프로토콜 (0) | 2020.09.21 |
[swift] 상속 (0) | 2020.09.05 |
[swift] 서브스크립트 (0) | 2020.06.25 |