210324 Wed

Sunny·2021년 4월 3일
0

Today I Learned

목록 보기
18/88
post-thumbnail

학습 내용

1. 첫 번째 학습 내용: 클로져 (Closures)

클로져란? 일정 기능을 하는 코드를 하나의 블록으로 모아놓은 것!

함수는 클로저의 한 형태이다!

클로저는 변수나 상수가 선언된 위치에서 reference를 capture하고 저장할 수 있음

Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures can capture and store references to any constants and variables from the context in which they’re defined. This is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.

클로저는 세 가지 형태가 있음

  • 이름이 있으면서 어떤 값도 획득하지 않는 전역함수의 형태

Global functions are closures that have a name and don’t capture any values.

  • 이름이 있으면서 다른 함수 내부의 값을 획득할 수 있는 중첩된 함수의 형태

Nested functions are closures that have a name and can capture values from their enclosing function.

  • 이름이 없고 주변 문맥에 따라 값을 획득할 수 있는 축약 문법으로 작성한 형태

Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.

클로저의 표현 방식

  • 클로저는 (매개변수와 반환 값의 타입을 문맥을 통해 유추할 수 있기 때문에) 매개변수와 반환 값의 타입을 생략할 수 있음

Inferring parameter and return value types from context

  • 클로저에 단 한 줄의 표현만 들어있다면 암시적으로 이를 반환값으로 취급함

Implicit returns from single-expression closures

  • 축약된 전달인자 이름을 사용할 수 있음

Shorthand argument names

  • 후행 클로저 문법을 사용할 수 있음

Trailing closure syntax

let names: [String] = ["Sunny", "Kangkyung", "Yun"]

func backwards(first: String, second: String) -> Bool {
    return first > second
}

let reversed: [String] = names.sorted(by: backwards)
print(reversed)

// print ["Yun", "Sunny", "Kangkyung"]
// 알파벳 역순으로 정렬된 것을 알 수 있음

클로저 표현은 통상 아래 형식을 따름

{ (매개변수들) -> 반환 타입 in
	 실행코드 
}

sorted(by:) 메서드에 클로저 전달

첫 번째 예시에서의 backwards(first:second:) 함수 대신에 sorted(by:) 메서드의 전달인자로 클로저를 직접 전달

let names: [String] = ["Sunny", "Kangkyung", "Yun"]
let reversed: [String] = names.sorted(by: { (first: String, second: String) -> Bool in
    return first > second
})
print(reversed)
// print ["Yun", "Sunny", "Kangkyung"]

후행 클로저 (Trailing Closures)

  • 함수나 메서드의 마지막 전달인자로 위치하는 클로저는 함수나 메서드의 소괄호를 닫은 후 작성해도 됨.
  • 언제 쓰나? 클로저가 조금 길어지거나 가독성이 조금 떨어진다 싶을 때 사용하면 좋음.
// 후행 클로저의 사용
let reversed: [String] = names.sorted() { (first: String, second: String) -> Bool in
    return first > second
}

// sorted(by:) 메서드의 소괄호까지 생략 가능
let reversed: [String] = names.sorted { (first: String, second: String) -> Bool in
    return first > second
}

값 획득 (Capturing Values)

클로저는 특정 문맥의 상수나 변수의 값을 캡쳐할 수 있습니다. 다시말해 원본 값이 사라져도 클로져의 body안에서 그 값을 활용할 수 있습니다.

A closure can capture constants and variables from the surrounding context in which it’s defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.

func makeIncrementer(forIncrement amount: Int) -> (() -> Int) {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

// incrementByTwo 상수에 상수 할당
let incrementByTwo: (() -> Int) = makeIncrementer(forIncrement: 2)

// 각각의 incrementer의 동작
let incrementByTwo: (() -> Int) = makeIncrementer(forIncrement: 2)
let incrementByTwo2: (() -> Int) = makeIncrementer(forIncrement: 2)
let incrementByTen: (() -> Int) = makeIncrementer(forIncrement: 10)

let first: Int = incrementByTwo() // 2
let second: Int = incrementByTwo() // 4
let third = incrementByTwo() // 6

let ten: Int = incrementByTen() // 10
let twenty: Int = incrementByTen() // 20
let thirty: Int = incrementByTen() // 30

incrementByTwo와 incrementByTen은 모두 상수.

이 두 상수 클로저는 값 획득을 통해 runningTotal 변수를 계속해서 증가시킬 수 있음

→ Why? 함수와 클로저는 참조 타입이기 때문!

클로저는 참조 타입 (Closures Are Reference Types)

  • 함수나 클로저를 상수나 변수에 할당할 때마다 상수나 변수에 함수나 클로저의 참조를 설정하는 것.
  • incrementByTwo라는 상수에 클로저를 할당한다는 것은 (내용물, 즉 값을 할당하는 것이 아닌) 해당 클로저의 참조를 할당
  • 결국 클로저의 참조를 다른 상수에 할당해준다면 이 두 상수가 모두 같은 클로저를 가리킴

Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it’s the choice of closure that incrementByTen refers to that’s constant, and not the contents of the closure itself.

This also means that if you assign a closure to two different constants or variables, both of those constants or variables refer to the same closure.

2. 두 번째 학습 내용: 고급 연산자 (Advanced Operators)

부호없는 Integer의 시프팅 (Shifting Behavior for Unsigned Integers)

아래 예제에서 pink와 16진수와 AND 연산을 하게 되는데 여기서 FF는 윈도우 역할을 해서 AND연산에서 FF의 위치에 있는 값만 취해 시프트 연산을 하게 됩니다. ??? 🤔

let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16    // redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF           // blueComponent is 0x99, or 153

문제점/고민한점 → 해결방안

클로저를 통해 비동기 콜백(call-back) ??? 🤔

자료 출처:

profile
iOS Developer

0개의 댓글