From 8c869942f87b6dbc0db20840b216d5e62ab7baaf Mon Sep 17 00:00:00 2001 From: TimFraedrich Date: Sun, 4 Oct 2020 15:09:14 +0000 Subject: [PATCH 01/27] Add DiskStorage size property --- Cache.xcodeproj/project.pbxproj | 16 +++++++++++++ .../Extensions/FileManager+Extensions.swift | 22 +++++++++++++++++ Source/Shared/Extensions/URL+Extensions.swift | 14 +++++++++++ Source/Shared/Storage/DiskStorage.swift | 24 ++++++++----------- Source/Shared/Storage/HybridStorage.swift | 7 ++++++ Source/Shared/Storage/Storage.swift | 7 ++++++ 6 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 Source/Shared/Extensions/FileManager+Extensions.swift create mode 100644 Source/Shared/Extensions/URL+Extensions.swift diff --git a/Cache.xcodeproj/project.pbxproj b/Cache.xcodeproj/project.pbxproj index 05475ed..6e1f740 100644 --- a/Cache.xcodeproj/project.pbxproj +++ b/Cache.xcodeproj/project.pbxproj @@ -11,6 +11,12 @@ 0E79164B250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E791649250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift */; }; 0E79164C250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E791649250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift */; }; 0E79164E250E2B0400A71666 /* Hasher+constantAccrossExecutions+Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79164D250E2B0400A71666 /* Hasher+constantAccrossExecutions+Tests.swift */; }; + 2292AB7B252A14520031F3B9 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2292AB7A252A14520031F3B9 /* URL+Extensions.swift */; }; + 2292AB7C252A14520031F3B9 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2292AB7A252A14520031F3B9 /* URL+Extensions.swift */; }; + 2292AB7D252A14520031F3B9 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2292AB7A252A14520031F3B9 /* URL+Extensions.swift */; }; + 2292AB85252A14F50031F3B9 /* FileManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2292AB84252A14F50031F3B9 /* FileManager+Extensions.swift */; }; + 2292AB86252A14F50031F3B9 /* FileManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2292AB84252A14F50031F3B9 /* FileManager+Extensions.swift */; }; + 2292AB87252A14F50031F3B9 /* FileManager+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2292AB84252A14F50031F3B9 /* FileManager+Extensions.swift */; }; BDEDD37D1DBCEB8A007416A6 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDEDD3561DBCE5B1007416A6 /* Cache.framework */; }; D21B667C1F6A723C00125DE1 /* DataSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF98531F694FFA00CE8F68 /* DataSerializer.swift */; }; D21B667E1F6A723C00125DE1 /* ExpirationMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF98551F694FFA00CE8F68 /* ExpirationMode.swift */; }; @@ -179,6 +185,8 @@ /* Begin PBXFileReference section */ 0E791649250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Hasher+constantAccrossExecutions.swift"; sourceTree = ""; }; 0E79164D250E2B0400A71666 /* Hasher+constantAccrossExecutions+Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Hasher+constantAccrossExecutions+Tests.swift"; sourceTree = ""; }; + 2292AB7A252A14520031F3B9 /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = ""; }; + 2292AB84252A14F50031F3B9 /* FileManager+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Extensions.swift"; sourceTree = ""; }; BDEDD3561DBCE5B1007416A6 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BDEDD3781DBCEB8A007416A6 /* Cache-tvOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Cache-tvOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D221E5BB20D00D9300BC940E /* MemoryStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryStorage.swift; sourceTree = ""; }; @@ -332,6 +340,8 @@ 0E791649250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift */, D28897041F8B79B300C61DEE /* JSONDecoder+Extensions.swift */, D2CF98501F694FFA00CE8F68 /* Date+Extensions.swift */, + 2292AB7A252A14520031F3B9 /* URL+Extensions.swift */, + 2292AB84252A14F50031F3B9 /* FileManager+Extensions.swift */, ); path = Extensions; sourceTree = ""; @@ -792,10 +802,12 @@ D2D4CC261FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */, D27014A720D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147E20D107DA003B45C7 /* SyncStorage.swift in Sources */, + 2292AB7D252A14520031F3B9 /* URL+Extensions.swift in Sources */, D292DAFF1F6A970B0060F614 /* Result.swift in Sources */, D21B669A1F6A724300125DE1 /* Date+Extensions.swift in Sources */, 0E79164C250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66891F6A723C00125DE1 /* ImageWrapper.swift in Sources */, + 2292AB87252A14F50031F3B9 /* FileManager+Extensions.swift in Sources */, D21B668B1F6A723C00125DE1 /* StorageError.swift in Sources */, D5A9D1B921134547005DBD3F /* ObservationToken.swift in Sources */, D270148A20D11040003B45C7 /* Storage+Transform.swift in Sources */, @@ -880,10 +892,12 @@ D2D4CC251FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */, D27014A620D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147D20D107DA003B45C7 /* SyncStorage.swift in Sources */, + 2292AB7C252A14520031F3B9 /* URL+Extensions.swift in Sources */, D292DAFE1F6A970B0060F614 /* Result.swift in Sources */, D21B66991F6A724200125DE1 /* Date+Extensions.swift in Sources */, 0E79164B250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66801F6A723C00125DE1 /* ImageWrapper.swift in Sources */, + 2292AB86252A14F50031F3B9 /* FileManager+Extensions.swift in Sources */, D21B66821F6A723C00125DE1 /* StorageError.swift in Sources */, D5A9D1B821134547005DBD3F /* ObservationToken.swift in Sources */, D270148920D11040003B45C7 /* Storage+Transform.swift in Sources */, @@ -934,10 +948,12 @@ D292DAFD1F6A970B0060F614 /* Result.swift in Sources */, D27014A520D129EB003B45C7 /* TransformerFactory.swift in Sources */, D2D4CC241FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */, + 2292AB7B252A14520031F3B9 /* URL+Extensions.swift in Sources */, D270147C20D107DA003B45C7 /* SyncStorage.swift in Sources */, D2CF98671F694FFA00CE8F68 /* Expiry.swift in Sources */, 0E79164A250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D270148820D11040003B45C7 /* Storage+Transform.swift in Sources */, + 2292AB85252A14F50031F3B9 /* FileManager+Extensions.swift in Sources */, D2CF986A1F694FFA00CE8F68 /* StorageError.swift in Sources */, D5A9D1B721134547005DBD3F /* ObservationToken.swift in Sources */, D5A138C11EB29BFA00881A20 /* UIImage+Extensions.swift in Sources */, diff --git a/Source/Shared/Extensions/FileManager+Extensions.swift b/Source/Shared/Extensions/FileManager+Extensions.swift new file mode 100644 index 0000000..c0c6c4c --- /dev/null +++ b/Source/Shared/Extensions/FileManager+Extensions.swift @@ -0,0 +1,22 @@ + +import Foundation + +extension FileManager { + /** + Calculates the size of the directory at the provided `URL` + - parameter url: the directory url + - returns: the size of the provided directory in bytes + */ + public func sizeOfDirectory(at url: URL) -> Int? { + guard let enumerator = self.enumerator(at: url, includingPropertiesForKeys: [], options: [], errorHandler: { _, _ -> Bool in + return false + }) else { + return nil + } + var size = 0 + for case let url as URL in enumerator { + size += url.fileSize ?? 0 + } + return size + } +} diff --git a/Source/Shared/Extensions/URL+Extensions.swift b/Source/Shared/Extensions/URL+Extensions.swift new file mode 100644 index 0000000..8d7ec49 --- /dev/null +++ b/Source/Shared/Extensions/URL+Extensions.swift @@ -0,0 +1,14 @@ + +import Foundation + +extension URL { + /// Returns the file size of the file at the given `URL` in bytes + var fileSize: Int? { + do { + let file = try self.resourceValues(forKeys: [.totalFileAllocatedSizeKey, .fileAllocatedSizeKey]) + return file.totalFileAllocatedSize ?? file.fileAllocatedSize + } catch { + return nil + } + } +} diff --git a/Source/Shared/Storage/DiskStorage.swift b/Source/Shared/Storage/DiskStorage.swift index 76f4cd0..d31f1f4 100644 --- a/Source/Shared/Storage/DiskStorage.swift +++ b/Source/Shared/Storage/DiskStorage.swift @@ -188,20 +188,6 @@ extension DiskStorage { return "\(path)/\(makeFileName(for: key))" } - /// Calculates total disk cache size. - func totalSize() throws -> UInt64 { - var size: UInt64 = 0 - let contents = try fileManager.contentsOfDirectory(atPath: path) - for pathComponent in contents { - let filePath = NSString(string: path).appendingPathComponent(pathComponent) - let attributes = try fileManager.attributesOfItem(atPath: filePath) - if let fileSize = attributes[.size] as? UInt64 { - size += fileSize - } - } - return size - } - func createDirectory() throws { guard !fileManager.fileExists(atPath: path) else { return @@ -273,3 +259,13 @@ public extension DiskStorage { return storage } } + +public extension DiskStorage { + /// Calculates the total size of the cache directory in bytes. + var totalSize: Int? { + if let directory = URL(string: self.path), let size = self.fileManager.sizeOfDirectory(at: directory) { + return size + } + return nil + } +} diff --git a/Source/Shared/Storage/HybridStorage.swift b/Source/Shared/Storage/HybridStorage.swift index 6a529cc..61bc60b 100644 --- a/Source/Shared/Storage/HybridStorage.swift +++ b/Source/Shared/Storage/HybridStorage.swift @@ -165,3 +165,10 @@ extension HybridStorage: KeyObservationRegistry { } } } + +public extension HybridStorage { + /// Returns the total size of the underlying DiskStorage in bytes. + var totalDiskStorageSize: Int? { + return self.diskStorage.totalSize + } +} diff --git a/Source/Shared/Storage/Storage.swift b/Source/Shared/Storage/Storage.swift index f3749cc..816220b 100644 --- a/Source/Shared/Storage/Storage.swift +++ b/Source/Shared/Storage/Storage.swift @@ -108,3 +108,10 @@ extension Storage: KeyObservationRegistry { hybridStorage.removeAllKeyObservers() } } + +public extension Storage { + /// Returns the total size of the DiskStorage of the underlying HybridStorage in bytes. + var totalDiskStorageSize: Int? { + return self.hybridStorage.diskStorage.totalSize + } +} From 5db17b4a83bfd88488b4e4f80e77648c758f93fa Mon Sep 17 00:00:00 2001 From: E L V I S <3lvis@users.noreply.github.com> Date: Sun, 4 Oct 2020 17:27:46 +0200 Subject: [PATCH 02/27] Update Cache.podspec --- Cache.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cache.podspec b/Cache.podspec index 6d31d0b..c5a7221 100644 --- a/Cache.podspec +++ b/Cache.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Cache" s.summary = "Nothing but cache." - s.version = "6.0.0" + s.version = "6.1.0" s.homepage = "https://github.com/hyperoslo/Cache" s.license = 'MIT' s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" } From 4085dcb4543b63ea740d6aea97c9349e8a33b264 Mon Sep 17 00:00:00 2001 From: Elvis Date: Sun, 4 Oct 2020 17:47:56 +0200 Subject: [PATCH 03/27] Update deployment targets --- Cache.xcodeproj/project.pbxproj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Cache.xcodeproj/project.pbxproj b/Cache.xcodeproj/project.pbxproj index 6e1f740..e4968d9 100644 --- a/Cache.xcodeproj/project.pbxproj +++ b/Cache.xcodeproj/project.pbxproj @@ -1057,6 +1057,7 @@ SDKROOT = appletvos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Debug; @@ -1075,6 +1076,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.Cache-tvOS-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 12.0; }; name = Release; @@ -1156,7 +1158,7 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/Tests/Mac/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.Cache-MacTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; @@ -1171,7 +1173,7 @@ FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/Tests/Mac/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.Cache-MacTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; From 9a279c376df29b076915d0e52b2bdb66fb67e469 Mon Sep 17 00:00:00 2001 From: E L V I S <3lvis@users.noreply.github.com> Date: Tue, 6 Oct 2020 19:10:34 +0200 Subject: [PATCH 04/27] Update README.md Fixes #269 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 023ab3e..04a54a8 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ let memoryConfig = MemoryConfig(expiry: .never, countLimit: 10, totalCostLimit: let storage = try? Storage( diskConfig: diskConfig, memoryConfig: memoryConfig, - transformer: TransformerFactory.forCodable(ofType: User.self) // Storage + transformer: TransformerFactory.forCodable(ofType: User.self) // Storage ) ``` @@ -86,13 +86,13 @@ All `Storage` now are generic by default, so you can get a type safety experienc If you want to change the type, `Cache` offers `transform` functions, look for `Transformer` and `TransformerFactory` for built-in transformers. ```swift -let storage: Storage = ... +let storage: Storage = ... storage.setObject(superman, forKey: "user") -let imageStorage = storage.transformImage() // Storage +let imageStorage = storage.transformImage() // Storage imageStorage.setObject(image, forKey: "image") -let stringStorage = storage.transformCodable(ofType: String.self) // Storage +let stringStorage = storage.transformCodable(ofType: String.self) // Storage stringStorage.setObject("hello world", forKey: "string") ``` From ed8355b0b0a72faf7c2730a80427ca9f6d287546 Mon Sep 17 00:00:00 2001 From: Colin Humber Date: Thu, 29 Oct 2020 08:20:13 -0600 Subject: [PATCH 05/27] Renamed Result to CacheResult to avoid conflicts with Swift's built-in Result type --- Cache.xcodeproj/project.pbxproj | 16 ++++---- Source/Shared/Library/CacheResult.swift | 16 ++++++++ Source/Shared/Library/Result.swift | 16 -------- Source/Shared/Storage/AsyncStorage.swift | 48 ++++++++++++------------ 4 files changed, 48 insertions(+), 48 deletions(-) create mode 100644 Source/Shared/Library/CacheResult.swift delete mode 100644 Source/Shared/Library/Result.swift diff --git a/Cache.xcodeproj/project.pbxproj b/Cache.xcodeproj/project.pbxproj index e4968d9..1482ccb 100644 --- a/Cache.xcodeproj/project.pbxproj +++ b/Cache.xcodeproj/project.pbxproj @@ -101,9 +101,9 @@ D28A1D241F6FFEF60030DF81 /* ObjectConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */; }; D28C9BAC1F67ECD400C180C1 /* TestHelper+iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291CDF1C28374800B702C9 /* TestHelper+iOS.swift */; }; D28C9BAF1F67EF8300C180C1 /* UIImage+ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291DA01C28405900B702C9 /* UIImage+ExtensionsTests.swift */; }; - D292DAFD1F6A970B0060F614 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* Result.swift */; }; - D292DAFE1F6A970B0060F614 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* Result.swift */; }; - D292DAFF1F6A970B0060F614 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* Result.swift */; }; + D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; + D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; + D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; D2CF981E1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF981F1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF98201F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; @@ -206,7 +206,7 @@ D27014A420D129EB003B45C7 /* TransformerFactory.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = TransformerFactory.swift; sourceTree = ""; tabWidth = 4; }; D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectConverterTests.swift; sourceTree = ""; }; D28897041F8B79B300C61DEE /* JSONDecoder+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "JSONDecoder+Extensions.swift"; sourceTree = ""; }; - D292DAFC1F6A970B0060F614 /* Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; + D292DAFC1F6A970B0060F614 /* CacheResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheResult.swift; sourceTree = ""; }; D292DB001F6AA06B0060F614 /* SyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncStorageTests.swift; sourceTree = ""; }; D292DB031F6AA0730060F614 /* AsyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncStorageTests.swift; sourceTree = ""; }; D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TestCase+Extensions.swift"; sourceTree = ""; }; @@ -355,7 +355,7 @@ D2CF98571F694FFA00CE8F68 /* ImageWrapper.swift */, D2CF98591F694FFA00CE8F68 /* StorageError.swift */, D2CF98861F695B8F00CE8F68 /* Types.swift */, - D292DAFC1F6A970B0060F614 /* Result.swift */, + D292DAFC1F6A970B0060F614 /* CacheResult.swift */, D2D4CC151FA3145000E4A2D5 /* MD5.swift */, D2D4CC1F1FA3411300E4A2D5 /* JSONDictionaryWrapper.swift */, D2D4CC231FA3426B00E4A2D5 /* JSONArrayWrapper.swift */, @@ -803,7 +803,7 @@ D27014A720D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147E20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7D252A14520031F3B9 /* URL+Extensions.swift in Sources */, - D292DAFF1F6A970B0060F614 /* Result.swift in Sources */, + D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B669A1F6A724300125DE1 /* Date+Extensions.swift in Sources */, 0E79164C250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66891F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -893,7 +893,7 @@ D27014A620D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147D20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7C252A14520031F3B9 /* URL+Extensions.swift in Sources */, - D292DAFE1F6A970B0060F614 /* Result.swift in Sources */, + D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B66991F6A724200125DE1 /* Date+Extensions.swift in Sources */, 0E79164B250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66801F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -945,7 +945,7 @@ D270148C20D113EA003B45C7 /* Optional+Extension.swift in Sources */, D2CF98601F694FFA00CE8F68 /* DiskConfig.swift in Sources */, D270147020D1018A003B45C7 /* Transformer.swift in Sources */, - D292DAFD1F6A970B0060F614 /* Result.swift in Sources */, + D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */, D27014A520D129EB003B45C7 /* TransformerFactory.swift in Sources */, D2D4CC241FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */, 2292AB7B252A14520031F3B9 /* URL+Extensions.swift in Sources */, diff --git a/Source/Shared/Library/CacheResult.swift b/Source/Shared/Library/CacheResult.swift new file mode 100644 index 0000000..2f2d10f --- /dev/null +++ b/Source/Shared/Library/CacheResult.swift @@ -0,0 +1,16 @@ +import Foundation + +/// Used for callback in async operations. +public enum CacheResult { + case value(T) + case error(Error) + + public func map(_ transform: (T) -> U) -> CacheResult { + switch self { + case .value(let value): + return CacheResult.value(transform(value)) + case .error(let error): + return CacheResult.error(error) + } + } +} diff --git a/Source/Shared/Library/Result.swift b/Source/Shared/Library/Result.swift deleted file mode 100644 index 4b80f49..0000000 --- a/Source/Shared/Library/Result.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -/// Used for callback in async operations. -public enum Result { - case value(T) - case error(Error) - - public func map(_ transform: (T) -> U) -> Result { - switch self { - case .value(let value): - return Result.value(transform(value)) - case .error(let error): - return Result.error(error) - } - } -} diff --git a/Source/Shared/Storage/AsyncStorage.swift b/Source/Shared/Storage/AsyncStorage.swift index 9a11994..5d61d9f 100644 --- a/Source/Shared/Storage/AsyncStorage.swift +++ b/Source/Shared/Storage/AsyncStorage.swift @@ -14,34 +14,34 @@ public class AsyncStorage { } extension AsyncStorage { - public func entry(forKey key: Key, completion: @escaping (Result>) -> Void) { + public func entry(forKey key: Key, completion: @escaping (CacheResult>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(Result.error(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { let anEntry = try self.innerStorage.entry(forKey: key) - completion(Result.value(anEntry)) + completion(CacheResult.value(anEntry)) } catch { - completion(Result.error(error)) + completion(CacheResult.error(error)) } } } - public func removeObject(forKey key: Key, completion: @escaping (Result<()>) -> Void) { + public func removeObject(forKey key: Key, completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(Result.error(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.removeObject(forKey: key) - completion(Result.value(())) + completion(CacheResult.value(())) } catch { - completion(Result.error(error)) + completion(CacheResult.error(error)) } } } @@ -50,56 +50,56 @@ extension AsyncStorage { _ object: Value, forKey key: Key, expiry: Expiry? = nil, - completion: @escaping (Result<()>) -> Void) { + completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(Result.error(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.setObject(object, forKey: key, expiry: expiry) - completion(Result.value(())) + completion(CacheResult.value(())) } catch { - completion(Result.error(error)) + completion(CacheResult.error(error)) } } } - public func removeAll(completion: @escaping (Result<()>) -> Void) { + public func removeAll(completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(Result.error(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.removeAll() - completion(Result.value(())) + completion(CacheResult.value(())) } catch { - completion(Result.error(error)) + completion(CacheResult.error(error)) } } } - public func removeExpiredObjects(completion: @escaping (Result<()>) -> Void) { + public func removeExpiredObjects(completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(Result.error(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.removeExpiredObjects() - completion(Result.value(())) + completion(CacheResult.value(())) } catch { - completion(Result.error(error)) + completion(CacheResult.error(error)) } } } - public func object(forKey key: Key, completion: @escaping (Result) -> Void) { - entry(forKey: key, completion: { (result: Result>) in + public func object(forKey key: Key, completion: @escaping (CacheResult) -> Void) { + entry(forKey: key, completion: { (result: CacheResult>) in completion(result.map({ entry in return entry.object })) @@ -108,8 +108,8 @@ extension AsyncStorage { public func existsObject( forKey key: Key, - completion: @escaping (Result) -> Void) { - object(forKey: key, completion: { (result: Result) in + completion: @escaping (CacheResult) -> Void) { + object(forKey: key, completion: { (result: CacheResult) in completion(result.map({ _ in return true })) From f9ba788a26251b48df0c3ba9588f4acf0af93826 Mon Sep 17 00:00:00 2001 From: Artem Garmash Date: Fri, 30 Oct 2020 17:06:00 +0300 Subject: [PATCH 06/27] Remove CacheResult in favor of Swift.Result --- Cache.xcodeproj/project.pbxproj | 8 ---- Source/Shared/Library/CacheResult.swift | 16 ------- Source/Shared/Storage/AsyncStorage.swift | 48 +++++++++---------- .../iOS/Tests/Storage/AsyncStorageTests.swift | 4 +- Tests/iOS/Tests/Storage/StorageTests.swift | 2 +- 5 files changed, 27 insertions(+), 51 deletions(-) delete mode 100644 Source/Shared/Library/CacheResult.swift diff --git a/Cache.xcodeproj/project.pbxproj b/Cache.xcodeproj/project.pbxproj index 1482ccb..4b3d8b5 100644 --- a/Cache.xcodeproj/project.pbxproj +++ b/Cache.xcodeproj/project.pbxproj @@ -101,9 +101,6 @@ D28A1D241F6FFEF60030DF81 /* ObjectConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */; }; D28C9BAC1F67ECD400C180C1 /* TestHelper+iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291CDF1C28374800B702C9 /* TestHelper+iOS.swift */; }; D28C9BAF1F67EF8300C180C1 /* UIImage+ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291DA01C28405900B702C9 /* UIImage+ExtensionsTests.swift */; }; - D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; - D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; - D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; D2CF981E1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF981F1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF98201F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; @@ -206,7 +203,6 @@ D27014A420D129EB003B45C7 /* TransformerFactory.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = TransformerFactory.swift; sourceTree = ""; tabWidth = 4; }; D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectConverterTests.swift; sourceTree = ""; }; D28897041F8B79B300C61DEE /* JSONDecoder+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "JSONDecoder+Extensions.swift"; sourceTree = ""; }; - D292DAFC1F6A970B0060F614 /* CacheResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheResult.swift; sourceTree = ""; }; D292DB001F6AA06B0060F614 /* SyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncStorageTests.swift; sourceTree = ""; }; D292DB031F6AA0730060F614 /* AsyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncStorageTests.swift; sourceTree = ""; }; D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TestCase+Extensions.swift"; sourceTree = ""; }; @@ -355,7 +351,6 @@ D2CF98571F694FFA00CE8F68 /* ImageWrapper.swift */, D2CF98591F694FFA00CE8F68 /* StorageError.swift */, D2CF98861F695B8F00CE8F68 /* Types.swift */, - D292DAFC1F6A970B0060F614 /* CacheResult.swift */, D2D4CC151FA3145000E4A2D5 /* MD5.swift */, D2D4CC1F1FA3411300E4A2D5 /* JSONDictionaryWrapper.swift */, D2D4CC231FA3426B00E4A2D5 /* JSONArrayWrapper.swift */, @@ -803,7 +798,6 @@ D27014A720D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147E20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7D252A14520031F3B9 /* URL+Extensions.swift in Sources */, - D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B669A1F6A724300125DE1 /* Date+Extensions.swift in Sources */, 0E79164C250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66891F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -893,7 +887,6 @@ D27014A620D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147D20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7C252A14520031F3B9 /* URL+Extensions.swift in Sources */, - D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B66991F6A724200125DE1 /* Date+Extensions.swift in Sources */, 0E79164B250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66801F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -945,7 +938,6 @@ D270148C20D113EA003B45C7 /* Optional+Extension.swift in Sources */, D2CF98601F694FFA00CE8F68 /* DiskConfig.swift in Sources */, D270147020D1018A003B45C7 /* Transformer.swift in Sources */, - D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */, D27014A520D129EB003B45C7 /* TransformerFactory.swift in Sources */, D2D4CC241FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */, 2292AB7B252A14520031F3B9 /* URL+Extensions.swift in Sources */, diff --git a/Source/Shared/Library/CacheResult.swift b/Source/Shared/Library/CacheResult.swift deleted file mode 100644 index 2f2d10f..0000000 --- a/Source/Shared/Library/CacheResult.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -/// Used for callback in async operations. -public enum CacheResult { - case value(T) - case error(Error) - - public func map(_ transform: (T) -> U) -> CacheResult { - switch self { - case .value(let value): - return CacheResult.value(transform(value)) - case .error(let error): - return CacheResult.error(error) - } - } -} diff --git a/Source/Shared/Storage/AsyncStorage.swift b/Source/Shared/Storage/AsyncStorage.swift index 5d61d9f..032ea08 100644 --- a/Source/Shared/Storage/AsyncStorage.swift +++ b/Source/Shared/Storage/AsyncStorage.swift @@ -14,34 +14,34 @@ public class AsyncStorage { } extension AsyncStorage { - public func entry(forKey key: Key, completion: @escaping (CacheResult>) -> Void) { + public func entry(forKey key: Key, completion: @escaping (Result, Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { let anEntry = try self.innerStorage.entry(forKey: key) - completion(CacheResult.value(anEntry)) + completion(.success(anEntry)) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func removeObject(forKey key: Key, completion: @escaping (CacheResult<()>) -> Void) { + public func removeObject(forKey key: Key, completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.removeObject(forKey: key) - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } @@ -50,56 +50,56 @@ extension AsyncStorage { _ object: Value, forKey key: Key, expiry: Expiry? = nil, - completion: @escaping (CacheResult<()>) -> Void) { + completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.setObject(object, forKey: key, expiry: expiry) - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func removeAll(completion: @escaping (CacheResult<()>) -> Void) { + public func removeAll(completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.removeAll() - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func removeExpiredObjects(completion: @escaping (CacheResult<()>) -> Void) { + public func removeExpiredObjects(completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.removeExpiredObjects() - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func object(forKey key: Key, completion: @escaping (CacheResult) -> Void) { - entry(forKey: key, completion: { (result: CacheResult>) in + public func object(forKey key: Key, completion: @escaping (Result) -> Void) { + entry(forKey: key, completion: { (result: Result, Error>) in completion(result.map({ entry in return entry.object })) @@ -108,8 +108,8 @@ extension AsyncStorage { public func existsObject( forKey key: Key, - completion: @escaping (CacheResult) -> Void) { - object(forKey: key, completion: { (result: CacheResult) in + completion: @escaping (Result) -> Void) { + object(forKey: key, completion: { (result: Result) in completion(result.map({ _ in return true })) diff --git a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift index 7ced640..63158dc 100644 --- a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift +++ b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift @@ -25,7 +25,7 @@ final class AsyncStorageTests: XCTestCase { storage.setObject(user, forKey: "user", completion: { _ in }) storage.object(forKey: "user", completion: { result in switch result { - case .value(let cachedUser): + case .success(let cachedUser): XCTAssertEqual(cachedUser, self.user) expectation.fulfill() default: @@ -52,7 +52,7 @@ final class AsyncStorageTests: XCTestCase { then("all are removed") { intStorage.existsObject(forKey: "key-99", completion: { result in switch result { - case .value: + case .success: XCTFail() default: expectation.fulfill() diff --git a/Tests/iOS/Tests/Storage/StorageTests.swift b/Tests/iOS/Tests/Storage/StorageTests.swift index f267f19..80f3f18 100644 --- a/Tests/iOS/Tests/Storage/StorageTests.swift +++ b/Tests/iOS/Tests/Storage/StorageTests.swift @@ -33,7 +33,7 @@ final class StorageTests: XCTestCase { storage.async.object(forKey: "user", completion: { result in switch result { - case .value(let cachedUser): + case .success(let cachedUser): XCTAssertEqual(cachedUser, self.user) expectation.fulfill() default: From db09aa310d6b97dde22f8d3180e6d954324fbcb8 Mon Sep 17 00:00:00 2001 From: E L V I S <3lvis@users.noreply.github.com> Date: Sat, 31 Oct 2020 17:51:41 +0100 Subject: [PATCH 07/27] Update Cache.podspec --- Cache.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cache.podspec b/Cache.podspec index c5a7221..c74a7c9 100644 --- a/Cache.podspec +++ b/Cache.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Cache" s.summary = "Nothing but cache." - s.version = "6.1.0" + s.version = "7.0.0" s.homepage = "https://github.com/hyperoslo/Cache" s.license = 'MIT' s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" } From 28acf9a115b5da873c4977bebf2f27ef32d3e634 Mon Sep 17 00:00:00 2001 From: Artem Garmash Date: Fri, 30 Oct 2020 17:06:00 +0300 Subject: [PATCH 08/27] Remove CacheResult in favor of Swift.Result --- Cache.xcodeproj/project.pbxproj | 8 ---- Source/Shared/Library/CacheResult.swift | 16 ------- Source/Shared/Storage/AsyncStorage.swift | 48 +++++++++---------- .../iOS/Tests/Storage/AsyncStorageTests.swift | 4 +- Tests/iOS/Tests/Storage/StorageTests.swift | 2 +- 5 files changed, 27 insertions(+), 51 deletions(-) delete mode 100644 Source/Shared/Library/CacheResult.swift diff --git a/Cache.xcodeproj/project.pbxproj b/Cache.xcodeproj/project.pbxproj index 1482ccb..4b3d8b5 100644 --- a/Cache.xcodeproj/project.pbxproj +++ b/Cache.xcodeproj/project.pbxproj @@ -101,9 +101,6 @@ D28A1D241F6FFEF60030DF81 /* ObjectConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */; }; D28C9BAC1F67ECD400C180C1 /* TestHelper+iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291CDF1C28374800B702C9 /* TestHelper+iOS.swift */; }; D28C9BAF1F67EF8300C180C1 /* UIImage+ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291DA01C28405900B702C9 /* UIImage+ExtensionsTests.swift */; }; - D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; - D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; - D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; D2CF981E1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF981F1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF98201F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; @@ -206,7 +203,6 @@ D27014A420D129EB003B45C7 /* TransformerFactory.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = TransformerFactory.swift; sourceTree = ""; tabWidth = 4; }; D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectConverterTests.swift; sourceTree = ""; }; D28897041F8B79B300C61DEE /* JSONDecoder+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "JSONDecoder+Extensions.swift"; sourceTree = ""; }; - D292DAFC1F6A970B0060F614 /* CacheResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheResult.swift; sourceTree = ""; }; D292DB001F6AA06B0060F614 /* SyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncStorageTests.swift; sourceTree = ""; }; D292DB031F6AA0730060F614 /* AsyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncStorageTests.swift; sourceTree = ""; }; D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TestCase+Extensions.swift"; sourceTree = ""; }; @@ -355,7 +351,6 @@ D2CF98571F694FFA00CE8F68 /* ImageWrapper.swift */, D2CF98591F694FFA00CE8F68 /* StorageError.swift */, D2CF98861F695B8F00CE8F68 /* Types.swift */, - D292DAFC1F6A970B0060F614 /* CacheResult.swift */, D2D4CC151FA3145000E4A2D5 /* MD5.swift */, D2D4CC1F1FA3411300E4A2D5 /* JSONDictionaryWrapper.swift */, D2D4CC231FA3426B00E4A2D5 /* JSONArrayWrapper.swift */, @@ -803,7 +798,6 @@ D27014A720D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147E20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7D252A14520031F3B9 /* URL+Extensions.swift in Sources */, - D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B669A1F6A724300125DE1 /* Date+Extensions.swift in Sources */, 0E79164C250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66891F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -893,7 +887,6 @@ D27014A620D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147D20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7C252A14520031F3B9 /* URL+Extensions.swift in Sources */, - D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B66991F6A724200125DE1 /* Date+Extensions.swift in Sources */, 0E79164B250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66801F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -945,7 +938,6 @@ D270148C20D113EA003B45C7 /* Optional+Extension.swift in Sources */, D2CF98601F694FFA00CE8F68 /* DiskConfig.swift in Sources */, D270147020D1018A003B45C7 /* Transformer.swift in Sources */, - D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */, D27014A520D129EB003B45C7 /* TransformerFactory.swift in Sources */, D2D4CC241FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */, 2292AB7B252A14520031F3B9 /* URL+Extensions.swift in Sources */, diff --git a/Source/Shared/Library/CacheResult.swift b/Source/Shared/Library/CacheResult.swift deleted file mode 100644 index 2f2d10f..0000000 --- a/Source/Shared/Library/CacheResult.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -/// Used for callback in async operations. -public enum CacheResult { - case value(T) - case error(Error) - - public func map(_ transform: (T) -> U) -> CacheResult { - switch self { - case .value(let value): - return CacheResult.value(transform(value)) - case .error(let error): - return CacheResult.error(error) - } - } -} diff --git a/Source/Shared/Storage/AsyncStorage.swift b/Source/Shared/Storage/AsyncStorage.swift index 5d61d9f..032ea08 100644 --- a/Source/Shared/Storage/AsyncStorage.swift +++ b/Source/Shared/Storage/AsyncStorage.swift @@ -14,34 +14,34 @@ public class AsyncStorage { } extension AsyncStorage { - public func entry(forKey key: Key, completion: @escaping (CacheResult>) -> Void) { + public func entry(forKey key: Key, completion: @escaping (Result, Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { let anEntry = try self.innerStorage.entry(forKey: key) - completion(CacheResult.value(anEntry)) + completion(.success(anEntry)) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func removeObject(forKey key: Key, completion: @escaping (CacheResult<()>) -> Void) { + public func removeObject(forKey key: Key, completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.removeObject(forKey: key) - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } @@ -50,56 +50,56 @@ extension AsyncStorage { _ object: Value, forKey key: Key, expiry: Expiry? = nil, - completion: @escaping (CacheResult<()>) -> Void) { + completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.setObject(object, forKey: key, expiry: expiry) - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func removeAll(completion: @escaping (CacheResult<()>) -> Void) { + public func removeAll(completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.removeAll() - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func removeExpiredObjects(completion: @escaping (CacheResult<()>) -> Void) { + public func removeExpiredObjects(completion: @escaping (Result<(), Error>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(CacheResult.error(StorageError.deallocated)) + completion(.failure(StorageError.deallocated)) return } do { try self.innerStorage.removeExpiredObjects() - completion(CacheResult.value(())) + completion(.success(())) } catch { - completion(CacheResult.error(error)) + completion(.failure(error)) } } } - public func object(forKey key: Key, completion: @escaping (CacheResult) -> Void) { - entry(forKey: key, completion: { (result: CacheResult>) in + public func object(forKey key: Key, completion: @escaping (Result) -> Void) { + entry(forKey: key, completion: { (result: Result, Error>) in completion(result.map({ entry in return entry.object })) @@ -108,8 +108,8 @@ extension AsyncStorage { public func existsObject( forKey key: Key, - completion: @escaping (CacheResult) -> Void) { - object(forKey: key, completion: { (result: CacheResult) in + completion: @escaping (Result) -> Void) { + object(forKey: key, completion: { (result: Result) in completion(result.map({ _ in return true })) diff --git a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift index 7ced640..63158dc 100644 --- a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift +++ b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift @@ -25,7 +25,7 @@ final class AsyncStorageTests: XCTestCase { storage.setObject(user, forKey: "user", completion: { _ in }) storage.object(forKey: "user", completion: { result in switch result { - case .value(let cachedUser): + case .success(let cachedUser): XCTAssertEqual(cachedUser, self.user) expectation.fulfill() default: @@ -52,7 +52,7 @@ final class AsyncStorageTests: XCTestCase { then("all are removed") { intStorage.existsObject(forKey: "key-99", completion: { result in switch result { - case .value: + case .success: XCTFail() default: expectation.fulfill() diff --git a/Tests/iOS/Tests/Storage/StorageTests.swift b/Tests/iOS/Tests/Storage/StorageTests.swift index f267f19..80f3f18 100644 --- a/Tests/iOS/Tests/Storage/StorageTests.swift +++ b/Tests/iOS/Tests/Storage/StorageTests.swift @@ -33,7 +33,7 @@ final class StorageTests: XCTestCase { storage.async.object(forKey: "user", completion: { result in switch result { - case .value(let cachedUser): + case .success(let cachedUser): XCTAssertEqual(cachedUser, self.user) expectation.fulfill() default: From dcdfd5f8cfdfd3e0f856d73b59d9126715b93a3a Mon Sep 17 00:00:00 2001 From: Elvis Nunez Date: Sun, 1 Nov 2020 09:51:00 +0100 Subject: [PATCH 09/27] Revert "Merge pull request #273 from agarmash/remove-custom-result-type" This reverts commit 43ab355b9e9c6a34e3c813ff6e338aff599f9acb, reversing changes made to 87bf5e0a1d693d9c1213825e017230aedc8836fd. --- Cache.xcodeproj/project.pbxproj | 8 ++++ Source/Shared/Library/CacheResult.swift | 16 +++++++ Source/Shared/Storage/AsyncStorage.swift | 48 +++++++++---------- .../iOS/Tests/Storage/AsyncStorageTests.swift | 4 +- Tests/iOS/Tests/Storage/StorageTests.swift | 2 +- 5 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 Source/Shared/Library/CacheResult.swift diff --git a/Cache.xcodeproj/project.pbxproj b/Cache.xcodeproj/project.pbxproj index 4b3d8b5..1482ccb 100644 --- a/Cache.xcodeproj/project.pbxproj +++ b/Cache.xcodeproj/project.pbxproj @@ -101,6 +101,9 @@ D28A1D241F6FFEF60030DF81 /* ObjectConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */; }; D28C9BAC1F67ECD400C180C1 /* TestHelper+iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291CDF1C28374800B702C9 /* TestHelper+iOS.swift */; }; D28C9BAF1F67EF8300C180C1 /* UIImage+ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5291DA01C28405900B702C9 /* UIImage+ExtensionsTests.swift */; }; + D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; + D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; + D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D292DAFC1F6A970B0060F614 /* CacheResult.swift */; }; D2CF981E1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF981F1F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; D2CF98201F69427C00CE8F68 /* TestCase+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */; }; @@ -203,6 +206,7 @@ D27014A420D129EB003B45C7 /* TransformerFactory.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = TransformerFactory.swift; sourceTree = ""; tabWidth = 4; }; D285143E1F6FFE1F00C674D1 /* ObjectConverterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectConverterTests.swift; sourceTree = ""; }; D28897041F8B79B300C61DEE /* JSONDecoder+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "JSONDecoder+Extensions.swift"; sourceTree = ""; }; + D292DAFC1F6A970B0060F614 /* CacheResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheResult.swift; sourceTree = ""; }; D292DB001F6AA06B0060F614 /* SyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncStorageTests.swift; sourceTree = ""; }; D292DB031F6AA0730060F614 /* AsyncStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncStorageTests.swift; sourceTree = ""; }; D2CF981B1F69427C00CE8F68 /* TestCase+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TestCase+Extensions.swift"; sourceTree = ""; }; @@ -351,6 +355,7 @@ D2CF98571F694FFA00CE8F68 /* ImageWrapper.swift */, D2CF98591F694FFA00CE8F68 /* StorageError.swift */, D2CF98861F695B8F00CE8F68 /* Types.swift */, + D292DAFC1F6A970B0060F614 /* CacheResult.swift */, D2D4CC151FA3145000E4A2D5 /* MD5.swift */, D2D4CC1F1FA3411300E4A2D5 /* JSONDictionaryWrapper.swift */, D2D4CC231FA3426B00E4A2D5 /* JSONArrayWrapper.swift */, @@ -798,6 +803,7 @@ D27014A720D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147E20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7D252A14520031F3B9 /* URL+Extensions.swift in Sources */, + D292DAFF1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B669A1F6A724300125DE1 /* Date+Extensions.swift in Sources */, 0E79164C250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66891F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -887,6 +893,7 @@ D27014A620D129EB003B45C7 /* TransformerFactory.swift in Sources */, D270147D20D107DA003B45C7 /* SyncStorage.swift in Sources */, 2292AB7C252A14520031F3B9 /* URL+Extensions.swift in Sources */, + D292DAFE1F6A970B0060F614 /* CacheResult.swift in Sources */, D21B66991F6A724200125DE1 /* Date+Extensions.swift in Sources */, 0E79164B250E2AA500A71666 /* Hasher+constantAccrossExecutions.swift in Sources */, D21B66801F6A723C00125DE1 /* ImageWrapper.swift in Sources */, @@ -938,6 +945,7 @@ D270148C20D113EA003B45C7 /* Optional+Extension.swift in Sources */, D2CF98601F694FFA00CE8F68 /* DiskConfig.swift in Sources */, D270147020D1018A003B45C7 /* Transformer.swift in Sources */, + D292DAFD1F6A970B0060F614 /* CacheResult.swift in Sources */, D27014A520D129EB003B45C7 /* TransformerFactory.swift in Sources */, D2D4CC241FA3426B00E4A2D5 /* JSONArrayWrapper.swift in Sources */, 2292AB7B252A14520031F3B9 /* URL+Extensions.swift in Sources */, diff --git a/Source/Shared/Library/CacheResult.swift b/Source/Shared/Library/CacheResult.swift new file mode 100644 index 0000000..2f2d10f --- /dev/null +++ b/Source/Shared/Library/CacheResult.swift @@ -0,0 +1,16 @@ +import Foundation + +/// Used for callback in async operations. +public enum CacheResult { + case value(T) + case error(Error) + + public func map(_ transform: (T) -> U) -> CacheResult { + switch self { + case .value(let value): + return CacheResult.value(transform(value)) + case .error(let error): + return CacheResult.error(error) + } + } +} diff --git a/Source/Shared/Storage/AsyncStorage.swift b/Source/Shared/Storage/AsyncStorage.swift index 032ea08..5d61d9f 100644 --- a/Source/Shared/Storage/AsyncStorage.swift +++ b/Source/Shared/Storage/AsyncStorage.swift @@ -14,34 +14,34 @@ public class AsyncStorage { } extension AsyncStorage { - public func entry(forKey key: Key, completion: @escaping (Result, Error>) -> Void) { + public func entry(forKey key: Key, completion: @escaping (CacheResult>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(.failure(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { let anEntry = try self.innerStorage.entry(forKey: key) - completion(.success(anEntry)) + completion(CacheResult.value(anEntry)) } catch { - completion(.failure(error)) + completion(CacheResult.error(error)) } } } - public func removeObject(forKey key: Key, completion: @escaping (Result<(), Error>) -> Void) { + public func removeObject(forKey key: Key, completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(.failure(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.removeObject(forKey: key) - completion(.success(())) + completion(CacheResult.value(())) } catch { - completion(.failure(error)) + completion(CacheResult.error(error)) } } } @@ -50,56 +50,56 @@ extension AsyncStorage { _ object: Value, forKey key: Key, expiry: Expiry? = nil, - completion: @escaping (Result<(), Error>) -> Void) { + completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(.failure(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.setObject(object, forKey: key, expiry: expiry) - completion(.success(())) + completion(CacheResult.value(())) } catch { - completion(.failure(error)) + completion(CacheResult.error(error)) } } } - public func removeAll(completion: @escaping (Result<(), Error>) -> Void) { + public func removeAll(completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(.failure(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.removeAll() - completion(.success(())) + completion(CacheResult.value(())) } catch { - completion(.failure(error)) + completion(CacheResult.error(error)) } } } - public func removeExpiredObjects(completion: @escaping (Result<(), Error>) -> Void) { + public func removeExpiredObjects(completion: @escaping (CacheResult<()>) -> Void) { serialQueue.async { [weak self] in guard let `self` = self else { - completion(.failure(StorageError.deallocated)) + completion(CacheResult.error(StorageError.deallocated)) return } do { try self.innerStorage.removeExpiredObjects() - completion(.success(())) + completion(CacheResult.value(())) } catch { - completion(.failure(error)) + completion(CacheResult.error(error)) } } } - public func object(forKey key: Key, completion: @escaping (Result) -> Void) { - entry(forKey: key, completion: { (result: Result, Error>) in + public func object(forKey key: Key, completion: @escaping (CacheResult) -> Void) { + entry(forKey: key, completion: { (result: CacheResult>) in completion(result.map({ entry in return entry.object })) @@ -108,8 +108,8 @@ extension AsyncStorage { public func existsObject( forKey key: Key, - completion: @escaping (Result) -> Void) { - object(forKey: key, completion: { (result: Result) in + completion: @escaping (CacheResult) -> Void) { + object(forKey: key, completion: { (result: CacheResult) in completion(result.map({ _ in return true })) diff --git a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift index 63158dc..7ced640 100644 --- a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift +++ b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift @@ -25,7 +25,7 @@ final class AsyncStorageTests: XCTestCase { storage.setObject(user, forKey: "user", completion: { _ in }) storage.object(forKey: "user", completion: { result in switch result { - case .success(let cachedUser): + case .value(let cachedUser): XCTAssertEqual(cachedUser, self.user) expectation.fulfill() default: @@ -52,7 +52,7 @@ final class AsyncStorageTests: XCTestCase { then("all are removed") { intStorage.existsObject(forKey: "key-99", completion: { result in switch result { - case .success: + case .value: XCTFail() default: expectation.fulfill() diff --git a/Tests/iOS/Tests/Storage/StorageTests.swift b/Tests/iOS/Tests/Storage/StorageTests.swift index 80f3f18..f267f19 100644 --- a/Tests/iOS/Tests/Storage/StorageTests.swift +++ b/Tests/iOS/Tests/Storage/StorageTests.swift @@ -33,7 +33,7 @@ final class StorageTests: XCTestCase { storage.async.object(forKey: "user", completion: { result in switch result { - case .success(let cachedUser): + case .value(let cachedUser): XCTAssertEqual(cachedUser, self.user) expectation.fulfill() default: From be773e801e72db46aab2d8272cbf3892efada681 Mon Sep 17 00:00:00 2001 From: Artem Garmash Date: Fri, 6 Nov 2020 11:22:40 +0300 Subject: [PATCH 10/27] Update code snippets in readme --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 04a54a8..99eae0f 100644 --- a/README.md +++ b/README.md @@ -247,42 +247,42 @@ You access Async APIs via `storage.async`, it is also thread safe, and you can u ```swift storage.async.setObject("Oslo", forKey: "my favorite city") { result in switch result { - case .value: + case .success: print("saved successfully") - case .error(let error): + case .failure(let error): print(error) } } storage.async.object(forKey: "my favorite city") { result in switch result { - case .value(let city): + case .success(let city): print("my favorite city is \(city)") - case .error(let error): + case .failure(let error): print(error) } } storage.async.existsObject(forKey: "my favorite city") { result in - if case .value(let exists) = result, exists { + if case .success(let exists) = result, exists { print("I have a favorite city") } } storage.async.removeAll() { result in switch result { - case .value: + case .success: print("removal completes") - case .error(let error): + case .failure(let error): print(error) } } storage.async.removeExpiredObjects() { result in switch result { - case .value: + case .success: print("removal completes") - case .error(let error): + case .failure(let error): print(error) } } @@ -381,7 +381,7 @@ This is how you perform object converting and saving with `Alamofire` ```swift Alamofire.request("https://gameofthrones.org/mostFavoriteCharacter").responseString { response in do { - let user = try JSONDecoder.decode(response.result.value, to: User.self) + let user = try JSONDecoder.decode(response.result.success, to: User.self) try storage.setObject(user, forKey: "most favorite character") } catch { print(error) From ed4cfaf76c5e98d1d8648a3c37c80aceab4b5cc1 Mon Sep 17 00:00:00 2001 From: Artem Garmash Date: Fri, 6 Nov 2020 11:34:11 +0300 Subject: [PATCH 11/27] Disable parallel test execution --- Cache.xcodeproj/xcshareddata/xcschemes/Cache-iOS.xcscheme | 1 - 1 file changed, 1 deletion(-) diff --git a/Cache.xcodeproj/xcshareddata/xcschemes/Cache-iOS.xcscheme b/Cache.xcodeproj/xcshareddata/xcschemes/Cache-iOS.xcscheme index 3c2c837..fc762f3 100644 --- a/Cache.xcodeproj/xcshareddata/xcschemes/Cache-iOS.xcscheme +++ b/Cache.xcodeproj/xcshareddata/xcschemes/Cache-iOS.xcscheme @@ -39,7 +39,6 @@ Date: Fri, 6 Nov 2020 12:44:04 +0300 Subject: [PATCH 12/27] Update Swift badge to the version 5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04a54a8..bfc7ee5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![License](https://img.shields.io/cocoapods/l/Cache.svg?style=flat)](http://cocoadocs.org/docsets/Cache) [![Platform](https://img.shields.io/cocoapods/p/Cache.svg?style=flat)](http://cocoadocs.org/docsets/Cache) [![Documentation](https://img.shields.io/cocoapods/metrics/doc-percent/Cache.svg?style=flat)](http://cocoadocs.org/docsets/Cache) -![Swift](https://img.shields.io/badge/%20in-swift%204.0-orange.svg) +![Swift](https://img.shields.io/badge/%20in-swift%205-orange.svg) ## Table of Contents From f1c5217faa7cf426748d2920f73c9e4902f94edf Mon Sep 17 00:00:00 2001 From: Quan Tran Date: Wed, 11 Nov 2020 22:30:47 -0600 Subject: [PATCH 13/27] Fix compatibility with Mac Catalyst --- Source/Mac/NSImage+Extensions.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Mac/NSImage+Extensions.swift b/Source/Mac/NSImage+Extensions.swift index 8ebbc9a..92d6dfc 100644 --- a/Source/Mac/NSImage+Extensions.swift +++ b/Source/Mac/NSImage+Extensions.swift @@ -1,4 +1,4 @@ -#if canImport(AppKit) +#if canImport(AppKit) && !targetEnvironment(macCatalyst) import AppKit /// Helper UIImage extension. From 27c0a86fdd2eadfdb4b2adf12ac20caf966b49d8 Mon Sep 17 00:00:00 2001 From: Saul Moreno Abril <93sauu@gmail.com> Date: Thu, 12 Nov 2020 14:16:59 +0100 Subject: [PATCH 14/27] Added allKeys and allObjects computed vars for storage with sense --- Source/Shared/Storage/DiskStorage.swift | 4 ++++ Source/Shared/Storage/HybridStorage.swift | 8 ++++++++ Source/Shared/Storage/MemoryStorage.swift | 8 ++++++++ Source/Shared/Storage/Storage.swift | 8 ++++++++ Source/Shared/Storage/StorageAware.swift | 11 +++++++++++ Source/Shared/Storage/SyncStorage.swift | 17 ++++++++++++++++- 6 files changed, 55 insertions(+), 1 deletion(-) diff --git a/Source/Shared/Storage/DiskStorage.swift b/Source/Shared/Storage/DiskStorage.swift index d31f1f4..d90e910 100644 --- a/Source/Shared/Storage/DiskStorage.swift +++ b/Source/Shared/Storage/DiskStorage.swift @@ -58,6 +58,10 @@ final public class DiskStorage { } extension DiskStorage: StorageAware { + public var allKeys: [Key] { [] } + + public var allObjects: [Value] { [] } + public func entry(forKey key: Key) throws -> Entry { let filePath = makeFilePath(for: key) let data = try Data(contentsOf: URL(fileURLWithPath: filePath)) diff --git a/Source/Shared/Storage/HybridStorage.swift b/Source/Shared/Storage/HybridStorage.swift index 61bc60b..385980f 100644 --- a/Source/Shared/Storage/HybridStorage.swift +++ b/Source/Shared/Storage/HybridStorage.swift @@ -26,6 +26,14 @@ public final class HybridStorage { } extension HybridStorage: StorageAware { + public var allKeys: [Key] { + memoryStorage.allKeys + } + + public var allObjects: [Value] { + memoryStorage.allObjects + } + public func entry(forKey key: Key) throws -> Entry { do { return try memoryStorage.entry(forKey: key) diff --git a/Source/Shared/Storage/MemoryStorage.swift b/Source/Shared/Storage/MemoryStorage.swift index 6ab4b6d..1adc46f 100644 --- a/Source/Shared/Storage/MemoryStorage.swift +++ b/Source/Shared/Storage/MemoryStorage.swift @@ -31,6 +31,14 @@ public class MemoryStorage: StorageAware { } extension MemoryStorage { + public var allKeys: [Key] { + Array(keys) + } + + public var allObjects: [Value] { + allKeys.compactMap { try? object(forKey: $0) } + } + public func setObject(_ object: Value, forKey key: Key, expiry: Expiry? = nil) { let capsule = MemoryCapsule(value: object, expiry: .date(expiry?.date ?? config.expiry.date)) cache.setObject(capsule, forKey: WrappedKey(key)) diff --git a/Source/Shared/Storage/Storage.swift b/Source/Shared/Storage/Storage.swift index 816220b..e2d7c69 100644 --- a/Source/Shared/Storage/Storage.swift +++ b/Source/Shared/Storage/Storage.swift @@ -43,6 +43,14 @@ public final class Storage { } extension Storage: StorageAware { + public var allKeys: [Key] { + self.syncStorage.allKeys + } + + public var allObjects: [Value] { + self.syncStorage.allObjects + } + public func entry(forKey key: Key) throws -> Entry { return try self.syncStorage.entry(forKey: key) } diff --git a/Source/Shared/Storage/StorageAware.swift b/Source/Shared/Storage/StorageAware.swift index ede372f..cbbb8ce 100644 --- a/Source/Shared/Storage/StorageAware.swift +++ b/Source/Shared/Storage/StorageAware.swift @@ -4,6 +4,17 @@ import Foundation public protocol StorageAware { associatedtype Key: Hashable associatedtype Value + + /** + Get all keys in the storage + */ + var allKeys: [Key] { get } + + /** + Get all objects from the storage + */ + var allObjects: [Value] { get } + /** Tries to retrieve the object from the storage. - Parameter key: Unique key to identify the object in the cache diff --git a/Source/Shared/Storage/SyncStorage.swift b/Source/Shared/Storage/SyncStorage.swift index 6555842..51d15f0 100644 --- a/Source/Shared/Storage/SyncStorage.swift +++ b/Source/Shared/Storage/SyncStorage.swift @@ -14,12 +14,27 @@ public class SyncStorage { } extension SyncStorage: StorageAware { + public var allKeys: [Key] { + var keys: [Key]! + serialQueue.sync { + keys = self.innerStorage.allKeys + } + return keys + } + + public var allObjects: [Value] { + var objects: [Value]! + serialQueue.sync { + objects = self.innerStorage.allObjects + } + return objects + } + public func entry(forKey key: Key) throws -> Entry { var entry: Entry! try serialQueue.sync { entry = try innerStorage.entry(forKey: key) } - return entry } From fe15b7cdf7266d22aa399f0c70cc3db733144970 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 17 Jan 2021 15:27:05 -0500 Subject: [PATCH 15/27] DiskStorage file URL handling improvements --- Source/Shared/Storage/DiskStorage.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Shared/Storage/DiskStorage.swift b/Source/Shared/Storage/DiskStorage.swift index d90e910..ca4db9a 100644 --- a/Source/Shared/Storage/DiskStorage.swift +++ b/Source/Shared/Storage/DiskStorage.swift @@ -64,7 +64,7 @@ extension DiskStorage: StorageAware { public func entry(forKey key: Key) throws -> Entry { let filePath = makeFilePath(for: key) - let data = try Data(contentsOf: URL(fileURLWithPath: filePath)) + let data = try Data(contentsOf: URL(fileURLWithPath: filePath, isDirectory: false)) let attributes = try fileManager.attributesOfItem(atPath: filePath) let object = try transformer.fromData(data) @@ -99,7 +99,7 @@ extension DiskStorage: StorageAware { } public func removeExpiredObjects() throws { - let storageURL = URL(fileURLWithPath: path) + let storageURL = URL(fileURLWithPath: path, isDirectory: true) let resourceKeys: [URLResourceKey] = [ .isDirectoryKey, .contentModificationDateKey, @@ -167,7 +167,7 @@ extension DiskStorage { */ func makeFileName(for key: Key) -> String { if let key = key as? String { - let fileExtension = URL(fileURLWithPath: key).pathExtension + let fileExtension = (key as NSString).pathExtension let fileName = MD5(key) switch fileExtension.isEmpty { From 9efca9d8017c6c866ac146f82a1637c82c50755f Mon Sep 17 00:00:00 2001 From: Alexey Ivashko Date: Tue, 8 Jun 2021 12:31:12 +0300 Subject: [PATCH 16/27] Fix SPM warning in Xcode 13b1 --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index c6fcee4..c167e64 100644 --- a/Package.swift +++ b/Package.swift @@ -13,8 +13,8 @@ let package = Package( targets: [ .target( name: "Cache", - path: "Source", - exclude: ["Library/ImageWrapper.swift"]), + path: "Source" + ), .testTarget( name: "CacheTests", dependencies: ["Cache"], From 033457ce946725e7d8c9ed47fbd19c5f74282312 Mon Sep 17 00:00:00 2001 From: Abdullah Alhaider Date: Wed, 8 Dec 2021 13:01:51 +0500 Subject: [PATCH 17/27] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 137c354..45afb49 100644 --- a/README.md +++ b/README.md @@ -391,7 +391,7 @@ Alamofire.request("https://gameofthrones.org/mostFavoriteCharacter").responseStr ## What about images -If you want to load image into `UIImageView` or `NSImageView`, then we also have a nice gift for you. It's called [Imaginary](https://github.com/hyperoslo/Imaginary) and uses `Cache` under the hood to make you life easier when it comes to working with remote images. +If you want to load image into `UIImageView` or `NSImageView`, then we also have a nice gift for you. It's called [Imaginary](https://github.com/hyperoslo/Imaginary) and uses `Cache` under the hood to make your life easier when it comes to working with remote images. ## Installation From 33a693c45e8ad1db4e7be59c6181f076195fc34c Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Sun, 14 Aug 2022 13:48:44 -0400 Subject: [PATCH 18/27] Add objectExists to replace existsObject --- Source/Shared/Storage/AsyncStorage.swift | 11 +++++++++++ Source/Shared/Storage/StorageAware.swift | 16 ++++++++++++++++ Tests/iOS/Tests/Storage/AsyncStorageTests.swift | 2 +- Tests/iOS/Tests/Storage/SyncStorageTests.swift | 4 ++-- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Source/Shared/Storage/AsyncStorage.swift b/Source/Shared/Storage/AsyncStorage.swift index 032ea08..4f1c1b0 100644 --- a/Source/Shared/Storage/AsyncStorage.swift +++ b/Source/Shared/Storage/AsyncStorage.swift @@ -106,6 +106,7 @@ extension AsyncStorage { }) } + @available(*, deprecated, renamed: "objectExists(forKey:completion:)") public func existsObject( forKey key: Key, completion: @escaping (Result) -> Void) { @@ -115,6 +116,16 @@ extension AsyncStorage { })) }) } + + public func objectExists( + forKey key: Key, + completion: @escaping (Result) -> Void) { + object(forKey: key, completion: { (result: Result) in + completion(result.map({ _ in + return true + })) + }) + } } public extension AsyncStorage { diff --git a/Source/Shared/Storage/StorageAware.swift b/Source/Shared/Storage/StorageAware.swift index cbbb8ce..2b58941 100644 --- a/Source/Shared/Storage/StorageAware.swift +++ b/Source/Shared/Storage/StorageAware.swift @@ -47,8 +47,15 @@ public protocol StorageAware { Check if an object exist by the given key. - Parameter key: Unique key to identify the object. */ + @available(*, deprecated, renamed: "objectExists(forKey:)") func existsObject(forKey key: Key) throws -> Bool + /** + Check if an object exist by the given key. + - Parameter key: Unique key to identify the object. + */ + func objectExists(forKey key: Key) -> Bool + /** Removes all objects from the cache storage. */ @@ -80,6 +87,15 @@ public extension StorageAware { } } + func objectExists(forKey key: Key) -> Bool { + do { + let _: Value = try object(forKey: key) + return true + } catch { + return false + } + } + func isExpiredObject(forKey key: Key) throws -> Bool { do { let entry = try self.entry(forKey: key) diff --git a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift index 63158dc..1251d15 100644 --- a/Tests/iOS/Tests/Storage/AsyncStorageTests.swift +++ b/Tests/iOS/Tests/Storage/AsyncStorageTests.swift @@ -50,7 +50,7 @@ final class AsyncStorageTests: XCTestCase { } then("all are removed") { - intStorage.existsObject(forKey: "key-99", completion: { result in + intStorage.objectExists(forKey: "key-99", completion: { result in switch result { case .success: XCTFail() diff --git a/Tests/iOS/Tests/Storage/SyncStorageTests.swift b/Tests/iOS/Tests/Storage/SyncStorageTests.swift index 4c055b3..8d31f82 100644 --- a/Tests/iOS/Tests/Storage/SyncStorageTests.swift +++ b/Tests/iOS/Tests/Storage/SyncStorageTests.swift @@ -40,8 +40,8 @@ final class SyncStorageTests: XCTestCase { try intStorage.removeAll() } - try then("all are removed") { - XCTAssertFalse(try intStorage.existsObject(forKey: "key-99")) + then("all are removed") { + XCTAssertFalse(intStorage.objectExists(forKey: "key-99")) } } } From de764f82582d5bf55a86f4ee798bdb856403f492 Mon Sep 17 00:00:00 2001 From: pareshios Date: Tue, 2 May 2023 16:54:49 +0530 Subject: [PATCH 19/27] feat: Added support to remove only in memory cache --- Source/Shared/Storage/DiskStorage.swift | 2 ++ Source/Shared/Storage/HybridStorage.swift | 5 +++++ Source/Shared/Storage/MemoryStorage.swift | 5 +++++ Source/Shared/Storage/Storage.swift | 4 ++++ Source/Shared/Storage/StorageAware.swift | 5 +++++ Source/Shared/Storage/StorageObservationRegistry.swift | 3 ++- Source/Shared/Storage/SyncStorage.swift | 7 +++++++ 7 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Source/Shared/Storage/DiskStorage.swift b/Source/Shared/Storage/DiskStorage.swift index ca4db9a..b0bf9e3 100644 --- a/Source/Shared/Storage/DiskStorage.swift +++ b/Source/Shared/Storage/DiskStorage.swift @@ -145,6 +145,8 @@ extension DiskStorage: StorageAware { // Remove objects if storage size exceeds max size try removeResourceObjects(resourceObjects, totalSize: totalSize) } + + public func removeInMemoryObject(forKey key: Key) throws { } } extension DiskStorage { diff --git a/Source/Shared/Storage/HybridStorage.swift b/Source/Shared/Storage/HybridStorage.swift index 385980f..9844803 100644 --- a/Source/Shared/Storage/HybridStorage.swift +++ b/Source/Shared/Storage/HybridStorage.swift @@ -51,6 +51,11 @@ extension HybridStorage: StorageAware { notifyStorageObservers(about: .remove(key: key)) } + + public func removeInMemoryObject(forKey key: Key) throws { + memoryStorage.removeObject(forKey: key) + notifyStorageObservers(about: .removeInMemory(key: key)) + } public func setObject(_ object: Value, forKey key: Key, expiry: Expiry? = nil) throws { var keyChange: KeyChange? diff --git a/Source/Shared/Storage/MemoryStorage.swift b/Source/Shared/Storage/MemoryStorage.swift index 1adc46f..567bf31 100644 --- a/Source/Shared/Storage/MemoryStorage.swift +++ b/Source/Shared/Storage/MemoryStorage.swift @@ -67,6 +67,11 @@ extension MemoryStorage { cache.removeObject(forKey: WrappedKey(key)) keys.remove(key) } + + public func removeInMemoryObject(forKey key: Key) throws { + cache.removeObject(forKey: WrappedKey(key)) + keys.remove(key) + } public func entry(forKey key: Key) throws -> Entry { guard let capsule = cache.object(forKey: WrappedKey(key)) else { diff --git a/Source/Shared/Storage/Storage.swift b/Source/Shared/Storage/Storage.swift index e2d7c69..12b567f 100644 --- a/Source/Shared/Storage/Storage.swift +++ b/Source/Shared/Storage/Storage.swift @@ -43,6 +43,10 @@ public final class Storage { } extension Storage: StorageAware { + public func removeInMemoryObject(forKey key: Key) throws { + try self.syncStorage.removeInMemoryObject(forKey: key) + } + public var allKeys: [Key] { self.syncStorage.allKeys } diff --git a/Source/Shared/Storage/StorageAware.swift b/Source/Shared/Storage/StorageAware.swift index 2b58941..6ab7b3f 100644 --- a/Source/Shared/Storage/StorageAware.swift +++ b/Source/Shared/Storage/StorageAware.swift @@ -71,6 +71,11 @@ public protocol StorageAware { - Parameter key: Unique key to identify the object. */ func isExpiredObject(forKey key: Key) throws -> Bool + /** + Removes the object by the given key from cache in memory only. + - Parameter key: Unique key to identify the object. + */ + func removeInMemoryObject(forKey key: Key) throws } public extension StorageAware { diff --git a/Source/Shared/Storage/StorageObservationRegistry.swift b/Source/Shared/Storage/StorageObservationRegistry.swift index abd4927..788631e 100644 --- a/Source/Shared/Storage/StorageObservationRegistry.swift +++ b/Source/Shared/Storage/StorageObservationRegistry.swift @@ -28,11 +28,12 @@ public enum StorageChange: Equatable { case remove(key: Key) case removeAll case removeExpired + case removeInMemory(key: Key) } public func == (lhs: StorageChange, rhs: StorageChange) -> Bool { switch (lhs, rhs) { - case (.add(let key1), .add(let key2)), (.remove(let key1), .remove(let key2)): + case (.add(let key1), .add(let key2)), (.remove(let key1), .remove(let key2)), (.removeInMemory(let key1), .removeInMemory(let key2)): return key1 == key2 case (.removeAll, .removeAll), (.removeExpired, .removeExpired): return true diff --git a/Source/Shared/Storage/SyncStorage.swift b/Source/Shared/Storage/SyncStorage.swift index 51d15f0..b7bab94 100644 --- a/Source/Shared/Storage/SyncStorage.swift +++ b/Source/Shared/Storage/SyncStorage.swift @@ -61,6 +61,13 @@ extension SyncStorage: StorageAware { try innerStorage.removeExpiredObjects() } } + + public func removeInMemoryObject(forKey key: Key) throws { + try serialQueue.sync { + try self.innerStorage.removeInMemoryObject(forKey: key) + } + } + } public extension SyncStorage { From ca92308ff98c60bccf7e9422896bf40d320f5799 Mon Sep 17 00:00:00 2001 From: Mike Hill Date: Thu, 4 Jan 2024 10:27:09 -0500 Subject: [PATCH 20/27] Update TransformerFactory.swift to add visionOS (#1) --- Source/Shared/Library/TransformerFactory.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Shared/Library/TransformerFactory.swift b/Source/Shared/Library/TransformerFactory.swift index 00e4fe9..8ee64ab 100644 --- a/Source/Shared/Library/TransformerFactory.swift +++ b/Source/Shared/Library/TransformerFactory.swift @@ -9,7 +9,7 @@ public class TransformerFactory { return Transformer(toData: toData, fromData: fromData) } - #if os(iOS) || os(tvOS) || os(macOS) + #if os(iOS) || os(tvOS) || os(macOS) || os(visionOS) public static func forImage() -> Transformer { let toData: (Image) throws -> Data = { image in return try image.cache_toData().unwrapOrThrow(error: StorageError.transformerFail) From 8b895e5ee3522a3d2783108e3152a14548ea3035 Mon Sep 17 00:00:00 2001 From: Mike Hill Date: Thu, 4 Jan 2024 10:32:57 -0500 Subject: [PATCH 21/27] Update Types.swift to add visionOS --- Source/Shared/Library/Types.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Shared/Library/Types.swift b/Source/Shared/Library/Types.swift index 81e7a30..e8408db 100644 --- a/Source/Shared/Library/Types.swift +++ b/Source/Shared/Library/Types.swift @@ -1,4 +1,4 @@ -#if os(iOS) || os(tvOS) +#if os(iOS) || os(tvOS) || os(visionOS) import UIKit public typealias Image = UIImage #elseif os(watchOS) From 08608e367aa74a48e8f27ff44c6ba75a9f0f23aa Mon Sep 17 00:00:00 2001 From: Keita Watanabe Date: Wed, 21 Feb 2024 11:06:47 +0900 Subject: [PATCH 22/27] add PrivacyInfo.xcprivacy --- Source/PrivacyInfo.xcprivacy | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Source/PrivacyInfo.xcprivacy diff --git a/Source/PrivacyInfo.xcprivacy b/Source/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/Source/PrivacyInfo.xcprivacy @@ -0,0 +1,5 @@ + + + + + From bf2fd30e560d69736fceb27b2da7ff728ba7e320 Mon Sep 17 00:00:00 2001 From: Keita Watanabe Date: Wed, 21 Feb 2024 11:16:40 +0900 Subject: [PATCH 23/27] add resources --- Package.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index c167e64..30ce2b8 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.1 +// swift-tools-version:5.5 import PackageDescription @@ -13,7 +13,8 @@ let package = Package( targets: [ .target( name: "Cache", - path: "Source" + path: "Source", + resources: [.copy("PrivacyInfo.xcprivacy")] ), .testTarget( name: "CacheTests", From e32a01da7a847266a0f7268ed467cd4b0fdf794e Mon Sep 17 00:00:00 2001 From: Keita Watanabe Date: Wed, 21 Feb 2024 11:39:25 +0900 Subject: [PATCH 24/27] add NSPrivacyAccessedAPICategoryFileTimestamp for modificationDate and contentModificationDateKey --- Source/PrivacyInfo.xcprivacy | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/PrivacyInfo.xcprivacy b/Source/PrivacyInfo.xcprivacy index 0c67376..1d40f90 100644 --- a/Source/PrivacyInfo.xcprivacy +++ b/Source/PrivacyInfo.xcprivacy @@ -1,5 +1,17 @@ - + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPITypeReasons + + C617.1 + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + + + From 049ef1af424ecb999c4ba8f8c172714fead2ce74 Mon Sep 17 00:00:00 2001 From: Keita Watanabe Date: Wed, 21 Feb 2024 11:44:15 +0900 Subject: [PATCH 25/27] add NSPrivacyCollectedDataTypes --- Source/PrivacyInfo.xcprivacy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/PrivacyInfo.xcprivacy b/Source/PrivacyInfo.xcprivacy index 1d40f90..934f6ed 100644 --- a/Source/PrivacyInfo.xcprivacy +++ b/Source/PrivacyInfo.xcprivacy @@ -2,6 +2,8 @@ + NSPrivacyCollectedDataTypes + NSPrivacyAccessedAPITypes From 1014bad6967f8afcc2675e700e011894d8e93391 Mon Sep 17 00:00:00 2001 From: Greg Date: Fri, 22 Mar 2024 10:17:33 -0700 Subject: [PATCH 26/27] Include privacy manifest in podspec --- Cache.podspec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cache.podspec b/Cache.podspec index c74a7c9..927952a 100644 --- a/Cache.podspec +++ b/Cache.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Cache" s.summary = "Nothing but cache." - s.version = "7.0.0" + s.version = "7.0.1" s.homepage = "https://github.com/hyperoslo/Cache" s.license = 'MIT' s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" } @@ -16,6 +16,7 @@ Pod::Spec.new do |s| s.ios.source_files = 'Source/{iOS,Shared}/**/*' s.osx.source_files = 'Source/{Mac,Shared}/**/*' s.tvos.source_files = 'Source/{iOS,Shared}/**/*' + s.resources = 'Source/PrivacyInfo.xcprivacy' s.frameworks = 'Foundation' s.swift_version = '5.0' From ec9f3af90d63a8fb32cb2abe91d4c53f46d8dd93 Mon Sep 17 00:00:00 2001 From: Elvis <3lvis@users.noreply.github.com> Date: Tue, 26 Mar 2024 06:25:29 +0100 Subject: [PATCH 27/27] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45afb49..ee260eb 100644 --- a/README.md +++ b/README.md @@ -398,10 +398,11 @@ If you want to load image into `UIImageView` or `NSImageView`, then we also have ### Cocoapods **Cache** is available through [CocoaPods](http://cocoapods.org). To install -it, simply add the following line to your Podfile: +it or update it, use the following line to your Podfile: ```ruby -pod 'Cache' +pod 'Cache', :git => 'https://github.com/hyperoslo/Cache.git' + ``` ### Carthage