removeObject(forKey:) 메서드를 사용하여 "greet"에 해당하는 값을 제거합니다.
데이터 타입별 저장
// 숫자 저장
UserDefaults.standard.set(123, forKey: "onetwothree")
// 부울 저장
UserDefaults.standard.set(true, forKey: "isEmpty")
// 배열 저장
let fruits = ["Apple", "Banana", "Orange"]
UserDefaults.standard.set(fruits, forKey: "fruits")
UserDefaults는 작은 규모의 데이터를 다룰경우 사용된다고 합니다. 큰 규모의 데이터를 다룰 경우 외부 라이브러리나 CoreData를 사용 해야겠죠..? 그럼 CoreData도 알아야겠죠...?
다시는 게을러 지지 않는다 했지만.. 한달간 작성글이 없네요..하하... 반성하겠습니다.. 공부는 자주 하지 않으면서 자기 합리화만 해왔던것 같네요... 공부는 잘 하지 않았어도 인턴 지원은 계속 하고있었습니다~ 하하 합격을 못해서 그렇지만요...
저 혼자 감사 챌린지를 진행하고 있었습니다. 의욕이 없어지면서 당장 졸업을 해야하니 기분이 푹 꺼지더라구요.. 그러던중 세우 라는 스트리머의 영상을 보면서 마음을 다잡았던것 같아요. 모든일에 감사를 붙이면 조금 힘이 된다구 하더라구요.. ㅋㅋ 무슨소리인줄 처음엔 감이 안잡혔지만 뭐 예를 들어 "아침에 늦잠 안잔 나에게 감사해🙏" 같이 모든 활동에 감사를 붙이니
머리속에 부정적인 생각이 사라지더라구요 하하
의미는 찾지 않았지만 항상 긍정적이라고 생각해왔던 제가 요근래 부정적인 생각이 머리속을 가득 차있었어서
감사해 챌린지를 하니 부정적인 생각이 씻겨내려갔어요 캬캬
여러분 모두 부정적인 생각에서 벗어나는 감사챌린지를 추천해드립니다 bb
오늘은 강의를 중점적으로 들었던것 같습니다. 델리게이트 패턴을 조금 맛봤는데요!! 아직 반숙도 아니니... 완숙이 될때까지 공부해보도록 하겠습니다.
앞으로의 계획선언
조금더 부지런히 살아야죠 지난달을 돌이켜보면 조금은 시간을 허투루 쓴것같습니다.. 강의 구매도 하였으니 매일 수강하고, 포트폴리오를 위한 개인 프로젝트를 진행해야겠습니다!!
강의를 듣고 개인프로젝트를 진행하면서 델리게이트 패턴또한 파해쳐 보겠습니다!
미숙하고,, 완전하지않고,, 게을러진 나를 반성하며,, 화이팅...!! (강의늪에 빠지지 않도록 주의하며 다 내꺼로 만들자)
class DiceGameTracker: DiceGameDelegate {
var numberOfTurns = 0
func gameDidStart(_ game: DiceGame) {
numberOfTurns = 0
if game is SnakesAndLadders {
print("Started a new game of Snakes and Ladders")
}
print("The game is using a \(game.dice.sides)-sided dice")
}
func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
numberOfTurns += 1
print("Rolled a \(diceRoll)")
}
func gameDidEnd(_ game: DiceGame) {
print("The game lasted for \(numberOfTurns) turns")
}
}
위의 예제는 DiceGameTracker클래스가 DIceGameDelegate 프로토콜을 채택합니다.
금, 토, 일요일을 신나게 쉬었습니다.. 하하 금요일은 어머니 생신을 같이 보냈구요, 토요일은 여자친구와 함께 시간을 보냈습니다~ 일요일은 늑연골염 덕분에 거의 누워있었던것 같습니다...
이정도면 많이 쉬었군요. 어제 장수상회를 보며 눈물을 질질 흘렸습니다.. 얼마나 슬프던지 배우분들을 보면서 할머니랑 할아버지 생각이 나 눈물이 더 많이 났던것 같네요.. 여러분들도 한번쯤은 보면 좋은 영화입니다 가족애 뿜뿜 ㅎㅎ
흐 계속 쉬고싶지만.. 누워만 있는건 조금 찔리는것 같네요 하하하...흐...ㅎ...ㅡ....ㅠㅠ,,,,
배운점
저번에 다하지 못한 미소유 참조 와 약한참조를 공부해보겠습니다!
약한 참조
약한 참조는 참조하는 인스턴스를 강하게 유지하지 않는 참조이므로 ARC가 참조된 인스턴스를 처리하는것을 중지하지 않는다고 합니다.
이 동적운 참조가 강한 참조 사이클의 일부가 되는 것을 방지합니다!
프로퍼티나 변수의 선언 앞에 weak 키워드를 위치시켜 약한참조를 나타냅니다.
약한 참조는 참조하는 인스턴스를 강하게 유지하지 않기 때문에 약한 참조가 참조하는 동안 인스턴스가 할당 해제 될 수 있습니다!
따라서 ARC는 인스턴스가 해제되면 nil 로 약한 참조를 자동으로 설정합니다.
따라서 nil 로 바뀌는 것을 허락 해야하므로 옵셔널 타입의 변수로 선언됩니다.
다른 옵셔널 값과 같이 약한 참조에 값의 존재를 확인할 수 있고, 더이상 존재하지 않는 유효하지 않은 인스턴스에 참조하는것으로 끝나지 않습니다 (????) -> 약한 참조는 옵셔널 값과 유사하지만, 옵셔널 값처럼 유효하지 않은 인스턴스를 참조할수 없다는 것을 의미하는것 같네요..
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
위의 코드는 Apartment 클래스의 tenant 프로퍼티는 약한참조로 선언되었습니다.
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
이전과 같이 john과 ubut4A는 강한참조로 연결됩니다.
Person 인스턴스는 Apartment 인스턴스에 대해 강한 참조를 가지고 있지만 Apartment 인스턴스는 Person 인스턴스에 대해 약한참조를 가지고 있습니다. -> john 변수에 nil 을 할당하여 강한참조를 끊으면 Person 인스턴스에 대해 더이상 강한참조가 아님을 의미합니다.
john = nil
// Prints "John Appleseed is being deinitialized"
더이상 Person 인스턴스에 대해 강한 참조를 가지고 있지 않기 때문에 할당 해제되고 tanant 프로퍼티는 nil 이 됩니다.
Apartment 인스턴스에 대한 유일한 참조는 unit4A 변수에서 가져온 것입니다. 강한참조를 끊으면 Apartment 인스턴스에 대한 강한참조는 더이상 없습니다.
unit4A = nil
// Prints "Apartment 4A is being deinitialized"
Apartment에 대한 강한참조가 없으니 할당 해제 됩니다.
미소유 참조
미소유 참조는 약한 참조와 같이 인스턴스를 강하게 유지하지 않습니다. 하지만 약한 참조와 다르게 미소유 참조는 다른 인스턴스의 수명이 같거나 더 긴 경우에 사용됩니다.
프로퍼티 선언 앞부분에 unowned 키워드를 붙여 미소유 참조를 나타냅니다.
약한 참조와 달리 미소유 참조는 항상 값을 갖도록 예상됩니다. 따라서 미소유로 만들어진 값은 옵셔널이 아니고, ARC는 미소유 참조의 값을 nil로 할당하지 않습니다.
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
위의 예제는 Customer 와 CreditCard의 관계입니다. 고객은 신용카드를 가지고 있거나 아닐수 있지만, 신용카드는 항상 고객과 연관되어 있습니다.
클래스의 새로운 인스턴스가 생성될 때마다 ARC는 인스턴스에 대한 정보를 저장하기 위해 메모리의 청크에 할당합니다. (메모리 청크 :동적으로 메모리를 할당할 때 사용되는 일정한 크기의 메모리 블록)
이 메모리는 해당 인스턴스와 관련된 저장된 프로퍼티의 값과 함께 인스턴스의 타입에 대한 정보를 가집니다.
또한 인스턴스가 더이상 필요치 않을 때 ARC는 메모리가 다른 목적으로 사용될 수 있도록 인스턴스에 의해 사용된 메모리를 할당 해제합니다. (이렇게 하면 메모리를 효율적으로 관리할 수 있겠군요!)
하지만 ARC가 아직 사용중인 인스턴스의 할당을 해제하면 더이상 인스턴스의 프로퍼티에 접근할 수 없거나 인스턴스의 메모리를 호출할 수 없습니다. (인스턴스에 접근하려 하면 앱은 크래시가 발생한다고 합니다.)
ARC 동작
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
위의 예제는 ARC의 동작에 대한 예제 입니다.
var reference1: Person?
var reference2: Person?
var reference3: Person?
Person에 여러개의 참조를 설정하기 위해 Person? 타입의 3개 변수를 정의합니다.
옵셔널 타입이므로 nil 값으로 자동으로 초기화되고 현재는 Person 인스턴스를 참조하지 않고 있습니다.
reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"
새로운 Person의 인스턴스는 reference1 변수에 할당되기 때문에 강한 참조가 있습니다.
하나의 강한 참조가 있기 때문에 ARC는 이 Person을 메모리에 유지하고 할당 해제하지 않습니다.
reference2 = reference1
reference3 = reference1
위의 예제로 이제 Person의 인스턴스에 3개의 강한 참조가 있습니다.
reference1 = nil
reference2 = nil
2개의 변수에 nil을 할당하여 강한 참조 3개중 2개가 중단되어 1개의 강한참조만 남고 Person 인스턴스는 할당 해제되지 않습니다.
reference3 = nil
// Prints "John Appleseed is being deinitialized"
마지막 강한 참조를 중단하여 Person 인스턴스는 할당 해제 됩니다.
클래스 인스턴스 사이의 강한 참조 사이클
ARC동작의 예제에선 Person 인스턴스를 생성하고 더이상 필요치 않을 때 Person 인스턴스 할당 해제하기 위해 참조의 수를 추적할 수 있습니다.
그러나 클래스의 인스턴스가 강한 참조가 없는 지점에 도달하지 않는 코드를 작성할 수 있습니다. 이는 두 클래스 인스턴스가 서로에 대한 강한 참조를 유지하여 각 인스턴스가 다른 인스턴스를 유지하는 경우 발생할 수 있습니다! 이를 강한 참조 사이클 이라고 합니다.
(예제를 보며 이해를 돕겠습니다~~)
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
위의 예제에서 Person 인스턴스는 String 타입의 name 프로퍼티와 초기값인 nil 인 옵셔널 apartment 프로퍼티를 가지고 있습니다.
(사람이 항상 아파트를 가지고 있지 않기 때문에 apartment 프로퍼티는 옵셔널 입니다.)
Apartment는 Person과 비슷하기 String 타입의 unit 프로퍼티와 초기값이 nil 인 옵셔널 tenant 프로퍼티를 가지고 있습니다.
(아파트를 항상 보유하는 것은 아니므로 tenant 프로퍼티는 옵셔널 입니다. 아파트는 항상 거주자를 보유하지 않으니까 로 이해해도 괜찮은건지...)
var john: Person?
var unit4A: Apartment?
옵셔널 타입의 2개의 변수를 정의합니다.
이제 특정 Person 인스턴스와 Apartment 인스턴스를 생성할 수 있습니다.
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
다음은 강한 참조가 이 두 인스턴스를 생성하고 할당하여 어떻게 보이는지 나타냅니다.
john변는 이제 새로운 Person 인스턴스에 대한 강한 참조를 가지고 있고, unit4A는 Apartment 인스턴스에 대해 강한 참조를 가지고 있습니다.
john!.apartment = unit4A
unit4A!.tenant = john
이제 사람은 아파트를 가지고 아파트는 소유자를 가지도록 두 인스턴스를 연결했습니다. 위의 예제로써 강한참조가 밑의 그림처럼 바뀌었습니다.
불행히도? 이 두인스턴스 연결은 강한 참조 싸이클을 생성합니다. 따라서 john과 unit4A변수에 의해 가진 강한 참조를 중단할 때 참조 카운트는 0으로 떨어지지 않고 인스턴스는 ARC에 의해 할당 해제되지 않습니다.
(참조가 발생할경우 ARC에 의해 참조 카운트가 1씩 증가, 참조가 해제되면 1감소)
john = nil
unit4A = nil
위의 코드로 nil로 설정할때 초기화 해제 구문은 호출이 되지 않습니다.
강한 참조 사이클은 Person과 Apartment 인스턴스가 할당 해제되는 것을 방지하여 앱에서 메로리 누수를 유발합니다!
따라서 Person과 Apartment 인스턴스 간의 강한 참조는 남아있고 중단 될 수 없습니다.
클래스 인스턴스 간의 강한 참조 사이클 해결
위와같은 문제를 해결하기 위해 Swift는 2개의 해결방법을 제공합니다.
1. 약한 참조 (weak reference)
2.미소유 참조 ( unowned reference )
이 2개를 사용하면 참조 사이클의 한 인스턴스가 강한 유지 없이 다른 인스턴스를 참조할 수 있습니다.
약한 참조를 사용하는 경우
다른 인스턴스의 수명이 더 짧은 경우 즉, 다른 인스턴스가 먼저 할당 해제 될 수 있을 때 약한 참조를 사용합니다.
위의 Apartment 예제에서 아파트는 어느 시점에 소유자가 없을 수 있는 것이 적절하므로 이경우 약한 참조를 사용하여 참조 사이클을 끊는 것이 적절한 경우 입니다.
미소유 참조를 사용하는 경우
다른 인스턴스의 수명이 동일하거나 더 긴 경우 미소유 참조를 사용합니다.
(오느른 여기까지...)
생각과 감정
건강하자고 한 운동이 잘못된 자세로 인해 건강을 해치고 있었군요... 그리고 컴퓨터를 많이해 일자목이.. 큽...
여러분도 자세 바르게하는 습관을 꼭 유지하세요....
요즌 document를 읽으면서 느끼는 감정이 대학 1, 2학년에 새로운 언어를 배울때 느끼는 감정과 조금은 비슷하네요ㅋ..
사실 그때는 이런걸 배우는 이유는 생각하지 않고 그냥 just 배워~ 학점을 위해서 머리에 때려넣고 까먹었는데
지금은 절대.. 절대는 모르겠지만 머리에 계속 남아있게 한번씩 들려서 다시 봐야겠어요.. 그리고 조금은 재밌다랄까요?
언어의 특징을 배우면서 한발짝은 아니어도 조금은 Swift와 친해졌다는 느낌이 많이 듭니다 ㅎㅎ
참조를 배우면서 예전에 다른 언어에서 배운것에대한 기본기는 조금? 비슷해서 이해하기 수월했습니다.. 그래도 조금 수월한 것이지 많이 어렵네요 ㅎㅎ
앞으로의 계획선언
빨리 회복해서 다음 약한참 조와 미소유 참조를 공부 하도록 하겠습니다!! 그리고 개인 프로젝트를 준비해야겠어요 마냥 document만 읽고있을수는 없으니 간단한 앱으로 시작하며 성장하겠습니다~~
함수의 마지막 인수로 함수에 클로저 표현식을 전달해야하고 클로저 표현식이 긴 경우 후행 클로저를 사용한다고 합니다!
예제를 보면서 알아보았습니다.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
위의 코드에서 someFunctionThatTakesAClosure 함수는 하나의 매개변수를 가지고 있습니다.
이 매개변수는 closure라는 이름의 클로저입니다.
someFunctionThatTakesAClosure함수를 호출할 때 closure 매개변수에 클로저를 전달합니다. 클로저는 중괄호로 묶여 있습니다.
someFunctionThatTakesAClosure함수를 호출할 때 후행 클로저를 사용합니다!
후행클로저는 함수의 마지막 매개변수로 전달되기 때문에 매개변수 이름을 생략할 수 있습니다.
마지막 someFunctionThatTakesAClosure()의 부분을 보시면 코드를 더욱 간결하게 사용할 수 있습니다.
특히 함수의 마지막 매개변수가 클로저인 경우 후행클로저를 사용하면 코드가 더욱 깔끔해집니다!!
주의할 점은 후행 클로저는 함수의 마지막 매개변수로만 사용할 수 있다는 점입니다!
reversedNames = names.sorted() { $0 > $1 }
문자열 정렬 클로저는 메서드의 소괄호 밖에 작성될 수 있습니다!
reversedNames = names.sorted { $0 > $1 }
후행 클로저로 표현식이 함수와 메서드의 유일한 인수일 경우 함수를 호출할때 ()를 생략해도 좋습니다!
위의 예제는 0은 "Zero"등으로 숫자를 그에 해당하는 영어로 매핑하는 딕셔너리 입니다!
numbers 배열을 사용하여 후행 클로저로 map(_:)메서드로 클로저 표현식을 작성하여 String값의 배열을 생성 할 수 있습니다.
let strings = numbers.map { (number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
// strings is inferred to be of type [String]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]
클로저 몸체를 보시면,
number를 number로 초기화 하고있습니다.
output 변수를 ""로 초기화 하고있습니다.
repeat으로 number가 0이 될때까지 반복합니다.
반복문의 각 반복에서 클로저는 number의 나머지를 구하고, 해당하는 영어 이름을 output변수에 추가합니다.
마지막으로 클로저는 output 변수의 값을 반환합니다.
따라서 map함수는 numbers 배열의 각 요소에 대해 위의 클로저를 실행하고, 각 요소에 대한 클로저의 결과를 배열 strings에 저장합니다.
( 딕셔너리의 서브 스크립트는 키가 존제하지 않는 경우에 값을 찾는걸을 실패하기 위해 옵셔널 값을 반환합니다! 따라서 digitNames뒤에 !를 붙여줍니다.)
함수가 여러개의 클로저를 가지고 있다면 첫번째 후행 클로저의 인수 라벨을 생략하고 남은 후행 클로저의 라벨을 표기합니다.
클로저를 실행하기 전에 num이란 값을 외부에서 변경하면 클로저 내부에서 사용하는 num의 값또한 변경됨!!
(다시 document로...)
Swift에서 값을 캡처할 수 있는 간단한 클로저 형태는 다른 분문 내에 작성하는 중첩함수 입니다.
중첩함수는 바깥 함수의 어떠한 인수도 캡처할 수 있고, 바깥 함수 내에 정의된 상수와 변수를 캡처 할 수 있습니다.
(이해가 조금 어려우니 예제를 보면서 이해하겠습니다!)
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
incrementer는 중첩함수로 makeIncrementer함수의 내부에 정의되어 있습니다.
incrementer()함수는 둘러싸인 컨텍스트에 runningTotal과 amount값을 캡처합니다. 이값을 캡처한 후 incrementer는 호출할때마다
amount로 runningTotal을 증가시키는 클로저로 makeIncrementer에 의해 반환됩니다.
makeIncrementer의 반환타입은 () -> Int 입니다. 이것은 함수를 반환한다는 의미입니다!
incrementer() 함수는 파라미터가 없으며 함수 본문 내에 runningTotal 과 amount 를 참조하고 있습니다. 둘러싸인 함수에 runningTotal 과 amount 대한 참조 (reference) 를 캡처하고 함수 내에서 사용합니다. 참조를 캡처하는 것은 makeIncrementer 호출이 종료될 때 runningTotal 과 amount 가 사라지지 않고 다음에 incrementer 함수가 호출될 때 runningTotal 을 사용할 수 있습니다.
incrementer 함수는 파라미터가 없으며 함수 본문 내의 runningTotal과 amount를 참조하고 있습니다.
runningTotal과 amount에 대한 참조(reference)를 캡처하고 함수 내에서 사용합니다! 참조를 캡처하는 것은 makeIncrementer호출이 종료될 때 runningTotal과 amount가 사라지지 않고 다음에 incrementer함수가 호출될때 runningTotal을 사용할 수 있습니다!!
클로저는 참조 타입
참조하는 클로저는 캡처한 runningTotal을 계속 증가시킬수 있는 이유는 함수와 클로저가 참조타입(reference tpyes)이기 때문입니다!
뒷부분은 ARC를 공부한후 다시오도록! - 엡! 삐~
생각과 감정
이전엔 졸업까지 별로 남지 않아 마음이 많이 조급했던것 같습니다! 흠... 다른분들에게 조언을 받고 여러 유튜브 영상을 보아도 천천히 자기페이스에 맞춰서 공부하는게 모쪼록 도움이 크다고 했지요.. 하하 저도 천천히 저의 페이스에 따라 나아가려 합니다!!