Swift

Core Data의 not Optional 설정 시 크래쉬 주의

Phililip
728x90

안녕하세요.

 

이번에는 Core Data를 Optional로 설정했을 시 주의사항에 대해서 알아보겠습니다.

 

 

 

이번 글은 아래 글을 토대로 작성하였습니다.

 

- https://atomicbird.com/blog/clash-of-the-optionals/

 

Clash of the Optionals

…or, how to accidentally break Swift initialization rules. Today I’m going to talk about optionals. Swift optionals. And also another kind of optional. And how you might break the ironclad rules of Swift without realizing it until it’s too late. What

atomicbird.com

 

 


 

## 1. 현상

 

Core Data에 Attribute를 추가하면 아래와 같은 설정 화면이 나옵니다.

(임의로 timestamp라는 attribute를 추가해봤어요.)

 

 

 

 

 

설정화면을 보면 기본적으로 Optional이 체크되어 있어요.

 

만약 timestamp가 Optional value가 아닌, 즉 항상 non-nil이 보장된다면 Optional 체크박스를 해제해주면 됩니다.

 

 

 

그런데 Xcode > Editor > Create NSManagedObject Subclass를 눌러서 코드로 뽑아보면 timestamp가 여전히 Optional 한 것을 볼 수 있어요..

 

 

 

 

흐으음.... 🤔 🤔 🤔 

 

 

전 분명 Optional 체크박스를 해제했는데, 코드화 시키니 여전히 Optional 하다고 되어있네요.....????

(이게 오늘의 핵심 주제입니다.)

 

 

왜 그럴까요????

 

 

 

## 2. 이유

 

그 이유를 알기 위해서는, 우선 Swift와 Core Data를 분리해서 봐야 합니다.

 

 

Swift의 not optional의 의미 Core Data의 not optional의 의미
초기화 시점 이후에는 property가 non-nil 이어야 한다. Core Data에 저장되어 있는 값을 변경할 때, 변경할 값이 non-nil 이어야 한다.

 

 

즉, Swift의 not optional과 Core Data의 not optional의 의미가 서로 다르기 때문에

 

우리의 똑똑한 Xcode는 코드로 추출했을 때 가장 안전한 방법인 Optional로 만들어주는 것이죠ㅠㅠ

(not optional로 했다가 런타임 때 크래쉬가 발생할 수 있기 때문이죠....ㅠㅠ)

 

 

 

이쯤에서 의문점이 하나 생길 것 같아요.

 

그냥 아래처럼 강제로 not optional로 바꿔주면 안 됨???

 

extension Event {
    @NSManaged public var timestamp: Date       // '?' 제거하면 not optional이 됨
}

 

 

결론은 가능하다!! 입니다. 하지만 전제조건이 있어요. 크래쉬가 나지 않게 잘~ 써야 합니다...;;;

 

 

 

timestamp 프로퍼티 앞에 @NSManaged 속성이 붙어있죠??

 

크래쉬가 나지 않게 어떻게 써야 하는가... 에 대해 알아보기 전에 우선 @NSManaged 속성에 대해 간단하게 알아봐야 할 것 같아요.

 

 

 

 

@NSManaged 속성을 사용하면 Swift Optional 규칙을 따르지 않게 됩니다.

 

즉, 프로퍼티가 not optional 일 경우, 초기화 시점이 아닌 값을 변경할 때 non-nil 이기만 하면 문제가 없다는 것이죠.

 

 

 

 

그래서 만약에 아래처럼 강제로 not optional로 바꿔줄 경우에 어떤 문제가 발생할 수 있냐면,

 

extension Event {
    @NSManaged public var timestamp: Date
}

 

let newEvent = Event()                     // timestamp 값 설정하지 않았는데 컴파일 에러가 발생하지 않음.
print("Date : \(newEvent.timestamp)")      // timestamp는 실질적으로 nil이기 때문에 크래쉬 발생

 

위 코드처럼, newEvent 인스턴스를 생성할 때 timestamp 값을 설정하지 않았지만 컴파일 에러가 발생하지 않습니다.

 

컴파일 에러가 발생하지 않으니, 런타임 때 newEvent.timestamp 프로퍼티로 접근하게 되면 nil 이기 때문에 크래쉬가 발생하게 되는 것이죠.

(속성을 not optional로 바꿈으로써, non-nil 제약조건이 초기화 시점 -> 값 변경 시점으로 변경되었기 때문이죠)

 

 

이런 문제는 쉽게 눈에 띄지 않기 때문에 앱 구동에 문제를 일으킬 가능성이 매우 높습니다ㅠㅠㅠ

 

 

 

 

## 3. 해결방법

 

프로퍼티의 속성을 not optional로 바꾸고 싶을 경우 발생할 수 있는 문제들에 대한 해결방법에 대해 소개하겠습니다.

 

 

### 3.1 (방법 1) not optional 프로퍼티에 접근할 때 nil 체크를 한다.

 

 

 

 

### 3.2 (방법 2) Default 값을 설정해준다.

 

 

 

#### 3.3 (방법 3) awakeFromInsert method를 구현한다. (값을 동적으로 할당해야 하는 경우)

 

 

 

 


 

 

이번 글은 여기서 마무리.

 

 

 

 

반응형

'Swift' 카테고리의 다른 글

CryptoKit을 사용한 암호화  (0) 2022.02.23
async/await 용 public API를 추가할 때 고려사항  (1) 2022.02.23
enum 남용 주의  (0) 2022.02.17
Literal 이란?  (1) 2022.02.07
Swift 인스턴스 method 목록 가져오는 방법  (0) 2022.02.06