Merge pull request #163 from TouchInstinct/feature/user_defaults_codable
Feature/user defaults codable
This commit is contained in:
commit
03701b4d82
|
|
@ -1,5 +1,8 @@
|
|||
# Changelog
|
||||
|
||||
### 0.8.12
|
||||
- **Add**: `UserDefaults+Codable` is back. Now with generic subscript support.
|
||||
|
||||
### 0.8.11
|
||||
- **Change**: `NumberFormattingService.computedFormatters` computed var reverted to static.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "LeadKit"
|
||||
s.version = "0.8.11"
|
||||
s.version = "0.8.12"
|
||||
s.summary = "iOS framework with a bunch of tools for rapid development"
|
||||
s.homepage = "https://github.com/TouchInstinct/LeadKit"
|
||||
s.license = "Apache License, Version 2.0"
|
||||
|
|
|
|||
|
|
@ -321,6 +321,13 @@
|
|||
67274790206CD88600725163 /* DateFormattingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6727478E206CD88600725163 /* DateFormattingService.swift */; };
|
||||
67274791206CD88600725163 /* DateFormattingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6727478E206CD88600725163 /* DateFormattingService.swift */; };
|
||||
67274792206CD88600725163 /* DateFormattingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6727478E206CD88600725163 /* DateFormattingService.swift */; };
|
||||
6732F23F214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6732F23E214C09F900B446F2 /* UserDefaults+Codable.swift */; };
|
||||
6732F240214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6732F23E214C09F900B446F2 /* UserDefaults+Codable.swift */; };
|
||||
6732F241214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6732F23E214C09F900B446F2 /* UserDefaults+Codable.swift */; };
|
||||
6732F242214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6732F23E214C09F900B446F2 /* UserDefaults+Codable.swift */; };
|
||||
6732F243214C189000B446F2 /* Single+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */; };
|
||||
6732F244214C189100B446F2 /* Single+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */; };
|
||||
6732F245214C189100B446F2 /* Single+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */; };
|
||||
673564F12068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673564F02068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift */; };
|
||||
673564F22068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673564F02068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift */; };
|
||||
673564F32068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673564F02068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift */; };
|
||||
|
|
@ -856,6 +863,7 @@
|
|||
6727477E206CD3BD00725163 /* ViewText+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewText+Extensions.swift"; sourceTree = "<group>"; };
|
||||
67274789206CD83600725163 /* DateFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormat.swift; sourceTree = "<group>"; };
|
||||
6727478E206CD88600725163 /* DateFormattingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormattingService.swift; sourceTree = "<group>"; };
|
||||
6732F23E214C09F900B446F2 /* UserDefaults+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Codable.swift"; sourceTree = "<group>"; };
|
||||
673564F02068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NumberFormattingService+DefaultImplementation.swift"; sourceTree = "<group>"; };
|
||||
673564F52068C68D00F0CBED /* NumberFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberFormat.swift; sourceTree = "<group>"; };
|
||||
6737CFA2207220960063E056 /* SeparatorConfiguration+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SeparatorConfiguration+Extensions.swift"; sourceTree = "<group>"; };
|
||||
|
|
@ -1150,6 +1158,7 @@
|
|||
671461DA1EB3396E00EAB194 /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6732F23C214C09DF00B446F2 /* Foundation */,
|
||||
671461DB1EB3396E00EAB194 /* Alamofire */,
|
||||
EFBE57CE1EC35ED90040E00A /* Array */,
|
||||
67A1FF921EBCA64A00D6C89F /* CABasicAnimation */,
|
||||
|
|
@ -1592,6 +1601,22 @@
|
|||
path = UIImage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6732F23C214C09DF00B446F2 /* Foundation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6732F23D214C09E900B446F2 /* UserDefaults */,
|
||||
);
|
||||
path = Foundation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6732F23D214C09E900B446F2 /* UserDefaults */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6732F23E214C09F900B446F2 /* UserDefaults+Codable.swift */,
|
||||
);
|
||||
path = UserDefaults;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
673564EF2068C29100F0CBED /* NumberFormattingService */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -3109,6 +3134,7 @@
|
|||
677452A9206263360024EEEF /* CursorType+RxDataSourceDefaultImplementation.swift in Sources */,
|
||||
677B06B221186C14006C947D /* Completable+DeferredJust.swift in Sources */,
|
||||
671462501EB3396E00EAB194 /* StaticCursor.swift in Sources */,
|
||||
6732F23F214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */,
|
||||
67990AE6213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */,
|
||||
6741C40F20EAC88800418D08 /* GeneralDataLoadingViewModel+Extensions.swift in Sources */,
|
||||
67EB7FC7206148D000BDD9FB /* TotalCountCursorListingResult.swift in Sources */,
|
||||
|
|
@ -3171,6 +3197,7 @@
|
|||
671463621EB3396E00EAB194 /* SupportProtocol.swift in Sources */,
|
||||
678D26A220692BFF00B05B93 /* TextFieldViewEvents.swift in Sources */,
|
||||
671462861EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */,
|
||||
6732F244214C189100B446F2 /* Single+DeferredJust.swift in Sources */,
|
||||
6774527B206252020024EEEF /* DataLoadingState.swift in Sources */,
|
||||
67E3525D2119B5A50035BDDB /* BaseTextAttributes.swift in Sources */,
|
||||
6714634E1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */,
|
||||
|
|
@ -3238,6 +3265,7 @@
|
|||
67386A8E206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */,
|
||||
671462961EB3396E00EAB194 /* CGSize+CGContextSize.swift in Sources */,
|
||||
671463661EB3396E00EAB194 /* ViewHeightProtocol.swift in Sources */,
|
||||
6732F241214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */,
|
||||
67EB7FD120615B8900BDD9FB /* TotalCountCursorConfiguration.swift in Sources */,
|
||||
678D267B20691D8200B05B93 /* DataModelFieldBinding.swift in Sources */,
|
||||
673CF40D2063AB7C00C329F6 /* GeneralDataLoadingViewModel.swift in Sources */,
|
||||
|
|
@ -3387,6 +3415,7 @@
|
|||
B84CB06B20B702260090DB91 /* Encodable+Extensions.swift in Sources */,
|
||||
671462731EB3396E00EAB194 /* CursorError.swift in Sources */,
|
||||
6741CED020E243F800FEC4D9 /* BaseCustomViewController.swift in Sources */,
|
||||
6732F242214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */,
|
||||
677B06B521186C14006C947D /* Completable+DeferredJust.swift in Sources */,
|
||||
6727478D206CD83600725163 /* DateFormat.swift in Sources */,
|
||||
67EB7FDD20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */,
|
||||
|
|
@ -3424,6 +3453,7 @@
|
|||
6774529520625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */,
|
||||
6713C23A20AF0C4D00875921 /* NetworkOperationState.swift in Sources */,
|
||||
6774529D20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */,
|
||||
6732F245214C189100B446F2 /* Single+DeferredJust.swift in Sources */,
|
||||
6714632F1EB3396E00EAB194 /* ConfigurableController.swift in Sources */,
|
||||
67990ACD213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */,
|
||||
67EB7FF42061682F00BDD9FB /* TotalCountCursorListingResult+DefaultTotalCountCursorListingResult.swift in Sources */,
|
||||
|
|
@ -3505,6 +3535,7 @@
|
|||
671463111EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */,
|
||||
67153E41207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */,
|
||||
67990AE7213EB4080040D195 /* ConfigurableView+Extensions.swift in Sources */,
|
||||
6732F240214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */,
|
||||
671462911EB3396E00EAB194 /* CGImage+Crop.swift in Sources */,
|
||||
6760DC4E212F351700020BAE /* UIView+AddSubviews.swift in Sources */,
|
||||
67E902582125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */,
|
||||
|
|
@ -3638,6 +3669,7 @@
|
|||
67990ACB213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */,
|
||||
EFBE57D11EC35EF20040E00A /* Array+Extensions.swift in Sources */,
|
||||
676B22A3206A626D002E9F8A /* NSAttributedString+Extensions.swift in Sources */,
|
||||
6732F243214C189000B446F2 /* Single+DeferredJust.swift in Sources */,
|
||||
671462D91EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */,
|
||||
3622F5DD20E253F1009DED94 /* TableDirector+Extensions.swift in Sources */,
|
||||
6714638D1EB3396E00EAB194 /* SolidFillDrawingOperation.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ PODS:
|
|||
- RxCocoa (4.2.0):
|
||||
- RxSwift (~> 4.0)
|
||||
- RxSwift (4.2.0)
|
||||
- SwiftDate (5.0.4)
|
||||
- SwiftLint (0.26.0)
|
||||
- SwiftDate (5.0.7)
|
||||
- SwiftLint (0.27.0)
|
||||
- TableKit (2.7.0)
|
||||
- UIScrollView-InfiniteScroll (1.1.0)
|
||||
|
||||
|
|
@ -38,8 +38,8 @@ SPEC CHECKSUMS:
|
|||
RxAlamofire: 87a9c588541210cc3e4a1f843ccc3ecf3eb98b31
|
||||
RxCocoa: 0b54909c902e1e581212a03e690bbd94032d8baa
|
||||
RxSwift: 99e10317ddfcc7fbe01356aafd118fde4a0be104
|
||||
SwiftDate: d9827f0e7edfeb8be52882beb67e75c773b634c3
|
||||
SwiftLint: f6b83e8d95ee1e91e11932d843af4fdcbf3fc764
|
||||
SwiftDate: f053fb89250c59af5eff777f3b832d2b9dd57403
|
||||
SwiftLint: 3207c1faa2240bf8973b191820a116113cd11073
|
||||
TableKit: 506650573ed96ec007649b655559ecd43f9fd505
|
||||
UIScrollView-InfiniteScroll: 3ef456bcbe759c19f510a383cff96e6647c98c98
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
import RxSwift
|
||||
|
||||
public enum UserDefaultsError: Error {
|
||||
|
||||
case noSuchValue(key: String)
|
||||
case unableToDecode(decodingError: Error)
|
||||
|
||||
}
|
||||
|
||||
public extension UserDefaults {
|
||||
|
||||
/// Returns the object with specified type associated with the first occurrence of the specified default.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - key: A key in the current user's defaults database.
|
||||
/// - decoder: JSON decoder to decode stored data.
|
||||
/// - Returns: The object with specified type associated with the specified key,
|
||||
/// or throw exception if the key was not found.
|
||||
/// - Throws: One of cases in UserDefaultsError
|
||||
func object<T: Decodable>(forKey key: String, decoder: JSONDecoder = JSONDecoder()) throws -> T {
|
||||
guard let storedData = data(forKey: key) else {
|
||||
throw UserDefaultsError.noSuchValue(key: key)
|
||||
}
|
||||
|
||||
do {
|
||||
return try decoder.decode(T.self, from: storedData)
|
||||
} catch {
|
||||
throw UserDefaultsError.unableToDecode(decodingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the object with specified type associated with the first occurrence of the specified default.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - key: A key in the current user's defaults database.
|
||||
/// - defaultValue: A default value which will be used if there is no such value for specified key,
|
||||
/// or if error occurred during mapping
|
||||
/// - decoder: JSON decoder to decode stored data.
|
||||
/// - Returns: The object with specified type associated with the specified key, or passed default value
|
||||
/// if there is no such value for specified key or if error occurred during mapping.
|
||||
func object<T: Decodable>(forKey key: String, defaultValue: T, decoder: JSONDecoder = JSONDecoder()) -> T {
|
||||
return (try? object(forKey: key, decoder: decoder)) ?? defaultValue
|
||||
}
|
||||
|
||||
/// Set or remove the value of the specified default key in the standard application domain.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - object: The object with specified type to store or nil to remove it from the defaults database.
|
||||
/// - key: The key with which to associate with the value.
|
||||
/// - encoder: JSON encoder to encode to encode passed object.
|
||||
/// - Throws: EncodingError if error is occured during passed object encoding.
|
||||
func set<T: Encodable>(object: T?, forKey key: String, encoder: JSONEncoder = JSONEncoder()) throws {
|
||||
if let object = object {
|
||||
set(try encoder.encode(object), forKey: key)
|
||||
} else {
|
||||
set(nil, forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
subscript<T: Codable>(key: String) -> T? {
|
||||
get {
|
||||
return try? object(forKey: key)
|
||||
}
|
||||
set {
|
||||
try? set(object: newValue, forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension Reactive where Base: UserDefaults {
|
||||
|
||||
/// Reactive version of object<T>(forKey:decoder:) -> T.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - key: A key in the current user's defaults database.
|
||||
/// - decoder: JSON decoder to decode stored data.
|
||||
/// - Returns: Single of specified model type.
|
||||
func object<T: Decodable>(forKey key: String, decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
|
||||
return .deferredJust { try self.base.object(forKey: key, decoder: decoder) }
|
||||
}
|
||||
|
||||
/// Reactive version of object<T>(forKey:defaultValue:decoder:) -> T.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - key: A key in the current user's defaults database.
|
||||
/// - defaultValue: A default value which will be used if there is no such value for specified key,
|
||||
/// or if error occurred during mapping
|
||||
/// - decoder: JSON decoder to decode stored data.
|
||||
/// - Returns: Single of specified model type.
|
||||
func object<T: Decodable>(forKey key: String, defaultValue: T, decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
|
||||
return .deferredJust { self.base.object(forKey: key, defaultValue: defaultValue, decoder: decoder) }
|
||||
}
|
||||
|
||||
/// Reactive version of set<T>(object:forKey:encoder:).
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - object: The object with specified type to store in the defaults database.
|
||||
/// - key: The key with which to associate with the value.
|
||||
/// - encoder: JSON encoder to encode to encode passed object.
|
||||
/// - Returns: Completable.
|
||||
func set<T: Encodable>(object: T?, forKey key: String, encoder: JSONEncoder = JSONEncoder()) -> Completable {
|
||||
return .deferredJust {
|
||||
try self.base.set(object: object, forKey: key, encoder: encoder)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ public extension PrimitiveSequence where Trait == CompletableTrait {
|
|||
/// - Parameter workUnit: Element factory function to invoke for each observer
|
||||
/// that subscribes to the resulting sequence.
|
||||
/// - Returns: A single whose observers trigger an invocation of the given element factory function.
|
||||
static func deferredJust(_ workUnit: @escaping () throws -> Void) -> Completable {
|
||||
static func deferredJust(_ workUnit: @escaping ThrowableVoidBlock) -> Completable {
|
||||
return .create { observer in
|
||||
do {
|
||||
try workUnit()
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ public extension TableDirector {
|
|||
at indexPath: IndexPath,
|
||||
with animation: UITableViewRowAnimation,
|
||||
manualBeginEndUpdates: Bool = false) {
|
||||
|
||||
|
||||
sections[indexPath.section].insert(rows: rows, at: indexPath.row)
|
||||
let indexPaths: [IndexPath] = rows.indices.map {
|
||||
IndexPath(row: indexPath.row + $0, section: indexPath.section)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Closure that takes no arguments and return Void.
|
||||
public typealias VoidBlock = () -> Void
|
||||
|
||||
/// Closure that takes no arguments, may throw error and return Void.
|
||||
public typealias ThrowableVoidBlock = () throws -> Void
|
||||
|
|
|
|||
Loading…
Reference in New Issue