24. Expert #2

Kang.__.Mingu·2021년 8월 7일
0

1. Study Swift

목록 보기
24/25

Collection

KeyValuePairs

배열과 딕셔너리의 장점을 두루 갖춘 KeyValuePairs에 대해 공부

KeyValuePair Literal

[key: value, key: value, ...]

KeyValuePair Type

KeyValuePairs<K,V>
  • 딕셔너리의 장점을 두루 갖춤
  • KeyValuePairs
  • 키 형식의 제약이 없다.
  • 동일한 키를 두 번 이상 저장하는 것도 가능
  • 정렬된 컬렉션

  • KeyValuePairs를 사용할 때는
  • 데이터를 키와 값의 쌍으로 저장해야하고
  • 동일한 키를 여러번 저장해야하고
  • 동일한 순서 또는 동일한 순서로 반복해서 처리해야한다면 사용
let words: KeyValuePairs = ["A" : "Apple", "B": "Banna", "C": "City"]

KeyValuePair Basics

words.count
words.isEmpty

//words.firstIndex(where: )   // 인덱스 검색
//words.first(where: )    // 특정 요소 검색
//words.contains(where: )     // 요소 검색

// "A"키에 접근하려면
words[0]
words[0].key        // 키 접근
words[0].value      // 값 접근

for elem in words {
    print(elem)
}

// 요소 삭제 추가 등 안됨

Enumeration

Associated Values

case에 연관 값을 저장하는 방법에 대해 공부

enum TypeName {
	case caseName(Type)
    case caseName(Type, Type, ...)
}
// 연관값?

enum VideoInterface {
    case dvi(width: Int, height: Int)
    case hdmi(Int, Int, Double, Bool)
    case displayPort(CGSize)
}

var input = VideoInterface.dvi(width: 2048, height: 1536)

switch input {
case .dvi(width: 2048, height: 1536):
    print("div 2048 x 1536")
case .dvi(width: 2048, height: _):
    print("div 2048 x Any")
case .dvi:
    print("dvi")
case .hdmi(let width, let height, let version, let audioEnabled):
    print("hdmi \(width)x\(height)")
case let .displayPort(size):
    print("dp")
}

input = .hdmi(3840, 2160, 2.1, true)

Enumeration Case Pattern

조건문과 반복문에서 연관 값을 매칭시키는 방법에 대해 공부

case Enum.case(let name):
case Enum.case(var name):
case let Enum.case(name):
case var Enum.case(name):

switch문, if문, guard문, for-in문, while문 에서 사용

enum Transportation {
    case bus(number: Int)
    case taxi(company: String, number: String)
    case subway(lineNumber: Int, express: Bool)
}

var tpt = Transportation.bus(number: 7)

switch tpt {
case .bus(let n):
    print(n)
case .taxi(let c, var n):
    print(c, n)
case let .subway(l, e):
    print(l, e)
}

tpt = Transportation.subway(lineNumber: 2, express: false)

if case let .subway(2, express) = tpt {
    if express {
        
    } else {
        
    }
}


if case .subway(_, true) = tpt {
    print("express")
}


let list = [
    Transportation.subway(lineNumber: 2, express: false),
    Transportation.bus(number: 4412),
    Transportation.subway(lineNumber: 7, express: true),
    Transportation.taxi(company: "SeoulTaxi", number: "1234"),
]

// 같은 패턴만 열거
for case let .subway(n, _) in list {
    print("subway \(n)")
}

// 급행만 열거
for case let .subway(n, true) in list {
    print("subway \(n)")
}

for case let .subway(n, true) in list where n == 2 {
    print("subway \(n)")
}

CaseIterable

모든 case를 열거할 수 있게 도와주는 CaseIterable 프로토콜에 대해 공부

열거형의 기능을 확장시켜줌

enum Weekday: Int, CaseIterable {
   case sunday
   case monday
   case tuesday
   case wednesday
   case thursday
   case friday
   case saturday
}

let rnd = Int.random(in: 0...Weekday.allCases.count)

Weekday(rawValue: rnd)

Weekday.allCases.randomElement()

// 모든 케이스를 열거
for w in Weekday.allCases {
    print(w)
}

Nonfrozen Enumeration

새로운 case를 안전하게 처리하는 방법에 대해 공부

enum ServiceType {
    case onlineCourse
    case offlineCamp
    case onlineCamp
    case seminar
}

let selectedType = ServiceType.onlineCourse

switch selectedType {
case .onlineCourse:
   print("send online course email")
case .offlineCamp:
   print("send offline camp email")
case . onlineCamp:
    print("send online camp email")
@unknown default:
    break
}
// @unknown  default 블럭과 같이 사용함 = 에러를 잡아줌

Structure and class

Identity Operator

항동 연산자를 통해 참조를 비교하는 방법에 대해 공부

Identical to Operator
classinstance === classInstance
---
Not identical to Operator
classInstance !== classInstance

화동 연산자
동일성을 비교

class A {
    
}

let a = A()
let b = a
let c = A()

a === b
a !== b

a !== c     // 인스턴스가 다름 !== 이기 때문에 true로 리턴됨

Property

Self Type

현재 형식으로 추론되는 Self 타입에 대해 공부

// Self 타입
extension Int {
   static let zero: Self = 0

   var zero: Self {
        return 0
   }

   func makeZero() -> Self {
        Self.zero
        return Self()     // 생성자를 호출하는 코드
   }
}


extension Double {
    static let zero: Self = 0

    var zero: Self {
         return 0
    }

    func makeZero() -> Self {
         Self.zero
         return Self()     // 생성자를 호출하는 코드
    }
}

Int.zero       

Double.zero

Property Wrapper #1

속성에 접근하는 코드를 별도의 타입으로 분리하는 Property Wrapper에 대해 공부

Page1

struct PlayerSetting {
    var initialSpeed: Double {
        get {
            return UserDefaults.standard.double(forKey: "initialSpeed")
        }
        set {
            UserDefaults.standard.set(newValue, forKey: "initialSpeed")
        }
   }
   
   var supportGesture: Bool {
      get {
         return UserDefaults.standard.bool(forKey: "supportGesture")
      }
      set {
         UserDefaults.standard.set(newValue, forKey: "supportGesture")
      }
   }
}


var currentSetting = PlayerSetting()
currentSetting.initialSpeed = 1.0
currentSetting.initialSpeed     // 1

currentSetting.initialSpeed = 1.5
currentSetting.initialSpeed     // 1.5

currentSetting.supportGesture   // false
currentSetting.supportGesture = true
currentSetting.supportGesture   // true

Property Wrapper #2-Projected Value

Projected Value를 통해 타입 외부에서 Property Wrapper에 접근하는 방법을 공부

Page2

struct PlayerSetting {
    @UserDefaultsHelper(key: "initialSpeed", defaultValue: 1.0) // 컴파일러가 필요한 코드를 자동으로 추가
    var initialSpeed: Double
    
    @UserDefaultsHelper(key: "supportGesture", defaultValue: true)
    var supportGesture: Bool
    
    func resetAll() {
        _initialSpeed.reset()       // _로 프로퍼티 인스턴스에 바로 접근 가능
        _supportGesture.reset()
    }
}

@propertyWrapper
struct UserDefaultsHelper<Value> {
    let key: String
    let defaultValue: Value
    
    var wrappedValue: Value {
        get {
            UserDefaults.standard.object(forKey: key) as? Value ?? defaultValue
        }
        set {
            UserDefaults.standard.setValue(newValue, forKey: key)
        }
    }
    func reset() {
        UserDefaults.standard.setValue(defaultValue, forKey: key)
    }
    
    var projectedValue: Self { return self }
}

var currentSetting = PlayerSetting()

currentSetting.initialSpeed
currentSetting.initialSpeed = 1.5
currentSetting.initialSpeed

currentSetting.supportGesture
currentSetting.supportGesture = false
currentSetting.supportGesture

currentSetting.$initialSpeed.reset()        // 접근할 때 $로 접근

// 타입 외부에서는 접근 불가
// 외부에서 접근하려면 $로 접근

Property Wrapper #3

Property Wrapper를 초기화하는 방법과 Property Wrapper가 가지고 있는 제약에 대해 공부

Page3

@propertyWrapper
class SimpleWrapper {
    var wrappedValue: Int
    var metadata: String?

    init() {
        print(#function)
        wrappedValue = 0
        metadata = nil
   }
    
    init(wrappedValue value: Int) {
        print(#function)
        wrappedValue = value
        metadata = nil
    }
    
    init(wrappedValue: Int, metadata: String?) {
        print(#function)
        self.wrappedValue = wrappedValue
        self.metadata = metadata
    }
}


struct MyType {
    @SimpleWrapper
    var a: Int = 123
    
    @SimpleWrapper(wrappedValue: 456)
    var b: Int
    
    @SimpleWrapper(wrappedValue: 123, metadata: "number")
    var c: Int
    
    @SimpleWrapper(metadata: "number")
    var d: Int = 123
}

let t = MyType()

Method and Subscript

Dynamic Member Lookup

점문법으로 서브스크립트에 접근하는 단축문법을 구현

@dynamicMemberLookup
struct Person {
   var name: String
   var address: String
    
    subscript(dynamicMember member: String) -> String {
        switch member {
        case "nameKey":
            return name
        case "addressKey":
            return address
        default:
            return "n/a"
        }
    }
}

let p = Person(name: "Ben", address: "Seoul")
p.name
p.address

p[dynamicMember: "nameKey"]
p[dynamicMember: "addressKey"]

// 단축 문법 사용 가능
p.nameKey
p.addressKey

p.missingKey
profile
최선을 다해 꾸준히 노력하는 개발자 망고입니당 :D

0개의 댓글