Lobster
Type-safe Firebase-RemoteConfig helper library.
Feature
- Can get a value from RemoteConfig / set a value to RemoteConfig to type-safe.
- Easy to set default value to RemoteConfig by using key-value subscripting.
- Custom type available ✨
String/IntenumDecodable(read-only) andCodable.
- Can manage expiration duration of config values.
- Combine framwork support.
Getting Started
- API Documentation
- Example Apps
Basic Usage
You can integrate Lobster in a few steps implementation:
1. Define ConfigKey
extension ConfigKeys {
static let welcomeTitle = ConfigKey<String>("welcome_title")
static let welcomeTitleColor = ConfigKey<UIColor>("welcome_title_color")
}
2. Register value to Firebase Project
Go to Firebase Project and set values you want to get.

3. Let’s use Lobster
import Lobster
// Set default value
Lobster.shared[default: .welcomeTitle] = "Welcome"
Lobster.shared[default: .welcomeTitleColor] = .black
self.titleLabel.text = Lobster.shared[.welcomeTitle]
// Fetch remote-config
Lobster.shared.fetch { _ in
dispatchQueue.main.async { [weak self] in
self?.titleLabel.text = Lobster.shared[.welcomeTitle]
self?.titleLabel.textColor = Lobster.shared[.welcomeTitleColor]
}
}
Tips for you
Combine
You can get values from Lobster with Combine’s stream.
Here is a sampl viewmodel class.
import Lobster
import Combine
extension ConfigKeys {
static let title = ConfigKey<String>("title")
}
final class ViewModel: ObservableObject {
@Published var title: String
private var cancellables: Set<AnyCancellable> = []
init() {
title = Lobster.shared[.titleText]
Lobster.shared.combine.fetched(.title)
.receive(on: RunLoop.main)
.assign(to: \.title, on: self)
.store(in: &cancellables)
}
}
NOTE: You need to install Lobster/Combine before using it.
Get value with subscripting syntax.
Use subscripting syntax.
- Non-Optional
extension ConfigKeys {
static let text = ConfigKey<String>("text")
}
// Get value from config.
// If value didn't fetch from remote yet. returns default value (if exists).
let text: String = Lobster.shared[.text]
// Get value from only config.
// it is possible to crash if value didn't fetch from remote yet.
let text: String = Lobster.shared[config: .text]
// Get value from only default.
// It is possible to crash if the default value is not set yet.
let text: String = Lobster.shared[default: .text]
// [safe:], [safeConfig:], [safeDefault:] subscripting syntax.
// It is safe because they return nil if they have no value.(return type is `Optional<T>`.)
let text: String? = Lobster.shared[safe: .text]
let text: String? = Lobster.shared[safeConfig: .text]
let text: String? = Lobster.shared[safeDefault: .text]
- Optional
extension ConfigKeys {
static let textOptional = ConfigKey<String?>("text_optional")
}
let text: String? = Lobster.shared[.textOptional]
let text: String? = Lobster.shared[config: .textOptional]
let text: String? = Lobster.shared[default: .textOptional]
Set Default value
You can set default values using subscripting syntax or plist.
// Set default value using `[default:]` syntax.
Lobster.shared[default: .titleText] = "Cart Items"
Lobster.shared[default: .titleColor] = .black
// or load from `defaults.plist`
Lobster.shared.setDefaults(fromPlist: "defaults")
Set debug mode
// Enable debug mode (development only)
Lobster.shared.debugMode = true
Lobster.shared.fetchExpirationDuration = 0.0
isStaled
If you set isStaled to true, Lobster will fetch remote value ignoring fetchExpirationDuration.
That is, You can retrieve config values immediately when you call fetch after You set isStales to true.
And isStaled will be set to false after fetched remote value.
Lobster.shared.fetchExpirationDuration = 60 * 12
Lobster.shared.isStaled = true
// Default expire duration is 12 hours.
// But if `isStaled` set to true,
// Lobster fetch values from remote ignoring expire duration.
Lobster.shared.fetch()
Supported types
Lobster supports more types as default followings:
- String
- Int
- Float
- Double
- Bool
- Data
- URL
- UIColor
- enum(String/Int)
- Decodable Object
- Codable Object
- Collection(Array)
- String
- Int
- Float
- Double
- Bool
- Data
- URL
- enum(String/Int)
- Decodable Object
- Codable Object
TODO
- [ ] CGPoint
- [ ] CGSize
- [ ] CGRect
- [ ] Dictionary
URL
Supports text:

UIColor
Supports only HEX string like "#FF00FF".

Enum
supports Int or String rawValue.
It can be used only by adapting ConfigSerializable.
If you want to use other enum, see Use custom value.
Decodable compliant type
read only
Codable compliant type
can set default value / read config value
Advanced Usage
You can easily get/set a value of custom type.
If you want to get/set ValueType (It’s a custom type that Lobster doesn’t support), you need to implement these steps:
- Conform
ConfigSerializableto theValueType - Create `ConfigBridge
- Define
ConfigKey<ValueType>
Example case 1: Enum
// Adapt protocol `ConfigSerializable`
enum Status: ConfigSerializable {
// Define `_config`, `_configArray`(If needed).
// Custom ConfigBridge's definition see below.
static var _config: ConfigBridge<Status> { return ConfigStatusBridge() }
static var _configArray: ConfigBridge<[Status]> { fatalError("Not implemented") }
case unknown
case active
case inactive
init(value: String?) {
guard let value = value else {
self = .unknown
return
}
switch value {
case "active": self = .active
case "inactive": self = .inactive
default: self = .unknown
}
}
var value: String {
switch self {
case .active: return "active"
case .inactive: return "inactive"
default: return ""
}
}
}
// Define Bridge class
final class ConfigStatusBridge: ConfigBridge<Status> {
typealias T = Status
// Save value to default store
override func save(key: String, value: T?, defaultsStore: DefaultsStore) {
defaultsStore[key] = value?.value
}
// Get value from RemoteConfig
override func get(key: String, remoteConfig: RemoteConfig) -> T? {
return remoteConfig[key].stringValue.flatMap(Status.init(value:))
}
// Get value from default store
override func get(key: String, defaultsStore: DefaultsStore) -> T? {
return (defaultsStore[key] as? String).flatMap(Status.init(value:))
}
}
// Define ConfigKey
extension ConfigKeys {
static let status = ConfigKey<Status>
}
// Set default
Lobster.shared[default: .status] = .inactive
// Use value
Lobster.shared.fetch { _ in
let currentStatus = Lobster.shared[.status]
}
To define subscript makes it possible to access custom enum.
Example Case 2: Decodable compliant type
Just adapt Decodable or Codable to class or struct and adapt ConfigSerializable
struct Person: Codable, ConfigSerializable {
let name: String
let age: Int
let country: String
}
extension ConfigKeys {
static let person = CodableConfigKey<Person>("person")
}
Define config value like below in console:

Requirements
- iOS 11.0+
- Xcode 10+
- Swift 5.0
Installation
CocoaPods
Lobster is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'Lobster', '~> 3.1.0'
# If you want to use extensions of Combine, please install below:
pod 'Lobster/Combine'
and run pod install
Development
- 1: setup project
$ cd path/to/Lobster
$ make
- 2: prepare
GoogleService-Info.plist
Due to security issues, I’m not providing GoogleService-Info.plist file.
So please prepare it yourself in your Firebase Project.
And Please make Firebase App’s bundle identifier -.test.LobsterTests.
After that, put it into LobsterTests/.

Communication
- If you found a bug, open an issue.
- If you have a feature request, open an issue.
- If you want to contribute, submit a pull request.:muscle:
License
Lobster is under MIT license. See the LICENSE file for more info.
View on GitHub
Lobster Reference