[iOS] UserDefaults와 SubScript의 운명적 만남

유인호·2024년 1월 22일
0

iOS

목록 보기
20/64

서론

SubScript를 공부하고나서 어떻게 활용해볼까 고민해보다가 UserDefaults에 활용하면 좋지 않을까 해서 한번 구성해봤음. UserDefaults가 사용하기 어려운건 아무래도 key를 개발자가 직접 String으로 넣어줘야 한다는것과 벨류를 뽑아낼때 string인지, bool인지 알아야 한다는점이겠다.

이를 조금더 쉽게 해결하기 위해 이런식으로 Extension을 구상해보았음.

구상

extension UserDefaults {
	enum UserDefaultsKeys: String, CaseIterable {
		case isFirstStart
		case userProfile
		case userNickname
		case searchHistory
		case likeList
	}

	subscript<T>(item: UserDefaultsKeys) -> T? {
		get {
			return UserDefaults.standard.value(forKey: item.rawValue) as? T
		} set {
			UserDefaults.standard.setValue(newValue, forKey: item.rawValue)
		}
	}
}

사용법

if let lists: [String] = UserDefaults.standard[.likeList] {
	print(lists)
}

단점

UserDefaults에 무엇이 저장될지 몰라서 제네릭을 이용해 타입을 받고 타입캐스팅을 통해 반환한다. 그러다보니 타입 캐스팅이 실패할때를 대비해 as? 연산자를 사용하다보니 if let같은 옵셔널 바인딩을 통해 해제를 해야한다.

해결?

오버로딩을 이용해서 옵셔널 바인딩을 사용하지 않고 UserDefaults를 사용할 수 있도록 고안해 보았다.

extension UserDefaults {
	enum UserDefaultsKeys: String, CaseIterable {
		case isFirstStart
		case userProfile
		case userNickname
		case searchHistory
		case likeList
	}

	subscript(item: UserDefaultsKeys) -> String {
		get {
			return UserDefaults.standard.string(forKey: item.rawValue) ?? ""
		} set {
			UserDefaults.standard.setValue(newValue, forKey: item.rawValue)
		}
	}

	subscript(item: UserDefaultsKeys) -> Bool {
		get {
			return UserDefaults.standard.bool(forKey: item.rawValue)
		} set {
			UserDefaults.standard.setValue(newValue, forKey: item.rawValue)
		}
	}

	subscript(item: UserDefaultsKeys) -> [String] {
		get {
			return UserDefaults.standard.array(forKey: item.rawValue) as! [String]
		} set {
			UserDefaults.standard.setValue(newValue, forKey: item.rawValue)
		}
	}
}

여기서 문제는 무엇이 저장되어있는지 실행시켜서 런타임 오류가 나봐야 문제를 알 수 있다는것. 휴먼에러를 방지하지 못한다.

extension UserDefaults {
	enum UserDefaultsStringKeys: String, CaseIterable {
		case userProfile
		case userNickname
	}

	enum UserDefaultsBoolKeys: String, CaseIterable {
		case isFirstStart
	}

	enum UserDefaultsArrayKeys: String, CaseIterable {
		case searchHistory
		case likeList
	}

	subscript(item: UserDefaultsStringKeys) -> String {
		get {
			return UserDefaults.standard.string(forKey: item.rawValue) ?? ""
		} set {
			UserDefaults.standard.setValue(newValue, forKey: item.rawValue)
		}
	}

	subscript(item: UserDefaultsBoolKeys) -> Bool {
		get {
			return UserDefaults.standard.bool(forKey: item.rawValue)
		} set {
			UserDefaults.standard.setValue(newValue, forKey: item.rawValue)
		}
	}

	subscript(item: UserDefaultsArrayKeys) -> [String] {
		get {
			return UserDefaults.standard.array(forKey: item.rawValue) as [String] ?? []
		} set {
			UserDefaults.standard.setValue(newValue, forKey: item.rawValue)
		}
	}
}

이런식으로 활용하게 된다면 옵셔널 바인딩의 문제와 휴먼에러를 방지할 수 있으면서 간단하게 사용할 수 있을 것이다.

다음편 [iOS] UserDefaults와 SubScript의 필연적 만남

profile
🍎Apple Developer Academy @ POSTECH 2nd, 🌱SeSAC iOS 4th

0개의 댓글