Swift 프로그래밍 입문 3

13강 구조체

import Swift

// 13강 구조체
struct Sample {
    // 인스턴스 프로퍼티
    var mutableProperty: Int = 100 // 가변 프로퍼티
    let immutableProperty: Int = 100 // 불편 프로퍼티
    static var typeProperty: Int = 100 // 타입 프로퍼티

    func instanceMethod() {
        print("instance method")
    }

    static func typeMethod() {
        print("type method")
    }
}

var mutable: Sample = Sample()
mutable.mutableProperty = 200
// 불편 프로퍼티는 수정할 수 없음
// mutable.immutableProperty = 200

Sample.typeProperty = 300
Sample.typeMethod()

// 사용 불가
//mutable.typeProperty

struct Company {
    var companyName: String = "people fund"
    var name: String = "zoe"

    static func selfIntroduce() {
        print("저는 회사 타입입니다")
    }
    func selfIntroduce() {
        print("저는 \(self.companyName) 소속 \(self.name)  입니다.")
    }
}

Company.selfIntroduce()

var zoe: Company = Company()
zoe.companyName = "pf"
zoe.name = "kahee"
zoe.selfIntroduce()

14강 클래스

// 구조체는 값타입 클래스는 참조타입, 다중상속 되지 않음
class SampleClass {
    // 가변 프로퍼티
    var mutableProperty: Int = 100
    // 불변 프로퍼티
    let immutableProperty: Int = 100
    // 타입 프로퍼티
    static var typeProperty: Int = 100

    // 인스턴스 메서드
    func instanceMethod() {
        print("instance method")
    }

    // 상속시 재정의 불가 타입 메서드
    static func typeMethod() {
        print("type method - static")
    }

    // 상속시 재정의 가능 타입 메서드
    class func classMethod() {
        print("type  method - class")
    }
}

// let, var 둘다 인스턴스 할당할때 내부 mutable property 값은 변경 할 수 있음
var  mutableReference: SampleClass = SampleClass()
mutableReference.mutableProperty = 200
//mutableReference.immutableProperty = 200
let immutagleReference: SampleClass = SampleClass()
immutagleReference.mutableProperty = 200

// 다만 참조정보 변경 할 수 없음
//immutagleReference = mutableReference
// 예약어 사용할 때는 `` 이걸 사용
class Student {
    var name: String = "unknown"
    var `class`: String = "Swfift"

    class func selfIntroduce() {
        print("학생타입입니다.")
    }

    func selfIntroduce() {
        print("저는 \(self.class)\(name)입니다.")
    }
}

let jina: Student = Student()
jina.name = "jina"
jina.selfIntroduce()

15강 열거형

// 15강 열거형
//  enum 은 타입이므로 대문자 카멜케이스 사용하여 이름 정의
enum Weekday {
    case mon
    case tue
    case wed
    case thu, fri, sat, sun
}

var day: Weekday = Weekday.mon
day = .tue

// switch의 비교값에 열거형 타입이 위치할 때
// 모든 열거형 케이스를 포함한다면
// default를 작성할 필요가 없습니다
switch day {
case .mon, .tue, .wed, .thu:
    print("평일입니다.")
case Weekday.fri:
    print("불금 파티")
case .sat, .sun:
    print("신나는 주말")
}

// c언어 처럼 정수값을 가지게 설정
// 1씩 자동으로 증가
enum Fruit: Int  {
    case apple = 0
    case grape = 1
    case peach //2
}

print("Fruit.peach.rawValue == \(Fruit.peach.rawValue)")
Fruit.peach.rawValue == 2

// Hashable 프로토콜을 따르는 모든 타입이 원시값의 타입으로 지정될 수 있음

enum School: String {
    case elementary =  "초등"
    case middle = "중등"
    case high = "고등"
    case uinversity
}
// 값이 없는 경우 case name 을 가져옴
print("School.university.rawValue == \(School.uinversity.rawValue)")

// case 가 없으면 nil 이 나올 수 있기 때문에 에러
let apple: Fruit? = Fruit(rawValue: 0)

if let orange: Fruit = Fruit(rawValue: 5) {
    print("\(orange) value \(orange.rawValue)")
} else {
    print("해당 케이스가 없습니다.")
}

enum Month {
    case dec, jan, feb
    case mar, apr, may
    case jun, jul, aug
    case sep, oct, nov

    func printMessage() {
        switch self {
        case .mar, .apr, .may:
            print("봄")
        case .jun, .jul, .aug:
            print("여름")
        case .sep, .oct, .nov:
            print("가을")
        case .dec, .jan, .feb:
            print("겨울")
        }
    }
}

Month.mar.printMessage()

16강 클래스 vs 구조체/열거형

// class 만 참조타입, 상속이 가능
// 구조체는 언제 사용하나요? 참조가 아닌 복사를 원할때, 전달되거나 할당될때 상속이 필요없을 때
// 주로 클래스를 많이 사용됨
// value 데이터 전달시 값 복사, reference 주소 전달

struct ValueType {
    var property = 1
}

class ReferenceType {
    var property = 1
}

let firstStructInstance = ValueType()
var secondStruuctInstance = firstStructInstance
secondStruuctInstance.property = 2
print("\(firstStructInstance.property)")    // 1
print("\(secondStruuctInstance.property)")  // 2

let firstClassReference = ReferenceType()
var secondClassReference = firstClassReference
secondClassReference.property = 2
print("\(firstClassReference.property)")    // 2
print("\(secondClassReference.property)")   // 2

// data types 의 경우 구조체로 되어있다. -> 클래스보다 선호
// Apple 프레임워크는 대부분 클래스임

17강 클로저 기본

// fisrt - citizen 변수, 상수 등으로 저장, 전달인자로 전달 가능
// { (매개변수 목록) -> 반환타입 in
// 실행코드
// }
func sumFunction(a: Int, b:Int) -> Int {
    return a + b
}
var sumResult: Int = sumFunction(a: 1, b: 2)

var sum: (Int, Int) -> Int = {
    (a: Int, b: Int) -> Int in return a + b
}

sumResult = sum(1, 2)

// 함수는 클로저의 일종
// sum 변수에 당연히 함수도 할당 가능함
sum = sumFunction(a:b:)

// 함수의 전달인자로서의 클로저 callback
let add: (Int, Int) -> Int
add = { (a: Int, b: Int) -> Int in
    return a + b
}

let substract: (Int, Int) -> Int
substract = { (a: Int, b: Int) -> Int in
    return a - b
}

let divide: (Int, Int) -> Int
divide = { (a: Int, b: Int) -> Int in
    return a / b
}

func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int {
    return method(a, b)
}

var calculated: Int
calculated = calculate(a: 50, b: 100, method: add) //150
calculated  =  calculate(a: 50, b: 100, method: {
    (left: Int, right: Int) -> Int in
        return left * right
})
print(calculated)

18강 클로져 고급

// 너무 다양한 표현법이 있기때문에 다른사람이 이해할 수 있는 정도까지
func calculate(a: Int, b: Int, method: (Int, Int) -> Int) -> Int {
    return method(a, b)
}
var calculated: Int

// 축약전 클로저
calculated  =  calculate(a: 50, b: 100, method: {
    (left: Int, right: Int) -> Int in
    return left * right
})

// 후행 클로저
var result: Int
result = calculate(a: 10, b:10) {
    (left: Int, right: Int) -> Int in
    return left + right
}

// 반환 타입 생략
// method 매개변수는 Int 타입을 반환할 것이라는 것 컴파일러가 이미 알기 때문에 굳이 명시하지 않아도됨
calculated  =  calculate(a: 50, b: 100, method: {
    (left: Int, right: Int) in
    return left * right
})

// 후행 클로저 + 반환타입 생략
calculated = calculate(a: 10, b:10) {
    (left: Int, right: Int) in
    return left + right
}

// 단축 인자이름
result = calculate(a: 10, b: 10, method: {
  return $0 + $1
})

// 암시적 반환 표현
// 클로저의 마지막 줄의 결과값은 암시적으로 반환값으로 취급
result = calculate(a: 10, b: 10){
  $0 + $1
}

result = calculate(a: 10, b: 10) { $0 + $1 }

19강 프로퍼티

// 구조체 안쪽에 사용할 수 있음

struct Student2 {
    // 인스턴스 저장 프로퍼티
    var name: String = ""
    var `class`: String = "Swift"
    var koreanAge: Int = 0

    // 인스턴스 연산 프로퍼티
    var westernAge: Int{
        get {
            return koreanAge - 1
        }

        set(intputValue){
            koreanAge = intputValue + 1
    }
}
    // 타입 저장 프로퍼티
    static var typeDescription: String = "학생"

    // 읽기 전용 인스턴스 연산 프로퍼티
    var selfIntroduction: String{
        get {
            return "저는 \(self.name) 입니다."
        }
    }
}

// 타입 연산 프로퍼티 사용
print(Student.selfIntroduce)

// 인스턴스 생성
var yagom: Student2 = Student2()
yagom.koreanAge = 10

// 인스턴스 저장 프로퍼티 사용
yagom.name = "yagom"
print(yagom.name)
// yagom

// 인스턴스 연산 프로퍼티 사용
print(yagom.selfIntroduction)
// 저는 Swift반 yagom입니다

print("제 한국나이는 \(yagom.koreanAge)살이고, 미쿡나이는 \(yagom.westernAge)살입니다.")

20강 프러퍼티 감시자

// willSet 바뀔값확인 didSet 어디서 변경되었는지 확인
// 연산 프로퍼티 안에는 만들어줄 수 없음, 저장되는 값이 호출 될때 사용되기 때문에
struct Money {
    var currencyRate: Double = 100 {
        willSet(newRate) {
            print("환율이 \(currencyRate)에서 \(newRate)으로 변경될 예정입니다")
        }

        didSet(oldRate) {
            print("환율이 \(oldRate)에서\(currencyRate) 으로 변경되었습니다.")
        }
    }

    // 프로퍼티 감시자 사용
    var dollar: Double = 0 {
        // willSet의 암시적 매개변수 이름 newValue
        willSet {
            print("\(dollar)달러에서 \(newValue)달러로 변경될 예정입니다")
        }

        // didSet의 암시적 매개변수 이름 oldValue
        didSet {
            print("\(oldValue)달러에서 \(dollar)달러로 변경되었습니다")
        }
    }

    // 연산 프로퍼티
    var won: Double{
        get {
            return dollar * currencyRate
        }
        set {
            dollar = newValue/currencyRate
        }
    }
}

var moneylnMyPocket: Money = Money()
moneylnMyPocket.currencyRate = 1150
moneylnMyPocket.dollar = 10
print(moneylnMyPocket.won)