소피it블로그

[Foundation] UserDefaults 정리 본문

개발_iOS/데이터 관리

[Foundation] UserDefaults 정리

sophie_l 2022. 8. 16. 16:51

https://developer.apple.com/documentation/foundation/userdefaults

 

Apple Developer Documentation

 

developer.apple.com

유저의 디폴트 데이터베이스의 인터페이스로, 앱의 론치를 넘어 지속되는 키-밸류 쌍이 저장됨

 

1. 선언

class UserDefaults : NSObject

2. 개요

 

유저디폴트 클래스는 디폴트 시스템과 상호작용하는 프로그램상의 인터페이스를 제공한다. 디폴트 시스템은 앱이 유저의 선호에 맞춰 커스텀될 수 있도록 한다. 예를 들어 앱은 유저들이 선호하는 단위나 미디어 재생 속도 등을 선택하게 할 수 있다. 앱은 이러한 선호들의 값에 매개변수를 부여하여 유저의 디폴트 데이터베이스에 저장한다. 이 매개변수들은 보통 앱의 디폴트 상태를 결정하거나 디폴트 행동을 시작하는데 사용되기 때문에 defaults라고 불린다.

앱이 실행될 때 유저디폴트 객체는 앱이 유저의 디폴트 데이터베이스에서 사용하는 디폴트값들을 읽어오는데 사용된다. 유저디폴트는 디폴트값이 필요할 때마다 유저의 디폴트 데이터베이스를 열어볼 필요가 없도록 해당 정보들을 저장한다. 디폴트값을 설정하면 이는 프로세스 중에는 동기적으로 변경되며, 지속적인 저장이나 다른 프로세스에는 비동기적이 된다.

교육 기관에서 관리되는 장치들을 제외하고는 유저의 디폴트값들은 각 장치 내부에 저장되며 백업과 회복을 위해 지속된다.

 

3. 디폴트 객체들 저장하기

 

유저디폴트 클래스는 float, double, integer, Boolean, URL 등의 자주 사용되는 타입들에 접근하는 편리한 방법을 제공한다.

디폴트 객체는 반드시 프라퍼티 리스트여야 한다. 즉, NSData, NSString, NSNumber, NSDate, NSArray, NSDictionary의 인스턴스(콜렉션 타입의 경우에는 인스턴스들의 집합)여야 한다. 다른 타입의 객체를 저장하고 싶으면 보통 아카이브를 하여 NSData의 인스턴스를 생성한다.

유저디폴트가 리턴하는 값들은 설령 mutable 객체가 값으로 설정되어 있다고 해도 변경될 수 없다(immutable). 예를 들어 "MyStringDefault"의 값을 mutable 문자열로 설정한다고 해도 후에 string(forKey:)메서드를 사용하여 불러오는 문자열은 immutable하다. 만일 디폴트값으로 mutable 문자열을 설정하고 후에 해당 문자열을 변경한다면, 디폴트값은 set(_:forKey:)를 다시 불러오지 않는 이상 변경된 문자열 값을 반영하지 않을 것이다.

 

4. 파일 references 지속하기

 

파일 URL은 파일 시스템에서의 위치를 구체화한다. 특정 파일의 위치를 저장하기 위해 set(_:forKey:) 메서드를 사용했는데 유저가 해당 파일을 옮긴다면, 앱은 다음 번 론치에서 해당 파일을 찾지 못할 것이다. 파일 시스템 아이덴티티를 통해 파일의 레퍼런스를 저장하기 위해서는 bookmarkData(options:incluingResourceValuesForKeys:relativeTo:) 메서드를 사용하여 NSURL 북마크를 생성하고 set(_:forKey:) 메서드를 통해 저장하면 된다. 

 

5. 디폴트 변경에 응답하기

 

특정 디폴트 값의 변경을 응답받으려면 key-value observing을 사용하면 된다. 또한 모든 로컬 디폴트 데이터베이스의 변경 사항을 알기 위해서는 default notification center에서 didChangeNotification에 대한 옵저버를 등록할 수도 있다.

 

6. 관리되는 환경에서 디폴트 사용하기

 

앱이 managed environments를 지원한다면, 관리자가 유저디폴트를 사용해 유저들의 선호를 결정하게 할 수 있다. 컴퓨터 랩이나 교실과 같이 관리되는 환경에서는 관리자나 선생님이 유저들을 위해 디폴트 선호의 집합을 설정해둠으로써 시스템을 구성할 수 있다. 만약 선호가 이런 방식으로 관리된다면, 앱은 제어를 비활성화하거나 숨김으로써 유저들이 기본 선호를 변경하지 못하게 해야 한다.

교육기관이 관리하는 디바이스에서 실행되는 앱은 유저의 다른 디바이스에서의 인스턴스와 작은 데이터를 주고받기 위해 iCloud key-value 저장을 사용할 수 있다. 예를 들어 교과서 앱은 유저가 현재 읽고 있는 페이지의 정보를 저장함으로써 앱의 다른 인스턴스들이 새로 론치되었을 때 해당 페이지를 열도록 할 수 있다.

 

7. Sandbox 고려사항

 

샌드박스된 앱은 다음과 같은 예외적인 경우를 빼고는 다른 앱의 선호에 접근하거나 수정할 수 없다.

 

  • macOS와 iOS의 앱 익스텐션
  • macOS에서의 애플리케이션 그룹에 있는 다른 앱

서드 파티 앱의 도메인이 addSuite(named:) 메서드를 사용하도록 추가한다고 해도 당신의 앱이 그 앱의 선호에 접근할 수 있는 권한을 부여받지는 못한다. 다른 앱의 선호에 접근하거나 이를 수정하려고 시도하면 에러가 나지는 않지만, macOS는 다른 앱의 선호 파일이 아닌 당신의 앱 컨테이너에 위치한 파일들을 읽고 쓰게 된다.

 

8. 스레드 안전

 

유저디폴트 클래스는 thread-safe 하다.

 

9. standard 유저 디폴트 객체 가져오기

// Returns the shared defaults object.
class var standard: UserDefaults

여기서 standard는 싱글턴 객체로 구현되어 있다.

 

10. 함수 목록 - 디폴트 값 세팅하기

// Sets the value of the specified default key.
func set(Any?, forKey: String)

// Sets the value of the specified default key to the specified float value.
func set(Float, forKey: String)

// Sets the value of the specified default key to the double value.
func set(Double, forKey: String)

// Sets the value of the specified default key to the specified integer value.
func set(Int, forKey: String)

// Sets the value of the specified default key to the specified Boolean value.
func set(Bool, forKey: String)

// Sets the value of the specified default key to the specified URL.
func set(URL?, forKey: String)

11. 함수 목록 - 디폴트 값 가져오기

// Returns the object associated with the specified key.
func object(forKey: String) -> Any?

// Returns the URL associated with the specified key.
func url(forKey: String) -> URL?

// Returns the array associated with the specified key.
func array(forKey: String) -> [Any]?

// Returns the dictionary object associated with the specified key.
func dictionary(forKey: String) -> [String : Any]?

// Returns the string associated with the specified key.
func string(forKey: String) -> String?

// Returns the array of strings associated with the specified key.
func stringArray(forKey: String) -> [String]?

// Returns the data object associated with the specified key.
func data(forKey: String) -> Data?

// Returns the Boolean value associated with the specified key.
func bool(forKey: String) -> Bool

// Returns the integer value associated with the specified key.
func integer(forKey: String) -> Int

// Returns the float value associated with the specified key.
func float(forKey: String) -> Float

// Returns the double value associated with the specified key.
func double(forKey: String) -> Double

// Returns a dictionary that contains a union of all key-value pairs in the domains in the search list.
func dictionaryRepresentation() -> [String : Any]

12. 기타

 

유저디폴트를 데이터베이스로 활용하면 안 된다. 유저디폴트는 아주 작은 데이터 하나에만 접근하려고 할 때도 디폴트로 plist에 저장된 전부를 불러오기 때문에 저장되는 데이터가 커지면 커질수록 앱에 부하가 온다. 따라서 유저의 선호와 관련된 작은 데이터를 저장할 때만 사용할 것.

또한, 유저디폴트는 이론적으로 Any 타입을 받기는 하지만 실제로는 스위프트 표준 데이터타입만 받기 때문에 커스텀 클래스나 구조체 등은 유저디폴트에 저장할 수 없다. 유저디폴트를 데이터베이스로 사용할 수 없는 또 다른 이유.