원하는 타이밍에 비동기 처리를 할 수 있게 해준다. 이게 무슨 말일까?? 각설하고 바로 예제를 보자. 1. Completion Handler 예제 모든 method에 completion 인자를 추가해주면, completion Handler를 사용하는 인자로 바꿀 수 있다. func A(completion: () -> ()) { ...10초 걸리는 작업.. completion() ...10초 걸리는 작업.. } func B() -> () { ...5초 걸리는 작업.. } //Completion Handler A(completion: B) // -> A가 호출되고 10초 뒤, B가 비동기로 실행된다. 그림으로 표현하자면 다음과 같다. A 함수 내부에 completion()을 적어둔 시점에서 B가 호출되며, ..
아래와 같이 closure을 인자로 보낼 때, 직접 method를 넣어 보내지 않고 { }을 통해 보낼 수 있다. //아래와 같은 함수의 경우 func A(task:() -> ()) { ... } func B() { ... } //기본 A(task: B) //Trailing Closure //이렇게도 사용할 수 있다! A() { () -> () in B() }
아주 간단히 요약하자면, 다음과 같다. 1. designated init(지정 생성자) 초기화에 반드시 필요한 생성자이다. 무조건 designated init이 불려야 객체가 생성된다. 2. convenience init(보조 생성자) 초기화에 반드시 필요하진 않다. 하지만, designated init이 가진 인자가 아닌 다른 인자로 초기화를 하고 싶을 때 사용한다. 그런데 방금 무조건 designated init이 불려야한다고 했기에, 이 생성자 내부에서 반드시 designated init을 불러야 한다. 다음은 인자가 없는 init을 가진 커스텀뷰를 만들고 싶을 때의 예이다. class CustomView: UIView { convenience init() { self.init(frame: .zer..
1. 저장, 불러오기 앱에서 만들었던 객체들을 Data로 저장하고 다시 불러오고 싶은 경우가 있을 것이다. 이런 경우 사용하는 것이 NSCoding 프로토컬이다. 2. Encode와 Decode NSCoding 프로토컬을 보면 Data로 저장할 때 쓰는 encoding과, Data에서 불러올 때 쓰는 init? method가 있다. 사용법은 필요한 타입에 이 프로토컬을 상속받아 사용하면 된다. 3. 기본 사용 예제 class Shape : NSObject, NSCoding { private var identifier : String ...생략... func encode(with aCoder: NSCoder) { aCoder.encode(identifier, forKey: "identifier") } re..
1. 뭔데 이건 항상 UIView를 상속받고, 쓰려고 하면 다음과 같이 required init?(coder: NSCoder)를 만들어준다. class CustomView: UIView { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 이게 대체 뭐고 왜 필요한지 알아보자. 2. NSCoder? 알기 위해선, 인자로 받고 있는 NSCoder이 무엇인지 먼저 알아야할 필요가 있다. 2023.10.22 - [IOS] - [iOS] NSCoding, 내 마음 속에.. 아니 Data에 저장하고 싶을 때 [iOS] NSCoding, 내 마음 속에.. 아니 Data에 저장하고 싶을 때 1. 저장, 불러오..
다음과 같이 종종 '@'가 붙은 코드들을 볼 수 있다. class A { @Published a: String } 각설하고, 바로 알아보자. 1. 해당 프로퍼티에 접근할 때마다, 수행할 동작을 우리가 원하는 대로 커스텀 할 수 있다. 이렇게만 이야기하면 감이 잡히지 않으니 예시와 함께 보자. 2. 예시 a라는 속성에 어떤 수를 넣더라도 1이라는 숫자가 들어가게 하고 싶을 경우, 다음과 같은 프로퍼티 래퍼를 만들 수 있다. struct OnlySet1 { private (set) var a: Int var wrappedA: Int { get { return value } set { a = 1 } } init(initialA: Int) { self.a = 1 } } 이제 이 프로퍼티 래퍼를 사용하면, str..
guard let a = b else { return } 이런 코드의 경우 옵저버 바인딩에 실패한다면 어디서 오류가 발생하였는지 알기 힘들다. 그래서 return 전에 log를 찍어, 값을 추적해줄 필요가 있다. 1. os_log import OSLog os_log("에러 발생") 그런데 이를 쓰려면 모든 파일에 import OSLog 를 하여야한다. 따로 객체로 분리해주는 편이 좋을 것이다. 2. Logger : 에러 발생 부분 바로 알 수 있는 방법 OSLog에서 제공하는 logger 객체를 활용해보자. enum Log { func make() -> Logger { return Logger() } } logger 객체는 logger 객체가 생성된 부분에서의 위치로 이동해준다. guard let tit..
1. 문제 상황 1-1) shape 객체를 아카이빙하려고 하였다. class Shape : NSObject, NSCoding { private var identifier : String private var point : Point private var size : Size } 1-2) 그런데 encode이 매번 실패하였다. 디버거로 확인해보니, 내가 만든 struct 타입에서 encode를 실패하는 것을 확인할 수 있었다. func encode(with aCoder: NSCoder) { aCoder.encode(identifier, forKey: "identifier") aCoder.encode(point, forKey: "point") // 실패 aCoder.encode(size, forKey: "s..