애플사이다의 iOS 개발 일지

[UserDefaults] object(forKey:) 및 bool(forKey:), string(forKey:)의 차이점은? 본문

iOS/영문 공식문서 뜯어보기-iOS

[UserDefaults] object(forKey:) 및 bool(forKey:), string(forKey:)의 차이점은?

Applecider 2022. 11. 6. 07:00

UserDefaults 관련 코드를 보다가 UserDetaults.standard.string(forKey:) 메서드를 봤는데,

object(forKey:) 메서드와의 차이점이 궁금해서 검색해봤다.

UserDefaults, 기본적인 key-value pair와의 차이점에 대한 기본적인 설명은 생략했다.

 

UserDefaults 관련 메서드는 이렇게 다양한데,

저장값을 string, bool, integer, double 등 타입별로 구분하면 번거로우니까 

한 방에 퉁쳐서 저장할 수 있는 object를 쓰는 게 낫지 않을까? 하는 생각을 했다.

-> 결론적으로 아니었음

UserDefaults 관련 메서드


공식문서

우선 공식문서를 살펴봤다.

대표적인 메서드인 object(forKey:) / bool(forKey:) / string(forKey:) 3개만 살펴보자.

 

일단 API가 추가된 시점은 모두 iOS 2.0으로 동일하다.

보통 더 최근에 나온 걸 많이 쓰니까.. 꼼수 쓰기 실패

 

각 메서드의 반환타입을 살펴보자.

object 메서드는 옵셔널 타입 Any?,

bool 메서드는 none-옵셔널 타입 Bool,

string 메서드는 옵셔널 타입 String?

 

🤔 직관적으로 옵셔널 타입을 반환하는 object / string 메서드는 특정 key에 저장된 값이 없으면 nil을 반환,

none-옵셔널 타입을 반환하는 bool 메서드는 다른 방식일 것을 예상할 수 있다.

 

공식문서를 확인해보니 예상대로였다. 웬일로..?

저장값이 없는 경우, bool 메서드는 false를 반환하고, 

integer, double 메서드는 0을 반환한다.

 

또 신기한 점이 integer/double 메서드는 저장값이 true/false이면 각각 1/0을 반환한다. (반대로 bool 메서드로는 숫자값을 반환 불가)

직관적이지 않으므로 현업코드에서 실제로 사용할 것 같지는 않지만..


구글링 - bool 및 object 메서드의 차이점

공식문서를 봤으니 이제 구글링을 해보자.

- 검색 키워드 : when use userdefaults string(forKey:), how to store string in UserDefaults

 

CocoaCasts의 How to Check if a Value Exists in User Defaults in Swift 포스트가 유용했다.

 

bool(forKey:) 메서드는 특정 key에 저장된 값이 없거나, 저장된 값이 bool 타입이 아니면 false를 반환하므로

특정 key에 대한 값이 존재하는지 여부를 알고 싶을 때 적절하지 않다.

(반환값으로 false를 받았을 때, 이게 내가 저장한 값인지, 해당 key가 존재하지 않는지 구분이 불가하므로)

 

그래서 해결책으로 bool 메서드 쓰지 말고 object 메서드를 쓰라고 권한다.

object 메서드는 저장된 값이 없을 때 친절하게 nil을 반환해주기 때문이다.

예제 코드

이 아티클을 기반으로 예제 코드를 작성해봤다.

// 1️⃣ 저장
UserDefaults.standard.set(true, forKey: "KeyForBool")

// 2️⃣ 저장한 값 꺼내보기
let value = UserDefaults.standard.bool(forKey: "KeyForBool")
let value2 = UserDefaults.standard.object(forKey: "KeyForBool")
let typeCastedValue2 = value2 as? Bool

print(value)  // true
print(value2) // optional(1) <- ✅ true가 아님. Any? 타입이라서 type casting 필요함 
print(typeCastedValue2) // optional(true)

// 3️⃣ 저장하지 않은 값 꺼내보기
let invalidValue = UserDefaults.standard.bool(forKey: "InvalidKey")
let invalidValue2 = UserDefaults.standard.object(forKey: "InvalidKey")

print(invalidValue)  // false <- ✅ 주의. 저장된 key가 없으면 false 반환 (nil이 아니라서 혼동됨)
print(invalidValue2) // nil
  • KeyForBool 이라는 key에다가 bool 값을 저장했고, 해당 key로 저장된 값을 다시 꺼내봤다.
  • bool 메서드로 꺼내면 true가 반환되고, object로 꺼내면 Any? 타입이므로 optional(1)이 나온다.
    그래서 as? Bool로 타입캐스팅해야 optioanl(true)를 얻을 수 있다.
  • 유효하지 않은 key로 저장된 값을 꺼내보면,
    bool 메서드는 false를 반환하므로 주의해야 한다. 내가 저장한 값인지, 해당 key가 존재하지 않는지 구분이 불가하기 때문이다.
    object 메서드는 nil을 반환하므로 존재하지 않는 값임을 알 수 있다.

구글링 - string 및 object 메서드의 차이점

그럼 이제 bool은 봤으니까 string 메서드만 확인하면 된다.

동일한 블로그에서 이 질문에 대한 답도 얻을 수 있었다.

CocoaCasts의 How to Store a String In User Defaults In Swift 포스트를 참고

 

UserDefaults에 문자열 값을 저장하고, 다시 이 값을 꺼낼 때 string, object 둘 다 써도 된다.

그렇다면 어떤 상황에서 string / object 메서드를 쓰는 게 좋을까?

 

결론부터 말하면 string을 쓰는 게 좋다. 타입캐스팅이 필요 없고, 가독성이 좋기 때문이다.

- 본론: I'm sure you agree that the string(forKey:) method is the more elegant option and easier to read and understand.

예제 코드

// 1️⃣ 저장
UserDefaults.standard.set("저장할 문자열", forKey: "KeyForString")

// 2️⃣ 저장한 값 꺼내보기
let value3 = UserDefaults.standard.string(forKey: "KeyForString")
let value4 = UserDefaults.standard.object(forKey: "KeyForString")
let typeCastedValue4 = value4 as? String

print(value3)  // Optional("저장할 문자열")
print(value4)  // Optional(저장할 문자열) 
print(typeCastedValue4) // Optional("저장할 문자열")

// 3️⃣ 저장하지 않은 값 꺼내보기
let invalidValue3 = UserDefaults.standard.string(forKey: "InvalidKey")
let invalidValue4 = UserDefaults.standard.object(forKey: "InvalidKey")

print(invalidValue3) // nil ✅
print(invalidValue4) // nil ✅
  • 위에서 본 bool 메서드와 달리 string 메서드는 key에 저장된 값이 없으면 nil을 반환하므로 헷갈리지 않는다.

결론

결론적으로 UserDefaults 메서드 중에서 반환타입이 옵셔널인 메서드인 string, array, dictionary, url 등은 

가독성이 좋고, 타입캐스팅이 필요 없으므로 object 메서드 대신 사용하는 게 좋다.

 

반면 반환타입이 none-옵셔널인 메서드인 bool, integer, double 등은

key에 저장된 값이 없을 때 nil을 반환할 수 없어 혼동될 수 있으므로 object 메서드로 대체하는 것이 좋다.

 

- Reference

 

🍎 포스트가 도움이 되었다면, 공감🤍 / 구독🍹 / 공유🔗 / 댓글✏️ 로 응원해주세요. 감사합니다.

Comments