본문 바로가기

UserDefaults 기초 정리

기술적인 이야기/애플 플랫폼 개발 2021. 10. 17.
반응형

UserDefaults는 iOS나 macOS 등 애플 플랫폼 용 앱에서 간단한 정보나 설정을 저장하고 읽어 들이기 위해 사용하는 클래스다. 데이터를 키-값(Key-Value) 스타일로 읽거나 쓸 수 있게 구성되어 있다. 해당 데이터는 각 앱의 전용 공간에 plist 형태로 저장되며 따라서 앱이 종료되어도 기록이 남아서 앱이 실행되었을 때 다시 읽을 수 있다.

Swift에서는 UserDefaults라는 이름으로 사용되고 있지만 원래 이름은 NSUserDefaults이고 Objective-C 코드에서는 아직도 이 이름이 사용되고 있다. 참고로 이 글은 Swift 기준이다.

이 클래스의 레퍼런스 매뉴얼을 살펴보면 굉장히 다양한 기능을 제공하고 있지만, 보통은 .standard라는 싱글톤 객체를 이용해 저장하거나 읽어 들이는 단순한 메서드를 주로 사용한다.

데이터는 단순한 Swift 기본 타입의 값 위주로 사용한다고 생각하자. 복잡하거나 큰 데이터는 이 저장소에 어울리지 않으니 별도의 DB나 Core Data를 활용하자.

값 기록하기

아래 예제는 age라는 키의 값을 27로 저장하는 예제다.

UserDefaults.standard.set(27, forKey: "age")

데이터 타입에 따라 다양한 오버로드가 구현되어 있기 때문에 Swift의 기본 타입 데이터는 대부분 그대로 저장할 수 있다. 즉 위의 코드는 정수를 기록하는 메서드를 실행시킨다.

저장된 데이터는 앱이 종료되어도 계속 파일 시스템에 기록되어서 남는다. 단 디스크에 기록되는 시점은 시스템 마음이다. 다만 늦어도 앱이 종료될 때에는 저장된다고 보면 될 것 같다.

값 읽어오기

읽을 때는 타입에 신경을 쓰는 편이 좋다. 아래 코드는 위에서 파일시스템에 저장한 age라는 키의 값을 읽어오는 예제다.

let age = UserDefaults.standard.integer(forKey: "age")!

위의 예에서 .integer라는 이름은 해당 키 값을 정수(integer)로 읽어온다는 의미다. 정확히는 옵셔널이기 때문에 값을 가져오기 위해 끝에 느낌표를 붙여놨다. 이렇게 각 타입을 읽어 들이는 전용 메서드들이 구현되어 있으니 적당한 것으로 찾아 쓰는 편이 편하다. 당연하게도 기록된 타입과 다른 타입으로 읽을 경우 nil이 반환되며 값이 읽어지지 않는다.

물론 아래처럼 캐스팅을 해서 읽어 들이는 것도 가능하긴 하다.

if let age = UserDefatuls.standard.object(forKey: "age") as? Int {
    ...
}

Objective-C에서 쓰는 방식과 비슷하다. 개인적으로는 캐스팅 방식은 코드가 복잡해 보이는 경향이 있어서 타입 전용 메서드를 사용하는 것을 추천한다.

기본값

앱이 가장 처음에 실행되었다면 당연히 원하는 키의 데이터를 찾을 수 없는데 이때 기본값을 수동으로 만들어 주려면 코드 일관성도 깨지고 상당히 귀찮다. 이럴 때 UserDefaults가 제공하는 register(defaults:) 메서드를 활용해서 각 키의 기본값을 작성해 줄 수 있다.

UserDefaults.standard.register(
    defaults: [
        "key1": true,
        "key2": 10,
        "key3": "value"
    ]
)

이 기본값은 다음과 같은 특징을 가진다.

  1. 실행 즉시 별다른 이상이 없다면 해당 키와 값이 메모리에 생성된다.
  2. 다만 해당 키의 값이 파일시스템에 기록되어 있다면 파일시스템의 값을 읽어서 세팅한다.
  3. 별도의 set을 하지 않으면 기본값은 파일시스템에 기록되지 않는다.

즉 이 기본값들은 메모리상에만 저장되기 때문에 별도로 값을 쓰지(set) 않으면 당연히 앱이 종료되면 사라진다 점에 주의해야 한다는 말이다. 따라서 register(defaults:) 코드는 앱 시작 시 항상 실행되게 작성해 놓아야 아마도 원하는 용도로 사용할 수 있을 것이다.

반응형

synchronize()

결론부터 말하자면 이 메서드는 잊어도 된다.

과거에는 값을 저장한 뒤에는 이 메서드를 호출하는 편이 안전했다. 파일 시스템과 메모리의 내용을 동기화하는 커맨드이기 때문이다.

UserDefaults.standard.synchronize()

이 메서드가 호출되면 UserDefaults의 모든 데이터가 즉시 파일시스템에 기록되었다. 이 동기화를 빼먹을 경우 간혹 데이터를 잃어버리는 경우도 드물게 있었기 때문에 개인적으로는 이 코드를 항상 썼었다.

하지만 요즘은 쓸 필요가 없이 모두 자동으로 필요할 때 값이 저장된다. 오히려 공식 레퍼런스 매뉴얼에서는 사용하지 않는 것을 추천할 정도니 말이다.

기타

값을 읽어올 때 혹시나 매번 파일시스템에서 읽어오느라 퍼포먼스가 저하되지 않을까 걱정하는 사람이 있을 수 있다. 물론 나처럼 이상한 것에서 걱정을 많이 하는 사람만 그럴지도 모르겠지만 말이다.

하여간 이 걱정은 할 필요가 없다. 모든 데이터는 기본적으로 메모리에 캐시가 되기 때문에 값을 계속 읽어도 I/O 부하가 생기거나 하지는 않는다.

728x90
반응형

댓글