배열과 딕셔너리의 장점을 두루 갖춘 KeyValuePairs에 대해 공부
[key: value, key: value, ...]
KeyValuePairs<K,V>
- 딕셔너리의 장점을 두루 갖춤
- KeyValuePairs
- 키 형식의 제약이 없다.
- 동일한 키를 두 번 이상 저장하는 것도 가능
- 정렬된 컬렉션
- KeyValuePairs를 사용할 때는
- 데이터를 키와 값의 쌍으로 저장해야하고
- 동일한 키를 여러번 저장해야하고
- 동일한 순서 또는 동일한 순서로 반복해서 처리해야한다면 사용
let words: KeyValuePairs = ["A" : "Apple", "B": "Banna", "C": "City"]
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)
}
// 요소 삭제 추가 등 안됨
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)
조건문과 반복문에서 연관 값을 매칭시키는 방법에 대해 공부
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)")
}
모든 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)
}
새로운 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 블럭과 같이 사용함 = 에러를 잡아줌
항동 연산자를 통해 참조를 비교하는 방법에 대해 공부
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로 리턴됨
현재 형식으로 추론되는 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에 대해 공부
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
Projected Value를 통해 타입 외부에서 Property Wrapper에 접근하는 방법을 공부
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를 초기화하는 방법과 Property Wrapper가 가지고 있는 제약에 대해 공부
@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()
점문법으로 서브스크립트에 접근하는 단축문법을 구현
@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