Suyeon9911 / TIL

매일 오전에 적는 미라클 TIL 🥣
10 stars 0 forks source link

[Swift] Swift의 데이터타입 총 정리 #73

Closed Suyeon9911 closed 1 year ago

Suyeon9911 commented 1 year ago

Swift로 알고리즘 문제를 조금씩 풀어볼 예정인데 그 전에 데이터 타입에 대한 내용을 한번 읽어보앗습니당 ! 그중에서 몰랐던 내용이나 기억하면 좋을 것 같은 내용들을 정리 ~ !

  1. Int 와 UInt : 양수만 사용한다고 해서 UInt 를 고집할 필요는 없다. 스위프트는 데이터타입에 엄격하기 때문에 같은 정수라 하더라도 전혀 다른 타입으로 인식하여 변수끼리 값을 교환할 때 많은 자원을 소모할 수 있다.

  2. 각 진수에 따라 정수를 표현하는 방법

    • 10진수 : 평소에 쓰던 숫자와 동일하게
    • 2진수 : 접두어 0b
    • 8진수 : 접두어 0o
    • 16진수 : 접두어 0x
  3. toggle() : true, false 반전

  4. 64비트 Double 15자리, 32비트 Float 6자리 : 무엇을 사용해야할지 잘 모르는 상황이라면 Double을 사용하기를 권장

  5. 임의의 수 만들기 random(in: ) ex) Int.random(in: -100...100)

  6. Character 값에 유니코드 문자를 사용할 수 있다. 한글변수이름도 사용가능

  7. 상수로 선언된 문자열은 변경 불가, 이니셜라이저를 사용하여 빈 문자열 생성 가능 String()

  8. append() 메서드를 사용하여 문자열을 이어붙일 수 있음. + 연산자도 가능

  9. count 문자의 수 세기, isEmpty 비어있는 지 확인

  10. 문자열 비교 == : true, false 값 반환

  11. 메서드를 통한 접두어, 접미어 확인 .hasPrefix("문자열") , hasSuffix("문자열")-> true, false

  12. 메서드를 통한 대소문자 변환 : uppercased(), lowercased()

  13. 코드상에서 여러줄의 문자열을 직접 쓰고 싶다면 큰따옴표 3개 사용

  14. 문자열 내 특수 문자

    • \n : 줄바꿈
    • \ : 문자열 내 백슬래시
    • \" : 문자열 내 큰 따옴표
    • \t : 탭문자
    • \0 : 문자열이 끝났음을 알리는 null 문자
  15. Any는 스위프트의 모든 데이터 타입을 사용할 수 있다는 뜻

  16. AnyObject는 조금 한정된 의미로 클래스의 인스턴스만 할당할 수 있다

  17. 변수 또는 상수에 값이 없는 경우, 즉 nil 일 경우 ? 해당 변수 또는 상수에 접근했을 때 잘못된 메모리 접근으로 런타임 오류 발생. - Null Point Exception

  18. 특정함수의 반환 타입으로 사용될 수 있는 Never라는 타입 존재

Suyeon9911 commented 1 year ago

스위프트는 타입에 민감하고 엄격 : 서로 다른 타입끼리의 데이터 교환은 꼭 타입캐스팅을 거쳐야 함

Type-safe 언어

타입별칭

튜플

var person: (String, Int, Double) = ("name", 100 , 182.5)

person.1 = 99
person.2 = 150

print(" \(person.0)")

person.age = 99 person.height = 150

print(" (person.name)")


- 튜플에는 타입이름에 해당하는 키워드가 따로 없어서 사용하기 불편
- 매번 같은 모양의 튜플을 사용하고 싶다면 타입 별칭을 사용해보자 

```swift 
typealias PersonTuple = (name: String, age: Int, height: Double)
let suyeon: PersonTuple =  ("name", 100 , 182.5)

print(" \(suyeon.name)")
Suyeon9911 commented 1 year ago

컬렉션 형 - 배열, 딕셔너리, 세트

배열

let emptyArray: [Int] = []

// 정식 문법 사용
let emptyArray2 = Array<Int>()

// 단축 문법 사용
let emptyArray3 = [Int]()

// 정식 문법
let strArray1: Array<String> = ["정식", "문법"]

// 단축 문법
let strArray2: [String] = ["단축", "문법"]

// 형식 추론
let strArray3 = ["형식", "추론"]

// 시퀀스
let nums = Array(1...3) // [1, 2, 3]

// 여러 자료형(타입)
let anyArr: [Any] = [1, 2, "three", "four"] // [1, 2, "three", "four"]

딕셔너리

// typealias 사용
typealias StringIntDictionary = [String: Int]

var numberForName: [String: Int] = [String: Int]()
var numberForName: StringIntDictionary = StringIntDictionary()
var numberForName:  [String: Int] = [:]

세트

Suyeon9911 commented 1 year ago

컬렉션에서 임의의 요소 추출과 뒤섞기 .

  1. 임의의 요소 추출 : randomElement()
  2. 뒤섞기 : shuffle()
  3. 자신의 요소는 그대로 둔 채 새로운 컬렉션에 임의의 순서로 섞어서 반환 shuffled()
Suyeon9911 commented 1 year ago

열거형

enum School {
    case primary
    case elementary
    case middle
    case high
    case collage
    case university
}

var highestEducationLevel: School = .university

// 같은 타입으로만 값을 변경할수 있다.
highestEducationLevel = .high

// 항목의 raw value : 특정 타입으로 지정된 값을 가질수 있다. 

enum School: String {
    case primary = "유치원"
    case elementary = "초등학교"
    case university = "대학교"
}

let highestEducationLevel: School = .university
print(highestEducationLevel.rawValue)

// 일부 항목만 원시값을 주는것도 가능하다. 
// 나머지는 알아서 처리 : 문자열이라면 각 항목이름 그대로, 정수 타입이면 첫 항목을 기주능로 0부터 1씩 늘어남

// 열거형이 원시값을 갖는 열거형일 때 , 원시값 정보를 안다면 원시값을 통해 열겨형 벼눗 또는 상수 생성가능

let primary = School(rawValue: "유치원")
let graduate = School(rawValue: "석박사") // nil
Suyeon9911 commented 1 year ago

열거형 - 연관값

enum MainDish {
    case pasta(taste: String)
    case pizza(dough: String, topping: String)
    case chicken(withSauce: Bool)
    case rice
}

var dinner: MainDish = .pasta(taste: "크림")
dinner = .pizza(dough: "치즈크러스트", topping: "불고기")
dinner = .chicken(withSauce: true)
dinner = .rice

// 여러 열거형의 응용

enum PastaTaste {
    case cream, tomato
}

enum PizzaDough {
    case cheeseCrust, thin, original
}

enum PizzaTopping {
    case pepperoni, cheese, bacon
}

enum MainDish {
    case pasta(taste: PastaTaste)
    case pizza(dough: PizzaDough, topping: PizzaTopping)
    case chicken(withSauce: Bool)
    case rice
}

var dinner: MainDish = .pasta(taste: .cream)
dinner = .pizza(dough: .cheeseCrust, topping: .bacon)
Suyeon9911 commented 1 year ago

항목순회

// 플랫폼 별로 사용 조건을 추가하는 경우 ?

enum School: CaseIterable {
    case primary
    case elementary
    case middle
    case high
    case collage
    case university

    @available(iOS, obsoleted: 12.0)
    case graduate

    static var allCases: [School] {
        let all: [School] = [.primary,
                            .elementary,
                            .middle,
                            .high,
                            .collage,
                            .collage,
                            .university]
        #if os(iOS)
        return all
        #else 
        return all + [.graduate]
        #endif
    }
}

let allCases: [School] = .allCases
print(allCases)
enum PastaTaste: CaseIterable {
    case cream, tomato
}

enum PizzaDough: CaseIterable {
    case cheeseCrust, thin, original
}

enum PizzaTopping: CaseIterable {
    case pepperoni, cheese, bacon
}

enum MainDish: CaseIterable {
    case pasta(taste: PastaTaste)
    case pizza(dough: PizzaDough, topping: PizzaTopping)
    case chicken(withSauce: Bool)
    case rice

    static var allCases: [MainDish] {
        return PastaTaste.allCases.map(MainDish.pasta) + PizzaDough.allCases.reduce([]) {
            (result, dough) -> [MainDish] in result + PizzaTopping.allCases.map {
                (topping) -> MainDish in MainDish.pizza(dough: dough, topping: topping)
            }
        }
        + [true, false].map(.chicken)
        + [.rice]
    }
}

print(MainDish.allCases.count)
Suyeon9911 commented 1 year ago

순환열거형

// 열거형 전체 indirect enum ArithmeticExpression { case number(Int) case addition(ArithmeticExpression, ArithmeticExpression) case multiplication(ArithmeticExpression, ArithmeticExpression) }

// evaluate는 열거형의 계산을 도와주는 순환함수

let five = ArithmeticExpression.number(5) let four = ArithmeticExpression.number(4) let sum = ArithmeticExpression.addition(five, four) let final = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

func evaluate(_ expression: ArithmeticExpression) -> Int { switch expression { case .number(let value): return value case .addition(let left, let right): return evaluate(left) + evaluate(right) case .multiplication(let left, let right): return evaluate(left) * evaluate(right) } }

let result: Int = evaluate(final) // indirect 키워드는 이진탐색트리등의 순환알고리즘을 구현할때 유용하게 사용가능


### 비교 가능한 열거형 
- Comparable 프로토콜을 채택하면 각 케이스 비교 가능. 
- 앞에 위치한 case가 더 작은 값이 된다.

```swift
enum Condition: Comparable {
    case terrible
    case bad
    case good
    case great
}

let myCondition: Condition = .great
let yourCondition: Condition = .bad

if myCondition >= yourCondition {
    print("제 상태가 더 좋군요")
} else {
    print("당신의 상태가 더 좋군요")
}

enum Device: Comparable {
    case iPhone(version: String)
    case iPad(version: String)
    case macBook
    case iMac
}

var devices: [Device] = []
devices.append(Device.iMac)
devices.append(.iPhone(version: "14.3"))
devices.append(.iPhone(version: "6.1"))
devices.append(.iPad(version: "10.3"))
devices.append(.macBook)

let sortedDevices: [Device] = devices.sorted()
print(sortedDevices)