Skip to content

Instantly share code, notes, and snippets.

@imaizume
Last active February 18, 2021 06:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imaizume/3e6dd078e2551cda53c611a91e5da2ac to your computer and use it in GitHub Desktop.
Save imaizume/3e6dd078e2551cda53c611a91e5da2ac to your computer and use it in GitHub Desktop.
How to manage parameters for Firebase Remote Config in Swift easily.
// MARK:- definition
/// Constraint for Parameter Type Definition.
protocol ParameterProtocol {
/// Parameter name in Firebase console. e.g. "beta_test_1"
var name: String { get }
/// Default value to be set to Remote Config object.
var defaultValue: [String: NSObject] { get }
}
/// Parameters return bool value.
enum BoolParameter: String {
case betaTest1
case betaTest2
}
extension BoolParameter: ParameterProtocol {
var name: String { return self.rawValue }
var defaultValue: [String: NSObject] {
switch self {
case .betaTest1: // default false
return [self.rawValue: false as NSObject]
case .betaTest2: // default true
return [self.rawValue: true as NSObject]
}
}
}
/// Parameters return string value.
enum StringParameter: String {
case betaTestA
case betaTestB
}
extension StringParameter: ParameterProtocol {
var name: String { return self.rawValue }
var defaultValue: [String: NSObject] {
switch self {
case .betaTestA: // default ""
return [self.rawValue: "" as NSObject]
case .betaTestB: // default "test"
return [self.rawValue: "test" as NSObject]
}
}
}
/// Interface required to store object which returns bool value.
protocol BoolStoreProtocol {
func boolValue(for key: BoolParameter) -> Bool
}
/// Stub object which returns bool value.
class BoolStoreStub: BoolStoreProtocol {
func boolValue(for key: BoolParameter) -> Bool {
return false
}
}
/// Interface required to store object which returns string value.
protocol StringStoreProtocol {
func stringValue(for key: StringParameter) -> String?
}
/// Stub object which returns string value.
class StringStoreStub: StringStoreProtocol {
func stringValue(for key: StringParameter) -> String? {
return ""
}
}
/// Store object which returns value fetched from Firebase.
class FirebaseStore {}
extension FirebaseStore: BoolStoreProtocol {
func boolValue(for key: BoolParameter) -> Bool {
let remoteConfig = RemoteConfig.remoteConfig()
remoteConfig.setDefaults(key.defaultValue)
return remoteConfig[key.name].boolValue
}
}
extension FirebaseStore: StringStoreProtocol {
func stringValue(for key: StringParameter) -> String? {
let remoteConfig = RemoteConfig.remoteConfig()
remoteConfig.setDefaults(key.defaultValue)
return remoteConfig[key.name].stringValue
}
}
// MARK:- example
let boolStore: BoolStoreProtocol = FirebaseStore()
let boolStub: BoolStoreProtocol = BoolStoreStub()
let realBoolValue: Bool = boolStore.boolValue(for: .betaTest1)
let stubBoolValue: Bool = boolStub.boolValue(for: .betaTest1)
let stringStore: StringStoreProtocol = FirebaseStore()
let stringStub: StringStoreProtocol = StringStoreStub()
let realStringValue: String? = stringStore.stringValue(for: .betaTestA)
let stubStringValue: String? = stringStub.stringValue(for: .betaTestA)
/// Constraint for Parameter Type Definition.
protocol ParameterProtocol {
/// Type of value which parameter returns
associatedtype ValueType
/// Parameter name in Firebase console. e.g. "beta_test_1"
var name: String { get }
/// Default value to be set to Remote Config object.
func defaultValue() -> ValueType
}
enum BoolParameter: String {
case betaTest1
case betaTest2
}
extension BoolParameter: ParameterProtocol {
typealias ValueType = Bool
var name: String { return self.rawValue }
func defaultValue() -> Bool {
switch self {
case .betaTest1:
return false
case .betaTest2:
return true
}
}
}
enum StringParameter: String {
case betaTestA
case betaTestB
}
extension StringParameter: ParameterProtocol {
typealias ValueType = String
var name: String { return self.rawValue }
func defaultValue() -> String {
switch self {
case .betaTestA:
return ""
case .betaTestB:
return "test"
}
}
}
class AnyKindOfParameter<ValueType>: ParameterProtocol {
init<X: ParameterProtocol>(_ base: X) where X.ValueType == ValueType {
self.name = base.name
self._defaultValue = { base.defaultValue() }
}
private(set) var name: String
func defaultValue() -> ValueType {
return self._defaultValue()
}
private let _defaultValue: () -> ValueType
}
extension AnyKindOfParameter where ValueType == Bool {
convenience init(_ base: BoolParameter) { self.init(base) }
}
extension AnyKindOfParameter where ValueType == String {
convenience init(_ base: StringParameter) { self.init(base) }
}
protocol StoreProtocol {
associatedtype ValueType
func getValue(for parameter: AnyKindOfParameter<ValueType>) -> ValueType
}
protocol BoolStoreProtocol {
func getValue(for parameter: AnyKindOfParameter<Bool>) -> Bool
}
protocol StringStoreProtocol {
func getValue(for parameter: AnyKindOfParameter<String>) -> String
}
class BoolStore {}
extension BoolStore: StoreProtocol, BoolStoreProtocol {
typealias ValueType = Bool
func getValue(for parameter: AnyKindOfParameter<Bool>) -> Bool {
let remoteConfig = RemoteConfig.remoteConfig()
remoteConfig.setDefaults([parameter.name: parameter.defaultValue() as NSObject])
return remoteConfig[parameter.name].boolValue
}
}
class BoolStub {}
extension BoolStub: StoreProtocol, BoolStoreProtocol {
func getValue(for parameter: AnyKindOfParameter<Bool>) -> Bool {
guard let param = parameter as? BoolParameter else { return false }
switch param {
case .betaTest1:
return true
case .betaTest2:
return false
}
}
}
let x: BoolStoreProtocol = BoolStore()
let y: BoolStoreProtocol = BoolStub()
let a: Bool = x.getValue(for: .init(.betaTest1))
let b: Bool = y.getValue(for: .init(.betaTest1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment