iOS 공부하는 감자

iOS) UserDefaults 본문

iOS

iOS) UserDefaults

DongTaTo 2022. 7. 16. 11:12
반응형

UserDefaults란?

iOS 앱에서 데이터를 영구적으로 보관하기 위해서는 다음과 같은 다양한 방법이 있다.

  1. 서버
  2. CoreData
  3. UserDefaults
  4. KeyChain

 

그중 UserDefaults는 앱이 실행되는 동안(런타임) Key-Value 형태로 데이터를 저장하는 사용자의 기본 데이터베이스에 대한 인터페이스다.

 

UserDefaults에 저장된 데이터는 앱이 종료되더라도 사라지지 않고, 영구적으로 저장된다.

단, UserDefaults의 데이터는 앱 Sandbox에 저장되므로 앱 자체가 삭제된다면 데이터도 같이 사라진다.

 

따라서 앱의 삭제 유무와 관계없이 데이터를 저장하기 위해서는 앱 내에서 백업/복구 기능을 지원하거나 KeyChain, iCloud 동기화 등의 기능을 추가하여 데이터를 유지시키기도 한다.

 

 


 

UserDefaults의 저장 위치

iOS 앱이 설치되면 앱이 실행되는 시점에 데이터를 저장할 수 있는 기본 데이터베이스가 생성된다.

 

기본 데이터베이스는 Property List를 기반으로 .plist 확장자 파일에 xml 형식으로 저장되며, Sandbox 내부에 저장된다.

정확한 위치는 : 홈 디렉토리 > Library > Preferences > .plist 이다.

 

기본 데이터베이스 파일이 앱 Sandbox 내부에 저장되기 때문에, 앱을 종료하더라도 데이터가 영구히 저장되는 것이다..!

 

UserDefaults에 저장되는 데이터는 사용자 기기의 저장공간 중 앱의 "문서 및 데이터" 영역을 차지하므로,

대용량의 데이터를 저장하기보다 다음과 같은 가벼운 단일 데이터 값을 저장하는게 좋다.

  • 인증 토큰 정보 (보다 안전한 KeyChain에 저장하는게 권장되긴 함)
  • 자동 로그인 여부
  • 알림 수신 여부
  • 팝업창 띄우기 여부
  • 앱 테마 설정 .. 등등

 

 


 

 

UserDefaults 사용하기

UserDefaults는 싱글톤 패턴으로 설계되어 있으며, 개발자는 standard 프로퍼티를 통해 전역 인스턴스를 반환받아서 사용할 수 있다.

 

 

 

1. 데이터 저장하기

Set() 메서드를 사용한다.

String, Double, Int 등 value 매개변수에 다양한 타입이 있지만, 데이터를 저장할 때에는 저장 가능한 타입 형식이라면 어떤 값을 입력해도 오류가 발생하지 않는다.

ex) 메서드는 Double을 매개변수로 입력하는 걸 선택하고, 문자열을 매개변수로 입력해도 오류 발생 X

 

 

 

 

2. 저장된 데이터 가져오기

데이터를 저장할 때와는 다르게 가져올 데이터 타입을 명확하게 해야 한다.

아래 사진처럼 데이터를 가져오는 메서드의 이름은 해당 메서드의 반환값 타입과 동일하다.

ex) Double타입의 데이터를 찾아온다면 메서드 이름이 double()

 

그리고 어떤 타입인지에 따라 반환값이 Optional Type이거나 아닌 경우가 있다.

사용자가 입력한 Key값에 대응하는 Value가 없을 수 있으므로 반환값이 Optoinal이며, 만약 Optoinal이 아닌 경우 반환 기본값을 가진다.

ex) Integer, Double : 0 / Bool : false

 

 

 

 

 

3. 특정 데이터 삭제하기

removeObject() 메서드에 삭제를 원하는 데이터 Key값을 입력하여 데이터를 삭제할 수 있다.

UserDefaults.standard.removeObject(forKey: "someKey")

 

 

 

 

4. Key값을 열거형으로 저장해서 사용하기

UserDefaults의 Key값은 문자열로 되어 있어서, 오타가 발생할 경우 데이터를 잘못 저장하거나 가져오지 못하는 문제가 발생한다.

이런 문제를 방지하기 위해 사용할 Key값을 미리 열거형으로 구현하여 사용하면 오타로 인한 실수를 방지할 수 있다.

enum UserDefaultsKey: String {
    case myKey
    case yourKey
    case sesacKey
}


UserDefaults.standard.set("저장할 데이터", forKey: UserDefaultsKey.myKey.rawValue)

 

Key값을 열거형으로 저장하면 다음과 같이 간편하게 모든 UserDefaults값을 초기화 시킬 수 있다.

UserDefaultsKey.allCases.forEach { UserDefaults.standard.removeObject(forKey: $0.rawValue) }

 

 

 

 

5. 싱글톤 인스턴스를 특정 상수에 담아서 사용할 수 있다.

UserDefaults를 사용할 때마다 UserDefaults.standard ... 이렇게 작성하면 좀 귀찮을(?) 수 있다.

만약 UserDefaults를 많이 사용한다면 상수에 담아서 좀 더 간편하게 사용할 수 있다.

let myUserDefaults = UserDefaults.standard

myUserDefaults.set("저장할 데이터", forKey: "Key")

 

 

 

 

 


 

 

사용자 정의 타입 저장하기

UserDefaults는 Base64 인코딩 형식의 Data 형을 따르기 때문에 저장할 수 있는 데이터는 Base 64 인코딩 형식을 거쳐야 한다.

기본 데이터 타입인 String, Int, Bool 등은 UserDefaults를 사용할 때 내부적으로 해당 인코딩 형식이 적용되지만, class, struct 같은 사용자 정의 타입은 직접 변환해서 저장해야 한다.

 

 

JSONEncoder / Decoder 사용하기

1) 사용할 Encoder, Decoder 인스턴스 생성

let encoder = JSONEncoder()

let decoder = JSONDecoder()

 

 

2) 저장을 원하는 타입에 Codable 프로토콜을 채택한다.

// UserDefaults로 저장할 사용자 정의 타입
struct Person: Codable {
    var name: String
    var age: Int
}

 

 

3) 저장할 인스턴스 생성 후, JSONEncoder를 사용하여 데이터를 저장한다.

let dong = Person(name: "dong", age: 25)

do {
    let encodedData = try encoder.encode(dong)
    UserDefaults.standard.set(encodedData, forKey: "myKey")
}catch {
    print("데이터 인코딩 실패")
}

 

 

4) JSONDecoder를 사용하여 데이터를 불러올 수 있다.

if let data = UserDefaults.standard.data(forKey: "myKey") {
    
    do {
        let decodedData = try decoder.decode(Person.self, from: data)
    }catch {
        print("데이터 디코딩 실패")
    }
    
}

 

 

 

 

 


 

 

UserDefaults는 Thread-Safe 하다.

UserDefaults는 하나의 기본 데이터베이스에 데이터를 저장하는 방법이기 때문에, 경쟁 조건이 발생할 가능성이 있다.

멀티 스레드 환경에서 하나의 데이터에 동시 접근하는 경우 데이터 무결성을 보장할 수 없기 때문에 데이터가 오류로 유실되거나 잘못 변경될 수도 있다.

 

다행히도 UserDefaults는 내부적으로 Thread-Safe 하게 설계되어 개발자가 이를 염두에 두고 개발하지 않아도 된다.

 

 

 

 


 

모든 UserDefaults 데이터 초기화하기

if let bundleID = Bundle.main.bundleIdentifier {
   UserDefaults.standard.removePersistentDomain(forName: bundleID)
}

 

UserDefualts에 reset 타입 메서드를 추가하여 사용할 수 있다.

extension UserDefaults {
    static func resetDefaults() {
        if let bundleID = Bundle.main.bundleIdentifier {
            UserDefaults.standard.removePersistentDomain(forName: bundleID)
        }
    }
}

 

 

 

반응형

'iOS' 카테고리의 다른 글

iOS) CollectionView - FlowLayout  (0) 2022.07.20
iOS) ATS (App Transport Security)  (0) 2022.07.20
iOS) Sandbox  (0) 2022.07.15
iOS) 라이브러리와 의존성 관리 도구  (0) 2022.07.14
iOS) App · ViewController의 생명주기  (0) 2022.07.13