Everyone tries to implement a cache at some point in their iOS app’s lifecycle, and this is ours.

Overview

SPTPersistentCache

Coverage Status Documentation License CocoaPods Carthage compatible Spotify FOSS Slack Readme Score

Everyone tries to implement a cache at some point in their app’s lifecycle, and this is ours. This is a library that allows people to cache NSData with time to live (TTL) values and semantics for disk management.

  • 📱 iOS 8.0+
  • 💻 OS X 10.10+

Architecture 📐

SPTPersistentCache is designed as an LRU cache which makes use of the file system to store files as well as inserting a cache header into each file. This cache header allows us to track the TTL, last updated time, the redundancy check and more. This allows the cache to know how often a file is accessed, when it was made, whether it has become corrupt and allows decisions to be made on whether the cache is stale.

The use of different files rather than a single binary file allows multiple reads/writes on different files within the cache without complicated blocking logic. The cache header in each file can be removed quite easily, this can be seen in the SPTPersistentCacheViewer tool that is made to run on OS X.

Included here is also the ability to schedule garbage collection over the cache, which allows the user to ensure they are never using too much space for commonly cache data (such as images).

Installation 📥

SPTPersistentCache can be installed in a variety of ways including traditional static libraries and dynamic frameworks.

Static Library

Simply include SPTPersistentCache.xcodeproj in your App’s Xcode project, and link your app with the library in the “Build Phases” section.

CocoaPods

We are indexed on CocoaPods, which can be installed using Ruby gems:

$ gem install cocoapods

Then simply add SPTPersistentCache to your Podfile.

pod 'SPTPersistentCache', '~> 1.1.1'

Lastly let CocoaPods do its thing by running:

$ pod install

Carthage

We support Carthage and provide pre-built binary frameworks for all new releases. Start by making sure you have the latest version of Carthage installed, e.g. using Homebrew:

$ brew update
$ brew install carthage

You will also need to add SPTPersistentCache to your Cartfile:

github "spotify/SPTPersistentCache" ~> 1.1.1

After that is all said and done, let Carthage pull in SPTPersistentCache like so:

$ carthage update

Next up, you need to add the framework to the Xcode project of your App. Lastly link the framework with your App and copy it to the App’s Frameworks directory under the “Build Phases”.

Usage example 👀

For an example of this framework's usage, see the demo application SPTPersistentCacheDemo in SPTPersistentCache.xcworkspace.

Creating the SPTPersistentCache

It is best to use different caches for different types of data you want to store, and not just one big cache for your entire application. However, only create one SPTPersistentCache instance for each cache, otherwise you might encounter anomalies when the two different caches end up writing to the same file.

NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingString:@"com.spotify.demo.image.cache"];

SPTPersistentCacheOptions *options = [SPTPersistentCacheOptions new];
options.cachePath = cachePath;
options.cacheIdentifier = @"com.spotify.demo.image.cache";
options.defaultExpirationPeriod = 60 * 60 * 24 * 30; // 30 days
options.garbageCollectionInterval = (NSUInteger)(1.5 * SPTPersistentCacheDefaultGCIntervalSec);
options.sizeConstraintBytes = 1024 * 1024 * 10; // 10 MiB
options.debugOutput = ^(NSString *string) {
    NSLog(@"%@", string);
};

SPTPersistentCache *cache = [[SPTPersistentCache alloc] initWithOptions:options];

Storing Data in the SPTPersistentCache

When storing data in the SPTPersistentCache, you must be aware of the file system semantics. The key will be used as the file name within the cache directory to save. The reason we did not implement a hash function under the hood is because we wanted to give the option of what hash function to use to the user, so it is recommended that when you insert data into the cache for a key, that you create the key using your own hashing function (at Spotify we use SHA1, although better hashing functions exist these days). If you want the cache record, i.e. file, to exist without any TTL make sure you store it as a locked file.

NSData *data = UIImagePNGRepresentation([UIImage imageNamed:@"my-image"]);
NSString *key = @"MyHashValue";
[self.cache storeData:data
              forKey:key
              locked:YES
        withCallback:^(SPTPersistentCacheResponse *cacheResponse) {
             NSLog(@"cacheResponse = %@", cacheResponse);
        } onQueue:dispatch_get_main_queue()];

Loading Data in the SPTPersistentCache

In order to restore data you already have saved in the SPTPersistentCache, you simply feed it the same key that you used to store the data.

NSString *key = @"MyHashValue";
[self.cache loadDataForKey:key withCallback:^(SPTPersistentCacheResponse *cacheResponse) {
    UIImage *image = [UIImage imageWithData:cacheResponse.record.data];
} onQueue:dispatch_get_main_queue()];

Note that if the TTL has expired, you will not receive a result.

Locking/Unlocking files

Sometimes you may want to lock a file in SPTPersistentCache long after it has been expired by its TTL. An example of where we do this at Spotify is images relating to the cover art of the songs you have offlined (we wouldn't want to invalidate these images when you are away on vacation). When you have locked a file, you must make sure you unlock it eventually, otherwise it will stay around forever. A lock is basically a contract between the cache and it's consumer that the data will remain in the cache until it is explicitly unlocked.

NSString *key = @"MyHashValue";
[self.cache lockDataForKeys:@[key] callback:nil queue:nil];
// Now my data is safe within the arms of the cache
[self.cache unlockDataForKeys:@[key] callback:nil queue:nil];
// Now my data will be subject to its original TTL

Note: That if you exceed the constrained size in your cache, even locked files can be subject to pruning.

Using the garbage collector

The garbage collection functionality in SPTPersistentCache is not automatically run, you have to call it manually using scheduleGarbageCollector.

[self.cache scheduleGarbageCollection];

This will schedule garbage collection on the interval you supplied in the SPTPersistentCacheOptions class, by default this is the SPTPersistentCacheDefaultExpirationTimeSec external variable. To unschedule the garbage collector simply call the opposite function unscheduleGarbageCollector.

[self.cache unscheduleGarbageCollection];

Manually managing cache usage

There are times when you may want to pre-empty a garbage collection that is scheduled, wipe the cache or simply remove all locked/unlocked files indiscriminantly. To support these cases we have provided methods to do just this.

// Lets wipe all the files we haven't explicitly locked
[self.cache wipeUnlockedFiles];
NSLog(@"Size = %@", @(self.cache.totalUsedSizeInBytes));
// Now let's wipe all the files we have explicitly locked
[self.cache wipeLockedFiles];
NSLog(@"Size = %@", @(self.cache.totalUsedSizeInBytes));
// Why not just wipe the entire cache?
[self.cache prune];
NSLog(@"Size = %@", @(self.cache.totalUsedSizeInBytes));

Background story 📖

At Spotify we began to standardise the way we handled images in a centralised way, and in doing so we initially created a component that was handling images and their caching. But then our requirements changed, and we began to need caching for our backend calls and preview MP3 downloads as well. In doing so, we managed to separate out our caching logic into a generic component that can be used for any piece of data.

Thus we boiled down what we needed in a cache, the key features being TTL on specific pieces of data, disk management to make sure we don't use too much, and protections against data corruption. It also became very useful to separate different caches into separate files (such as images and mp3s), in order to easily measure how much space each item is taking up.

Tools 🔨

Having a nice GUI tool to inspect the contents of an SPTPersistentCache directory would be nice, so we made one. In this repository we have a project called SPTPersistentCacheViewer.xcodeproj which is part of the SPTPersistentCache.xcworkspace. When you open it and build it for OS X, you will see a GUI that allows you to inspect the contents of a cache, including individual items TTL and payload size.

SPTPersistentCacheViewer

Contributing 📬

Contributions are welcomed, have a look at the CONTRIBUTING.md document for more information.

License 📝

The project is available under the Apache 2.0 license.

Acknowledgements

Comments
  • Update to use a NSOperationQueue instead of GCD

    Update to use a NSOperationQueue instead of GCD

    After analyzing some performance numbers, it seemed that a large number of interactions on the persistent cache where causing long read times. It turns out that you can flood the execution queue with things like unlocking or deleting and they would block operations like reads until the queue finished all of the operations that were enqueued before the read. The idea with this PR is to use a priority queue in the form of NSOperationQueue to allow reads to have a higher priority for reads than for unlocks or deletes.

    I added some timing and a performance test in SPTPersistentCachePerformance that creates 200 locked items in the cache and then enqueues 200 unlocks followed immediately by 200 reads. I ran the test 3 times, first on the current GCD version and then on 2 versions using the NSOperationQueue, first with normal priority for all operation types and then with a high priority for reads and a low priority for unlocks.

    Here are the times of the read sitting in the queue before execution begins. The test was run on an iPhone 6 running iOS 9.3.5. All times are in milliseconds.

    | Type | Queue Average | Queue Min | Queue Max | | --- | --- | --- | --- | | Current GCD | 372.1658762 | 51.09783 | 968.4579 | | NSOperationQueue Normal | 348.2155414 | 33.32054 | 963.0783 | | NSOperationQueue Priority | 328.9230705 | 12.22912 | 909.4095 |

    This shows close to a 12% increase in the average queue time and a 6% improvement over the max wait time.

    There are some backwards compatibility breaking changes in this that modify a few methods (such as removeDataForKeys, prune, wipeLockedFiles, and wipeNonLockedFiles) to be asynchronous instead of synchronous.

    enhancement api breaking 
    opened by chrisbtreats 11
  • Love to SPTPersistentCacheRecordHeaderType

    Love to SPTPersistentCacheRecordHeaderType

    • Create Make function for SPTPersistentCacheRecordHeaderType

      and unit test it!

    • Rename SPTPersistentCacheRecordHeaderType to SPTPersistentCacheRecordHeader.

      Following the convention of Apple's structures, dropped the type suffix of SPTPersistentCacheRecordHeaderType.

    opened by ChocoChipset 9
  • "Messaging unqualified id" error in Xcode 11b1

    Buildng the app with Xcode 11b1 results in 3 of the following errors:

    Messaging unqualified id
    

    in:

    SPTPersistentCacheOptions.mL111 SPTPersistentCache.mL967 SPTPersistentCache.mL986

    I admit I am a bit miffed on what the actual problem is. Despite a few years of exclusive Swift development, I feel like I should be able to infer what it doesn't like about the object being messaged in these 3 cases.

    In the first, init is triggering the warning. In the second two, integerValue.

    opened by erikkerber 5
  • Update to use a NSOperationQueue instead of GCD

    Update to use a NSOperationQueue instead of GCD

    Reopening version of https://github.com/spotify/SPTPersistentCache/pull/78

    After analyzing some performance numbers, it seemed that a large number of interactions on the persistent cache where causing long read times. It turns out that you can flood the execution queue with things like unlocking or deleting and they would block operations like reads until the queue finished all of the operations that were enqueued before the read. The idea with this PR is to use a priority queue in the form of NSOperationQueue to allow reads to have a higher priority for reads than for unlocks or deletes.

    I added some timing and a performance test in SPTPersistentCachePerformance that creates 200 locked items in the cache and then enqueues 200 unlocks followed immediately by 200 reads. I ran the test 3 times, first on the current GCD version and then on 2 versions using the NSOperationQueue, first with normal priority for all operation types and then with a high priority for reads and a low priority for unlocks.

    Here are the times of the read sitting in the queue before execution begins. The test was run on an iPhone 6 running iOS 9.3.5. All times are in milliseconds.

    | Type | Queue Average | Queue Min | Queue Max | | --- | --- | --- | --- | | Current GCD | 372.1658762 | 51.09783 | 968.4579 | | NSOperationQueue Normal | 348.2155414 | 33.32054 | 963.0783 | | NSOperationQueue Priority | 328.9230705 | 12.22912 | 909.4095 |

    This shows close to a 12% increase in the average queue time and a 6% improvement over the max wait time.

    There are some backwards compatibility breaking changes in this that modify a few methods (such as removeDataForKeys, prune, wipeLockedFiles, and wipeNonLockedFiles) to be asynchronous instead of synchronous.

    api breaking 
    opened by chrisbtreats 5
  • Wrong nullability flags on SPTPersistentCacheResponse

    Wrong nullability flags on SPTPersistentCacheResponse

    The interface of SPTPersistentCacheResponse tells the compiler that all its properties are NONNULL but it's obvious that it's not true, you cannot have result and error instantiated at the same time.

    This is a big issue in Swift3 projects, because if you check directly the presence of record without checking result before, the app will crash at runtime, because the compiler cannot let you use optional access to these properties.

    A corrected version of it could be

    @interface SPTPersistentCacheResponse : NSObject
    
    /**
     * @see SPTPersistentCacheResponseCode
     */
    @property (nonatomic, assign, readonly) SPTPersistentCacheResponseCode result;
    /**
     * Defines error of response if appliable
     */
    @property (nonatomic, strong, readonly, nullable) NSError *error;
    /**
     * @see SPTPersistentCacheRecord
     */
    @property (nonatomic, strong, readonly, nullable) SPTPersistentCacheRecord *record;
    
    @end
    
    bug swift compatibility 
    opened by dral3x 4
  • currentTimeCallback, do we need it?

    currentTimeCallback, do we need it?

    Just wondering if we really need the currentTimeCallback parameter in SPTPersistentCacheOptions.

    It makes the API more complex and I'm not sure if it's a common to require something different than the default implementation we provide.

    @spotify/objc-dev

    question 
    opened by ChocoChipset 4
  • Refactor scheduling logic

    Refactor scheduling logic

    • Move all timer logic to SPTPersistentCacheTimerProxy.

      Encapsulate all logic regarding timing to the SPTPersistentCacheTimerProxy class. Also unit test it. ;)

    • Rename SPTPersistentCacheTimerProxy to SPTPersistentCacheGarbageCollectorScheduler

      After moving the timer logic to SPTPersistentCacheTimerProxy, this class is no longer a timer proxy, but an object in charge of scheduling the garbage collection. Hence, rename it to the more descriptive name SPTPersistentCacheGarbageCollectorScheduler.

    enhancement refactor 
    opened by ChocoChipset 4
  • Linked missing implementation header to .pbxproj

    Linked missing implementation header to .pbxproj

    Currently SPTPersistentCache.h imports SPTPersistentCacheImplementation.h, however it has not been linked in the .pbxproj thus not being included in headers when built

    opened by damiankolasinski 3
  • Create Codecov config file

    Create Codecov config file

    With Codecov.io’s latest update they’ve migrated to using a .yaml config file in the repo. Instead of having the config stored in their database.

    This PR migrates our settings from their database to a file in our repo.

    ci 
    opened by rastersize 3
  • Make min free disk space portion adjustable by clients of the library

    Make min free disk space portion adjustable by clients of the library

    Currently, SPTPersistentCacheFileManager calculates the minimum free disk space by 0.1 * total disk space. This is unreasonable for the sizes of the current device storages. This pull request makes it possible for clients to change the portion of the total disk space that should be free.

    opened by tmpit 0
  • Deployment target triggers a compiler warning in Xcode 12+

    Deployment target triggers a compiler warning in Xcode 12+

    Xcode 12 dropped support for iOS 8: https://developer.apple.com/documentation/xcode-release-notes/xcode-12-release-notes

    When compiling the project in Xcode for the simulator I get the following warning:

    The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.
    

    I can see that from the xcconfig file that deployment target is explicitly set to 8.0: https://github.com/spotify/SPTPersistentCache/blob/master/ci/spotify_os.xcconfig#L21

    I've increased to 12.0 locally for my project and it all builds ok. However I do not want to deviate the fork from the Spotify repo.

    Would it be possible to bump to 9.0 at least please?

    opened by parrotbait 0
  • Declares data property of SPTPersistentCacheRecord as copy

    Declares data property of SPTPersistentCacheRecord as copy

    data property of SPTPersistentCacheRecord is declared as strong. This could lead to problem when instances of SPTPersistentCacheRecord are created with NSMutableData. PR adds failing test case to show this behaviour and fix for it.

    opened by valeriyvan 0
  • Doesn't compile under Xcode 10

    Doesn't compile under Xcode 10

    @8W9aG Thank you in advance for taking a look at this.

    SPTPersistentCache doesn't compile via standard Carthage pull under Xcode 10.

    The error is:

    CompileC /Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/Objects-normal/armv7/SPTPersistentCache.o /Users/z002r44/Dustin-Harmony-iOS/Carthage/Checkouts/SPTPersistentCache/Sources/SPTPersistentCache.m normal armv7 objective-c com.apple.compilers.llvm.clang.1_0.compiler (in target: SPTPersistentCache-iOS)
        cd /Users/z002r44/Dustin-Harmony-iOS/Carthage/Checkouts/SPTPersistentCache/SPTPersistentCacheFramework
        export LANG=en_US.US-ASCII
        /Users/z002r44/Downloads/Xcode10.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c -arch armv7 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -std=gnu11 -fobjc-arc -fmodules -gmodules -fmodules-cache-path=/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/ModuleCache.noindex -fno-autolink -fmodules-prune-interval=86400 -fmodules-prune-after=345600 -fbuild-session-file=/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/ModuleCache.noindex/Session.modulevalidation -fmodules-validate-once-per-build-session -Wnon-modular-include-in-framework-module -Werror=non-modular-include-in-framework-module -fmodule-name=SPTPersistentCache -Wno-trigraphs -fpascal-strings -Os -fno-common -Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Wmissing-field-initializers -Wmissing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code -Wnullable-to-nonnull-conversion -Wimplicit-atomic-properties -Werror=deprecated-objc-isa-usage -Wno-objc-interface-ivars -Werror=objc-root-class -Warc-repeated-use-of-weak -Wno-arc-maybe-repeated-use-of-weak -Wexplicit-ownership-type -Wimplicit-retain-self -Wduplicate-method-match -Wmissing-braces -Wparentheses -Wswitch -Wunused-function -Wunused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wconditional-uninitialized -Wunknown-pragmas -Wshadow -Wfour-char-constants -Wconversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wfloat-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wassign-enum -Wsign-compare -Wshorten-64-to-32 -Wpointer-sign -Wnewline-eof -Wselector -Wstrict-selector-match -Wundeclared-selector -Wdeprecated-implementations -DNS_BLOCK_ASSERTIONS=1 -DOBJC_OLD_DISPATCH_PROTOTYPES=0 -isysroot /Users/z002r44/Downloads/Xcode10.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.sdk -fstrict-aliasing -Wprotocol -Wdeprecated-declarations -miphoneos-version-min=8.0 -g -Wsign-conversion -Winfinite-recursion -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wno-semicolon-before-method-body -fembed-bitcode -iquote /Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/SPTPersistentCache-generated-files.hmap -I/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/SPTPersistentCache-own-target-headers.hmap -I/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/SPTPersistentCache-all-non-framework-target-headers.hmap -ivfsoverlay /Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/all-product-headers.yaml -iquote /Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/SPTPersistentCache-project-headers.hmap -I/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/BuildProductsPath/Release-iphoneos/include -I../include -I/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/DerivedSources/armv7 -I/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/DerivedSources -Weverything -Wno-error=deprecated -Wno-objc-missing-property-synthesis -Wno-gnu-conditional-omitted-operand -Wno-gnu -Wno-documentation-unknown-command -Wno-reserved-id-macro -Wno-auto-import -Wno-missing-variable-declarations -Wno-c++98-compat -Werror -Wno-direct-ivar-access -Wno-padded -F/Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/BuildProductsPath/Release-iphoneos -MMD -MT dependencies -MF /Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/Objects-normal/armv7/SPTPersistentCache.d --serialize-diagnostics /Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/Objects-normal/armv7/SPTPersistentCache.dia -c /Users/z002r44/Dustin-Harmony-iOS/Carthage/Checkouts/SPTPersistentCache/Sources/SPTPersistentCache.m -o /Users/z002r44/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10A254a/SPTPersistentCache/1.1.1/Build/Intermediates.noindex/ArchiveIntermediates/SPTPersistentCache-iOS/IntermediateBuildFilesPath/SPTPersistentCacheFramework.build/Release-iphoneos/SPTPersistentCache-iOS.build/Objects-normal/armv7/SPTPersistentCache.o
    /Users/z002r44/Dustin-Harmony-iOS/Carthage/Checkouts/SPTPersistentCache/Sources/SPTPersistentCache.m:737:80: error: implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'ObjectType _Nonnull' (aka 'id') [-Werror,-Wnullable-to-nonnull-conversion]
                                            userInfo:@{ NSLocalizedDescriptionKey: @(errorString) }];
                                                                                   ^
    /Users/z002r44/Dustin-Harmony-iOS/Carthage/Checkouts/SPTPersistentCache/Sources/SPTPersistentCache.m:965:30: warning: messaging unqualified id [-Wobjc-messaging-id]
            currentCacheSize += [image[SPTDataCacheFileAttributesKey][NSFileSize] integerValue];
                                 ^
    /Users/z002r44/Dustin-Harmony-iOS/Carthage/Checkouts/SPTPersistentCache/Sources/SPTPersistentCache.m:984:30: warning: messaging unqualified id [-Wobjc-messaging-id]
            currentCacheSize -= [image[SPTDataCacheFileAttributesKey][NSFileSize] integerValue];
    

    I put in a PR to fix, but can't figure out why the CI process fails on the PR. Would like to use SPTPersistentCache from master if possible, not from a fork that I took: https://github.com/DanEdgarTarget/SPTPersistentCache

    Thank you for any help.

    opened by DanEdgarTarget 2
  • Remove deprecated interfaces

    Remove deprecated interfaces

    This has been deprecated for over two years.

    If we merge this it’s a semver MAJOR change, so I guess the question is if we want anything else in a 2.0.0 release.

    @rastersize @8W9aG @dflems

    opened by JensAyton 3
Releases(1.1.1)
Owner
Spotify
Spotify
Cache - Nothing but Cache.

Cache doesn't claim to be unique in this area, but it's not another monster library that gives you a god's power. It does nothing but caching, but it does it well. It offers a good public API with out-of-box implementations and great customization possibilities. Cache utilizes Codable in Swift 4 to perform serialization.

HyperRedink 2.7k Dec 28, 2022
Apple Asset Cache (Content Cache) Tools

AssetCacheTool A library and tool for interacting with both the local and remote asset caches. This is based on research I did a few years ago on the

Kenneth Endfinger 21 Jan 5, 2023
Rock - Paper - Scissors game. CPU gives you a sign and asks to win or lose your move. Than you have to decide witch sign do you choose to score a point

RockPaperScissors 2nd challange from HackingWithSwift.com. The CPU gives you a sign (rock, paper or scissors) and asks you either to win or to lose th

Pavel Surový 0 Nov 27, 2021
MrCode is a simple GitHub iPhone App that can cache Markdown content (include images in HTML) for read it later.

MrCode is a simple GitHub iPhone App that can cache Markdown content (include images in HTML) for read it later.

hao 448 Dec 19, 2022
Cachyr A typesafe key-value data cache for iOS, macOS, tvOS and watchOS written in Swift.

Cachyr A typesafe key-value data cache for iOS, macOS, tvOS and watchOS written in Swift. There already exists plenty of cache solutions, so why creat

Norsk rikskringkasting (NRK) 124 Nov 24, 2022
Carlos - A simple but flexible cache, written in Swift for iOS 13+ and WatchOS 6 apps.

Carlos A simple but flexible cache, written in Swift for iOS 13+ and WatchOS 6 apps. Breaking Changes Carlos 1.0.0 has been migrated from PiedPiper de

National Media & Tech 628 Dec 3, 2022
Fast, non-deadlocking parallel object cache for iOS, tvOS and OS X

PINCache Fast, non-deadlocking parallel object cache for iOS and OS X. PINCache is a fork of TMCache re-architected to fix issues with deadlocking cau

Pinterest 2.6k Dec 28, 2022
CachyKit - A Caching Library is written in Swift that can cache JSON, Image, Zip or AnyObject with expiry date/TTYL and force refresh.

Nice threadsafe expirable cache management that can cache any object. Supports fetching from server, single object expire date, UIImageView loading etc.

Sadman Samee 122 Dec 28, 2022
Track is a thread safe cache write by Swift. Composed of DiskCache and MemoryCache which support LRU.

Track is a thread safe cache write by Swift. Composed of DiskCache and MemoryCache which support LRU. Features Thread safe: Implement by dispatch_sema

Cheer 268 Nov 21, 2022
🏈 Cache CocoaPods for faster rebuild and indexing Xcode project.

Motivation Working on a project with a huge amount of pods I had some troubles: - Slow and unnecessary indexing of pods targets, which implementation

Vyacheslav Khorkov 487 Jan 5, 2023
SwiftyCache is a dynamic and auto-managed cache written in Swift

SwiftyCache is a dynamic and auto-managed cache written in Swift. Unlike a simple cache system, it allows you to keep some data even in different executions. Guaranteeing persistence, when desired, without increasing the time required to save or recover data.

Antonio Guerra 3 Aug 28, 2022
A lightweight generic cache for iOS written in Swift with extra love for images.

Haneke is a lightweight generic cache for iOS and tvOS written in Swift 4. It's designed to be super-simple to use. Here's how you would initalize a J

Haneke 5.2k Dec 29, 2022
High performance cache framework for iOS.

YYCache High performance cache framework for iOS. (It's a component of YYKit) Performance You may download and compile the latest version of sqlite an

null 2.3k Dec 16, 2022
MemoryCache - type-safe, thread-safe memory cache class in Swift

MemoryCache is a memory cache class in swift. The MemoryCache class incorporates LRU policies, which ensure that a cache doesn’t

Yusuke Morishita 74 Nov 24, 2022
UITableView cell cache that cures scroll-lags on cell instantiating

UITableView + Cache https://github.com/Kilograpp/UITableView-Cache UITableView cell cache that cures scroll-lags on a cell instantiating. Introduction

null 73 Aug 6, 2021
💾 Simple memory & disk cache

Cache ?? Simple memory & disk cache Usage ??‍?? Default let cache = Cache<String>() try memory.save("MyValue", forKey: "MyKey") let cached = try cac

SeongHo Hong 2 Feb 28, 2022
Cache library for videos for React Native

@lowkey/react-native-cache Cache everything Installation npm install @lowkey/react-native-cache Usage import ReactNativeCache from "@lowkey/react-nati

Max Prokopenko 1 Oct 1, 2021
CachedAsyncImage is the simplest way to add cache to your AsyncImage.

CachedAsyncImage ??️ CachedAsyncImage is AsyncImage, but with cache capabilities. Usage CachedAsyncImage has the exact same API and behavior as AsyncI

Lorenzo Fiamingo 278 Jan 5, 2023
XCRemoteCache is a remote cache tool for Xcode projects.

XCRemoteCache is a remote cache tool for Xcode projects. It reuses target artifacts generated on a remote machine, served from a simple REST server. H

Spotify 737 Dec 27, 2022