commit f93527d8ccc3f88b2e0697e9fd78be28d40a3a26 Author: Christopher Luu Date: Tue Jan 26 15:05:06 2016 -0500 Initial source commit diff --git a/CacheIsKing-iOS/CacheIsKing.h b/CacheIsKing-iOS/CacheIsKing.h new file mode 100644 index 0000000..558fd2e --- /dev/null +++ b/CacheIsKing-iOS/CacheIsKing.h @@ -0,0 +1,19 @@ +// +// CacheIsKing-iOS.h +// CacheIsKing-iOS +// +// Created by Christopher Luu on 1/26/16. +// +// + +#import + +//! Project version number for CacheIsKing-iOS. +FOUNDATION_EXPORT double CacheIsKingVersionNumber; + +//! Project version string for CacheIsKing-iOS. +FOUNDATION_EXPORT const unsigned char CacheIsKingVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/CacheIsKing-iOS/Info.plist b/CacheIsKing-iOS/Info.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/CacheIsKing-iOS/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/CacheIsKing-tvOS/CacheIsKing.h b/CacheIsKing-tvOS/CacheIsKing.h new file mode 100644 index 0000000..3bd2407 --- /dev/null +++ b/CacheIsKing-tvOS/CacheIsKing.h @@ -0,0 +1,19 @@ +// +// CacheIsKing-tvOS.h +// CacheIsKing-tvOS +// +// Created by Christopher Luu on 1/26/16. +// +// + +#import + +//! Project version number for CacheIsKing-tvOS. +FOUNDATION_EXPORT double CacheIsKingsVersionNumber; + +//! Project version string for CacheIsKing-tvOS. +FOUNDATION_EXPORT const unsigned char CacheIsKingVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/CacheIsKing-tvOS/Info.plist b/CacheIsKing-tvOS/Info.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/CacheIsKing-tvOS/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/CacheIsKing.podspec b/CacheIsKing.podspec new file mode 100644 index 0000000..1ebd83d --- /dev/null +++ b/CacheIsKing.podspec @@ -0,0 +1,16 @@ +Pod::Spec.new do |s| + s.name = 'CacheIsKing' + s.version = '0.0.1' + s.license = 'MIT' + s.summary = 'A simple cache that can hold Swift items' + s.homepage = 'https://github.com/nuudles/CacheIsKing' + s.authors = { 'Christopher Luu' => 'nuudles@gmail.com' } + s.source = { :git => 'https://github.com/nuudles/CacheIsKing.git', :tag => s.version } + + s.ios.deployment_target = '8.0' + s.tvos.deployment_target = '9.0' + + s.source_files = 'Source/*.swift' + + s.requires_arc = true +end diff --git a/CacheIsKing.xcodeproj/project.pbxproj b/CacheIsKing.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6108eb2 --- /dev/null +++ b/CacheIsKing.xcodeproj/project.pbxproj @@ -0,0 +1,663 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 30D75C271C57CE1400F4E62D /* CacheIsKing.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D75C261C57CE1400F4E62D /* CacheIsKing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30D75C2E1C57CEC500F4E62D /* KingCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C2D1C57CEC500F4E62D /* KingCache.swift */; }; + 30D75C371C57D17400F4E62D /* CacheIsKing.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D75C361C57D17400F4E62D /* CacheIsKing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30D75C3C1C57D1A300F4E62D /* KingCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C2D1C57CEC500F4E62D /* KingCache.swift */; }; + 30D75C441C57D2CA00F4E62D /* CacheIsKingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C431C57D2CA00F4E62D /* CacheIsKingTests.swift */; }; + 30D75C461C57D2CA00F4E62D /* CacheIsKing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30D75C231C57CE1400F4E62D /* CacheIsKing.framework */; }; + 30D75C4D1C57F1C800F4E62D /* AnyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */; }; + 30D75C4E1C58033B00F4E62D /* AnyKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 30D75C471C57D2CA00F4E62D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 30D75C181C57CD6100F4E62D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 30D75C221C57CE1400F4E62D; + remoteInfo = "CacheIsKing-iOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 30D75C231C57CE1400F4E62D /* CacheIsKing.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CacheIsKing.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 30D75C261C57CE1400F4E62D /* CacheIsKing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CacheIsKing.h; sourceTree = ""; }; + 30D75C281C57CE1400F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 30D75C2D1C57CEC500F4E62D /* KingCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KingCache.swift; sourceTree = ""; }; + 30D75C341C57D17400F4E62D /* CacheIsKing.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CacheIsKing.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 30D75C361C57D17400F4E62D /* CacheIsKing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CacheIsKing.h; sourceTree = ""; }; + 30D75C381C57D17400F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 30D75C411C57D2CA00F4E62D /* CacheIsKingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CacheIsKingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 30D75C431C57D2CA00F4E62D /* CacheIsKingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheIsKingTests.swift; sourceTree = ""; }; + 30D75C451C57D2CA00F4E62D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyKey.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 30D75C1F1C57CE1400F4E62D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30D75C301C57D17400F4E62D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30D75C3E1C57D2CA00F4E62D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 30D75C461C57D2CA00F4E62D /* CacheIsKing.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 30D75C171C57CD6100F4E62D = { + isa = PBXGroup; + children = ( + 30D75C2C1C57CEB600F4E62D /* Source */, + 30D75C251C57CE1400F4E62D /* CacheIsKing-iOS */, + 30D75C351C57D17400F4E62D /* CacheIsKing-tvOS */, + 30D75C421C57D2CA00F4E62D /* CacheIsKingTests */, + 30D75C241C57CE1400F4E62D /* Products */, + ); + sourceTree = ""; + }; + 30D75C241C57CE1400F4E62D /* Products */ = { + isa = PBXGroup; + children = ( + 30D75C231C57CE1400F4E62D /* CacheIsKing.framework */, + 30D75C341C57D17400F4E62D /* CacheIsKing.framework */, + 30D75C411C57D2CA00F4E62D /* CacheIsKingTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 30D75C251C57CE1400F4E62D /* CacheIsKing-iOS */ = { + isa = PBXGroup; + children = ( + 30D75C261C57CE1400F4E62D /* CacheIsKing.h */, + 30D75C281C57CE1400F4E62D /* Info.plist */, + ); + path = "CacheIsKing-iOS"; + sourceTree = ""; + }; + 30D75C2C1C57CEB600F4E62D /* Source */ = { + isa = PBXGroup; + children = ( + 30D75C2D1C57CEC500F4E62D /* KingCache.swift */, + 30D75C4C1C57F1C800F4E62D /* AnyKey.swift */, + ); + path = Source; + sourceTree = ""; + }; + 30D75C351C57D17400F4E62D /* CacheIsKing-tvOS */ = { + isa = PBXGroup; + children = ( + 30D75C361C57D17400F4E62D /* CacheIsKing.h */, + 30D75C381C57D17400F4E62D /* Info.plist */, + ); + path = "CacheIsKing-tvOS"; + sourceTree = ""; + }; + 30D75C421C57D2CA00F4E62D /* CacheIsKingTests */ = { + isa = PBXGroup; + children = ( + 30D75C431C57D2CA00F4E62D /* CacheIsKingTests.swift */, + 30D75C451C57D2CA00F4E62D /* Info.plist */, + ); + path = CacheIsKingTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 30D75C201C57CE1400F4E62D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 30D75C271C57CE1400F4E62D /* CacheIsKing.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30D75C311C57D17400F4E62D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 30D75C371C57D17400F4E62D /* CacheIsKing.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 30D75C221C57CE1400F4E62D /* CacheIsKing-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 30D75C291C57CE1400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-iOS" */; + buildPhases = ( + 30D75C1E1C57CE1400F4E62D /* Sources */, + 30D75C1F1C57CE1400F4E62D /* Frameworks */, + 30D75C201C57CE1400F4E62D /* Headers */, + 30D75C211C57CE1400F4E62D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "CacheIsKing-iOS"; + productName = "CacheIsKing-iOS"; + productReference = 30D75C231C57CE1400F4E62D /* CacheIsKing.framework */; + productType = "com.apple.product-type.framework"; + }; + 30D75C331C57D17400F4E62D /* CacheIsKing-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 30D75C391C57D17400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-tvOS" */; + buildPhases = ( + 30D75C2F1C57D17400F4E62D /* Sources */, + 30D75C301C57D17400F4E62D /* Frameworks */, + 30D75C311C57D17400F4E62D /* Headers */, + 30D75C321C57D17400F4E62D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "CacheIsKing-tvOS"; + productName = "CacheIsKing-tvOS"; + productReference = 30D75C341C57D17400F4E62D /* CacheIsKing.framework */; + productType = "com.apple.product-type.framework"; + }; + 30D75C401C57D2CA00F4E62D /* CacheIsKingTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 30D75C491C57D2CA00F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKingTests" */; + buildPhases = ( + 30D75C3D1C57D2CA00F4E62D /* Sources */, + 30D75C3E1C57D2CA00F4E62D /* Frameworks */, + 30D75C3F1C57D2CA00F4E62D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 30D75C481C57D2CA00F4E62D /* PBXTargetDependency */, + ); + name = CacheIsKingTests; + productName = CacheIsKingTests; + productReference = 30D75C411C57D2CA00F4E62D /* CacheIsKingTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 30D75C181C57CD6100F4E62D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0720; + TargetAttributes = { + 30D75C221C57CE1400F4E62D = { + CreatedOnToolsVersion = 7.2; + }; + 30D75C331C57D17400F4E62D = { + CreatedOnToolsVersion = 7.2; + }; + 30D75C401C57D2CA00F4E62D = { + CreatedOnToolsVersion = 7.2; + }; + }; + }; + buildConfigurationList = 30D75C1B1C57CD6100F4E62D /* Build configuration list for PBXProject "CacheIsKing" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 30D75C171C57CD6100F4E62D; + productRefGroup = 30D75C241C57CE1400F4E62D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 30D75C221C57CE1400F4E62D /* CacheIsKing-iOS */, + 30D75C331C57D17400F4E62D /* CacheIsKing-tvOS */, + 30D75C401C57D2CA00F4E62D /* CacheIsKingTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 30D75C211C57CE1400F4E62D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30D75C321C57D17400F4E62D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30D75C3F1C57D2CA00F4E62D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 30D75C1E1C57CE1400F4E62D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 30D75C4D1C57F1C800F4E62D /* AnyKey.swift in Sources */, + 30D75C2E1C57CEC500F4E62D /* KingCache.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30D75C2F1C57D17400F4E62D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 30D75C4E1C58033B00F4E62D /* AnyKey.swift in Sources */, + 30D75C3C1C57D1A300F4E62D /* KingCache.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 30D75C3D1C57D2CA00F4E62D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 30D75C441C57D2CA00F4E62D /* CacheIsKingTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 30D75C481C57D2CA00F4E62D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 30D75C221C57CE1400F4E62D /* CacheIsKing-iOS */; + targetProxy = 30D75C471C57D2CA00F4E62D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 30D75C1C1C57CD6100F4E62D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + 30D75C1D1C57CD6100F4E62D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + 30D75C2A1C57CE1400F4E62D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "CacheIsKing-iOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-iOS"; + PRODUCT_NAME = CacheIsKing; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 30D75C2B1C57CE1400F4E62D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "CacheIsKing-iOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-iOS"; + PRODUCT_NAME = CacheIsKing; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 30D75C3A1C57D17400F4E62D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "CacheIsKing-tvOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-tvOS"; + PRODUCT_NAME = CacheIsKing; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 30D75C3B1C57D17400F4E62D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "CacheIsKing-tvOS/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "com.nuudles.CacheIsKing-tvOS"; + PRODUCT_NAME = CacheIsKing; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 30D75C4A1C57D2CA00F4E62D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = CacheIsKingTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.CacheIsKingTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 30D75C4B1C57D2CA00F4E62D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = CacheIsKingTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.CacheIsKingTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 30D75C1B1C57CD6100F4E62D /* Build configuration list for PBXProject "CacheIsKing" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 30D75C1C1C57CD6100F4E62D /* Debug */, + 30D75C1D1C57CD6100F4E62D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 30D75C291C57CE1400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 30D75C2A1C57CE1400F4E62D /* Debug */, + 30D75C2B1C57CE1400F4E62D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 30D75C391C57D17400F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKing-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 30D75C3A1C57D17400F4E62D /* Debug */, + 30D75C3B1C57D17400F4E62D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 30D75C491C57D2CA00F4E62D /* Build configuration list for PBXNativeTarget "CacheIsKingTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 30D75C4A1C57D2CA00F4E62D /* Debug */, + 30D75C4B1C57D2CA00F4E62D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 30D75C181C57CD6100F4E62D /* Project object */; +} diff --git a/CacheIsKing.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/CacheIsKing.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5d805bd --- /dev/null +++ b/CacheIsKing.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/CacheIsKing.xcodeproj/xcshareddata/xcschemes/CacheIsKing-iOS.xcscheme b/CacheIsKing.xcodeproj/xcshareddata/xcschemes/CacheIsKing-iOS.xcscheme new file mode 100644 index 0000000..93561fe --- /dev/null +++ b/CacheIsKing.xcodeproj/xcshareddata/xcschemes/CacheIsKing-iOS.xcscheme @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CacheIsKing.xcodeproj/xcshareddata/xcschemes/CacheIsKing-tvOS.xcscheme b/CacheIsKing.xcodeproj/xcshareddata/xcschemes/CacheIsKing-tvOS.xcscheme new file mode 100644 index 0000000..0cb35de --- /dev/null +++ b/CacheIsKing.xcodeproj/xcshareddata/xcschemes/CacheIsKing-tvOS.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CacheIsKingTests/CacheIsKingTests.swift b/CacheIsKingTests/CacheIsKingTests.swift new file mode 100644 index 0000000..7ff3a95 --- /dev/null +++ b/CacheIsKingTests/CacheIsKingTests.swift @@ -0,0 +1,246 @@ +// +// CacheIsKingTests.swift +// CacheIsKingTests +// +// Created by Christopher Luu on 1/26/16. +// +// + +import XCTest +@testable import CacheIsKing + +class CacheIsKingTests: XCTestCase { + func testSettingAndGettingItems() { + let cache = KingCache() + cache.setItem(123, forKey: "123") + + XCTAssert(cache.cacheDictionary.count == 1) + XCTAssert(cache.count == 1) + XCTAssert(cache.itemForKey("123") == 123) + XCTAssert(cache.cacheDictionary[AnyKey("123")] as? Int == .Some(123)) + XCTAssert(cache[123] == nil) + + cache[234] = "234" + + XCTAssert(cache.cacheDictionary.count == 2) + XCTAssert(cache.count == 2) + XCTAssert(cache.itemForKey(234) == "234") + XCTAssert(cache.cacheDictionary[AnyKey(234)] as? String == .Some("234")) + + // Test setting/getting an array + let array = [1, 2, 3, 4, 5] + cache[5] = array + + XCTAssert(cache.cacheDictionary.count == 3) + XCTAssert(cache.count == 3) + if let fetchedArray: [Int] = cache.itemForKey(5) { + XCTAssert(fetchedArray == array) + } + else { + XCTFail("Expected an int array") + } + + let testStruct = TestStruct(name: "Testing", value: Int(arc4random_uniform(100000))) + cache["TestingStruct"] = testStruct + + guard let fetchedStruct: TestStruct = cache.itemForKey("TestingStruct") else { + XCTFail() + return + } + XCTAssert(testStruct.name == fetchedStruct.name) + XCTAssert(testStruct.value == fetchedStruct.value) + } + + func testDifferentKindsOfKeys() { + let cache = KingCache() + + let floatKey: Float = 123.456 + cache.setItem(123.456, forKey: floatKey) + XCTAssert(cache.itemForKey(floatKey) as Double? == .Some(123.456)) + + cache[floatKey] = 456.789 + XCTAssert(cache.count == 1) + XCTAssert(cache[floatKey] as? Double == .Some(456.789)) + + cache.setItem("123.456", forKey: "123.456") + XCTAssert(cache.count == 2) + XCTAssert(cache.itemForKey("123.456") as String? == .Some("123.456")) + + let boolKey = true + cache.setItem(true, forKey: boolKey) + XCTAssert(cache.count == 3) + XCTAssert(cache.itemForKey(boolKey) as Bool? == .Some(true)) + + cache.removeItemForKey(boolKey) + XCTAssert(cache.count == 2) + XCTAssert(cache.itemForKey(boolKey) as Bool? == .None) + } + + func testSettingAndGettingEnum() { + let cache = KingCache() + cache["ABC"] = TestEnum.ABC + cache["DEF"] = TestEnum.DEF("BlahBlahBlah") + cache["GHI"] = TestEnum.GHI(-500) + + guard let abc: TestEnum = cache.itemForKey("ABC"), + def: TestEnum = cache.itemForKey("DEF"), + ghi: TestEnum = cache.itemForKey("GHI") + else { + XCTFail() + return + } + switch (abc, def, ghi) { + case (.ABC, .DEF(let stringValue), .GHI(let intValue)): + XCTAssert(stringValue == "BlahBlahBlah") + XCTAssert(intValue == -500) + default: + XCTFail() + } + } + + func testSubscripts() { + let cache = KingCache() + + // Int subscript + cache[123] = 123 + XCTAssert(cache[123] as? Int == .Some(123)) + XCTAssert(cache.count == 1) + + cache[123] = nil + XCTAssert(cache[123] as? Int == .None) + XCTAssert(cache.count == 0) + + // String subscript + cache["123"] = 123 + XCTAssert(cache["123"] as? Int == .Some(123)) + XCTAssert(cache.count == 1) + + cache["123"] = nil + XCTAssert(cache["123"] as? Int == .None) + XCTAssert(cache.count == 0) + + // Float subscript + let floatKey: Float = 3.14 + cache[floatKey] = 123 + XCTAssert(cache[floatKey] as? Int == .Some(123)) + XCTAssert(cache.count == 1) + + cache[floatKey] = nil + XCTAssert(cache[floatKey] as? Int == .None) + XCTAssert(cache.count == 0) + } + + func testRemovingItems() { + let cache = KingCache() + cache.setItem(123, forKey: 123) + cache.setItem(234, forKey: 234) + cache.setItem(345, forKey: 345) + cache.setItem(456, forKey: 456) + + XCTAssert(cache.count == 4) + + cache.removeItemForKey(123) + + XCTAssert(cache.count == 3) + XCTAssert(cache[123] == nil) + + cache[234] = nil + + XCTAssert(cache.count == 2) + XCTAssert(cache[234] == nil) + + cache.removeAllItems() + + XCTAssert(cache.count == 0) + + cache.setItem(123, forKey: 123) + cache.setItem(234, forKey: 234) + cache.setItem(345, forKey: 345) + cache.setItem(456, forKey: 456) + + XCTAssert(cache.count == 4) + + NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidReceiveMemoryWarningNotification, object: nil) + + XCTAssert(cache.count == 0) + + cache.setItem(123, forKey: 123) + cache.setItem(234, forKey: 234) + cache.setItem(345, forKey: 345) + cache.setItem(456, forKey: 456) + + XCTAssert(cache.count == 4) + + NSNotificationCenter.defaultCenter().postNotificationName(UIApplicationDidEnterBackgroundNotification, object: nil) + + XCTAssert(cache.count == 0) + } + + func testCountLimit() { + let cache = KingCache() + cache.setItem(123, forKey: 123) + cache.setItem(234, forKey: 234) + cache.setItem(345, forKey: 345) + cache.setItem(456, forKey: 456) + + XCTAssert(cache.count == 4) + + cache.countLimit = 3 + + XCTAssert(cache.count == 3) + + cache.removeAllItems() + + XCTAssert(cache.count == 0) + + cache.setItem(123, forKey: 123) + cache.setItem(234, forKey: 234) + cache.setItem(345, forKey: 345) + cache.setItem(456, forKey: 456) + + XCTAssert(cache.count == 3) + + cache[567] = 567 + XCTAssert(cache.count == 3) + + cache.removeAllItems() + + cache.setItem(123, forKey: 123) + cache.setItem(234, forKey: 234) + cache.setItem(345, forKey: 345) + cache.setItem(456, forKey: 456) + + cache.countLimit = 2 + + XCTAssert(cache.count == 2) + } + + func testEmptyEviction() { + // Make sure that an eviction on an empty dictionary doesn't crash + let cache = KingCache() + cache.evictItemsIfNeeded() + } + + func testObjCObjects() { + let cache = KingCache() + + let oldCache = NSCache() + cache.setItem(oldCache, forKey: "InceptionCache") + + guard let _: NSCache = cache.itemForKey("InceptionCache") else { + XCTFail("Expected an NSCache object") + return + } + } +} + +private struct TestStruct { + let name: String + let value: Int +} + +private enum TestEnum { + case ABC + case DEF(String) + case GHI(Int) +} diff --git a/CacheIsKingTests/Info.plist b/CacheIsKingTests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/CacheIsKingTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bd25506 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Christopher Luu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e13cc98 --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# CacheIsKing + + + + + +`CacheIsKing` is a simple cache that allows you to store any item, including objects, pure Swift structs, enums (with associated values), etc. Simply put, it's designed to act like an `NSCache` for everything, including Swift variables. + +## Features + +- Simply set, get, and remove items based on any key that is `Hashable` +- The cache is cleared when the app receives a memory warning +- Similar to `NSCache`, the cache is cleared when the app enters the background +- Subscripts are supported for `String`, `Int`, and `Float` keys +- `itemForKey` uses generics so you don't have to cast the return value when the type is inferred correctly +- Similar to `NSCache`, the cache can have a `countLimit` set to ensure that the cache doesn't get too large + +## Requirements + +- iOS 8.0+ +- tvOS 9.0+ +- Xcode 7+ + +## Installation using CocoaPods + +[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. + +Because `CacheIsKing ` is written in Swift, you must use frameworks. + +To integrate `CacheIsKing ` into your Xcode project using CocoaPods, specify it in your `Podfile`: + +```ruby +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' +use_frameworks! + +pod 'CacheIsKing' +``` + +Then, run the following command: + +```bash +$ pod install +``` + +## Installation using Carthage + +Add this to your `Cartfile`: + +``` +github "nuudles/CacheIsKing" +``` + +## Usage + +Simply use the `KingCache` class similar to how you'd use a `NSCache`. Using the `setItem` and `itemForKey` methods allow you to use type inference to get the values you want. + +```swift +let cache = KingCache() +cache.setItem(123, forKey: "123") + +if let item: Int = cache.itemForKey(456) { + doSomethingWithItem(item) +} +``` + +You can also use subscripts to set/get items from the cache. Unfortunately since Swift doesn't support subscript methods with generics yet, you'll have to cast your items as necessary. Also currently only `String`, `Int`, and `Float` keys are supported: + +```swift +let cache = KingCache() +cache["123"] = 123 + +if let item = cache[456] as? Int { + doSomethingWithItem(item) +} +``` + +The `KingCache` also has a `countLimit` property, which allows you to set the maximum number of items in the cache. It currently evicts randomly until the `countLimit` is met. + +```swift +let cache = KingCache() +cache.countLimit = 2 + +cache[123] = 123 +cache[234] = 234 +cache[345] = 345 + +print("\(cache.count)") // shows a count of 2 +``` + +## TODO + +- Refine eviction algorithm (currently evicts randomly) +- Update with better subscript support once Swift supports subscripts with generics \ No newline at end of file diff --git a/Source/AnyKey.swift b/Source/AnyKey.swift new file mode 100644 index 0000000..bc31c78 --- /dev/null +++ b/Source/AnyKey.swift @@ -0,0 +1,39 @@ +// +// AnyKey.swift +// CacheIsKing +// +// Created by Christopher Luu on 1/26/16. +// +// + +import Foundation + +/// This code was taken from: +/// http://stackoverflow.com/questions/24119624/how-to-create-dictionary-that-can-hold-anything-in-key-or-all-the-possible-type +struct AnyKey: Hashable { + private let underlying: Any + private let hashValueFunc: () -> Int + private let equalityFunc: (Any) -> Bool + + init(_ key: T) { + underlying = key + // Capture the key's hashability and equatability using closures. + // The Key shares the hash of the underlying value. + hashValueFunc = { key.hashValue } + + // The Key is equal to a Key of the same underlying type, + // whose underlying value is "==" to ours. + equalityFunc = { + if let other = $0 as? T { + return key == other + } + return false + } + } + + var hashValue: Int { return hashValueFunc() } +} + +func ==(x: AnyKey, y: AnyKey) -> Bool { + return x.equalityFunc(y.underlying) +} diff --git a/Source/KingCache.swift b/Source/KingCache.swift new file mode 100644 index 0000000..a655ac2 --- /dev/null +++ b/Source/KingCache.swift @@ -0,0 +1,131 @@ +// +// KingCache.swift +// CacheIsKing +// +// Created by Christopher Luu on 1/26/16. +// +// + +import Foundation + +public class KingCache { + // MARK: - Private variables + private var notificationObservers: [NSObjectProtocol] = [] + + // MARK: - Internal variables + var cacheDictionary: [AnyKey: Any] = [:] + + // MARK: - Public variables + public var count: Int { + return cacheDictionary.count + } + public var countLimit: UInt = 0 { + didSet { + evictItemsIfNeeded() + } + } + + // MARK: - Initialization methods + public init() { + let removalBlock = { [unowned self] (_: NSNotification) in + self.cacheDictionary.removeAll() + } + + var notificationObserver = NSNotificationCenter.defaultCenter() + .addObserverForName(UIApplicationDidReceiveMemoryWarningNotification, + object: nil, + queue: nil, + usingBlock: removalBlock) + notificationObservers.append(notificationObserver) + notificationObserver = NSNotificationCenter.defaultCenter() + .addObserverForName(UIApplicationDidEnterBackgroundNotification, + object: nil, + queue: nil, + usingBlock: removalBlock) + notificationObservers.append(notificationObserver) + } + + deinit { + notificationObservers.forEach { + NSNotificationCenter.defaultCenter().removeObserver($0) + } + } + + // MARK: - Internal methods + func evictItemsIfNeeded() { + if countLimit > 0 && cacheDictionary.count > Int(countLimit) { + // TODO: Evict items with more rhyme or reason + var keys = cacheDictionary.keys.flatMap { $0 } + while cacheDictionary.count > Int(countLimit) { + let randomIndex = Int(arc4random_uniform(UInt32(keys.count))) + let key = keys.removeAtIndex(randomIndex) + cacheDictionary.removeValueForKey(key) + } + } + } + + // MARK: - Public methods + public func setItem(item: Any, forKey key: K) { + cacheDictionary[AnyKey(key)] = item + evictItemsIfNeeded() + } + + public func itemForKey(key: K) -> T? { + if let item = cacheDictionary[AnyKey(key)] as? T { + return item + } + return nil + } + + public func removeItemForKey(key: K) { + cacheDictionary[AnyKey(key)] = nil + } + + public func removeAllItems() { + cacheDictionary.removeAll() + } + + // MARK: - Subscript methods + // TODO: Consolidate these subscript methods once subscript generics with constraints are supported + public subscript(key: Int) -> Any? { + get { + return itemForKey(key) + } + set { + if let newValue = newValue { + setItem(newValue, forKey: key) + } + else { + removeItemForKey(key) + } + } + } + + public subscript(key: Float) -> Any? { + get { + return itemForKey(key) + } + set { + if let newValue = newValue { + setItem(newValue, forKey: key) + } + else { + removeItemForKey(key) + } + } + } + + public subscript(key: String) -> Any? { + get { + return itemForKey(key) + } + set { + if let newValue = newValue { + setItem(newValue, forKey: key) + } + else { + removeItemForKey(key) + } + } + } +}