적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

Swift iOS 앱 개발/Swift 튜토리얼

[Stanford iOS] Lecture 4. Grid + enum + Optionals

hongssup_ 2021. 4. 5. 22:09
반응형

Grid

add rows and columns by replacing HStack with Grid. 

How Swift deal with memory : the way that Swift cleans up memory is when nobody points to something anymore, it cleans up the memory and frees it up for someone else to use.

Memory cycle : if two things are pointing to each other and they’re both in the heap, they’re never gonna be able to go away b/c they’re always gonna have a pointer to each other.

@escaping used so that we can detect memory cycles by escaping functions

.self is required to make the capture semantics explicit. 

(capture semantics means the fact that it’s going to capture everything inside onTapGesture’s function and keep it in the heap so that when onTapGesture executes it in the future when someone taps on this Card, that this stuff is still around. 근데 structure 라서 갠춘? 

Grid is a container. it contains all Views and puts them in rows and columns it contains them. 컨테이너의 역할은 할당된 공간을 안에 있는 것들로 나누어주는것? offer space and position things. 

so need to figure out how much space has been allocated. => use GeometryReader to find out how much space was given to the Grid

GridLayout : its initializer takes a number of items and a size 

 

Enum

: another variety of data structure in addition to struct and class 

- the value is discrete (이산 값)

enum MenuItem {
    case hamburger
    case fries
    case drink
    case cookie
}

- an enum is a value type(like struct), so it is copied as it is passed around

- Associated Data : each of descrete values can have some associated data with it

다른 언어들과 다르게 Swift에서의 enum 각각의 값과 관련된 데이터들을 가질수 있다는 . 

- Checking an enum's state

An enum's state is checked with a switch statement (if 말고)

var menuItem = MenuItem.hamburger(patties: 2)
switch menuItem {
    case .hamburger: break
    case .fries: print("fries")
    default: print("other")

switch - case : switch must handle all possible cases 

break : do nothing in a given case

default : if not a specific case

- switching on self : can test the enum's state (and get associated data) using self ... 

switch self { case. ... }

- 흥미로운 enum protocol "CaseIterable" : getting all the cases if an enumeration

enum 타입에서 CaseIterable 프로토콜을 사용하면 allCases라는 static var를 사용할 수 있게 된다. that you can iterate over. 

enum Numbers: CaseIterable {
    case 1
    case 2
    case 3
}

for num in Numbers.allCases {
    ...
}

 

Optional

: the most important enum

enum Optional<T> {
    case none
    case some(T)	//has associated value, which is a don't care 
}

can only have two discrete values : is set (some) or not set (none)

optional works with any type, it doesn't care what type it is

정해지지 않은 변수가 필요하거나 값을 리턴해야 할 때 magic type "Optional"을 쓰면 된다. 

nil 값을 할당하고 싶을 때에도 optional .none 을 쓰면 됨. 

- Optional, force unwrapping 쓰는 법

case some (value set) : ! 

let x: String? = ... 
print(x!)

switch x {
    case .none: //raise an exception (crash)
    case .some(let data): print(data)
}

- 안전하게 if let 사용해서 crash 방지. set case 일 경우 { } 안에. 아니면 밖에. 

if let safex = x {
    print(safex)
} else { //do something else }

switch x {
    case .none: { //do something else }
    case .some(let data): print(data)
}

- Optional defaulting : ??  (= nil-coalescing operator)

let x: String? = ...
let y = x ?? "foo"

switch x {
    case .none: y = "foo"
    case .some(let data): y = data
}

 

MemoryGame

struct MemoryGame<CardContent> 에서 

if cards[chosenIndex].content == cards[potentialMatchIndex].content { ... }

를 입력하면 Binary operator '==' cannot be applied to two 'CardContent' operands 라는 경고문이 뜬다. 

static func == (Self, Self) -> Bool

이렇게 '==' 는 Swift 내장기능이 아니라 하나의 함수 이름이라고 생각하면 되는데, 특정 type들에서만 사용이 가능하다. 

MemoryGame<CardContent>에서 CardContent는 type을 알 수 없는 Generic이기 때문에, == 를 사용할 수 없는것.

다행히도 == 함수는 'Equatable'이라는 프로토콜 안에 있기 때문에, 다음과 같이 이 프로토콜을 상속해주면 사용이 가능하다. 

struct MemoryGame<CardContent> where CardContent: Equatable { ... }

 

 

.indices : The indices that are valid for subscripting the collection, in ascending order.

var indices: Range<Int> { get }

 

 

 

var indexOfTheOndAndOnlyFaceUpCard: Int? {
    get {
        var faceUpCardIndices = [Int]()
        for index in cards.indices {
            if cards[index].isFaceUp {
                faceUpCardIndices.append(index)
            }
        }
        if faceUpCardIndices.count == 1 {
            return faceUpCardIndices.first
        } else {
            return nil
        }
    }
    set {
        for index in cards.indices {
            if index == newValue {
                cards[index].isFaceUp = true
            } else {
                cards[index].isFaceUp = false
            }
        }
    }
}

이렇게 긴 코드를

var indexOfTheOndAndOnlyFaceUpCard: Int? {
    get { cards.indices.filter { cards[$0].isFaceUp }.only }
    set {
        for index in cards.indices {
            cards[index].isFaceUp = index == newValue
        }
    }
}

이렇게 간단하게 줄여버림... 

728x90
반응형