├── DDGDataCache_Swift ├── DDGDataCache_Swift.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata │ │ │ └── dudongge.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── dudongge.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── DDGDataCache_Swift │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── DDGDataCache │ │ └── DDGDataCache.swift │ ├── DDGDataCache_Swift-Bridging-Header.h │ ├── Info.plist │ └── ViewController.swift └── gif │ └── DDGDataCache.gif ├── LICENSE └── README.md /DDGDataCache_Swift/DDGDataCache_Swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F75C5B6720BC309A00A40766 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75C5B6620BC309A00A40766 /* AppDelegate.swift */; }; 11 | F75C5B6920BC309A00A40766 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75C5B6820BC309A00A40766 /* ViewController.swift */; }; 12 | F75C5B6C20BC309A00A40766 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F75C5B6A20BC309A00A40766 /* Main.storyboard */; }; 13 | F75C5B6E20BC309B00A40766 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F75C5B6D20BC309B00A40766 /* Assets.xcassets */; }; 14 | F75C5B7120BC309B00A40766 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F75C5B6F20BC309B00A40766 /* LaunchScreen.storyboard */; }; 15 | F75C5B7A20BC30E500A40766 /* DDGDataCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75C5B7920BC30E500A40766 /* DDGDataCache.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | F75C5B6320BC309A00A40766 /* DDGDataCache_Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DDGDataCache_Swift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | F75C5B6620BC309A00A40766 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | F75C5B6820BC309A00A40766 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 22 | F75C5B6B20BC309A00A40766 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 23 | F75C5B6D20BC309B00A40766 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | F75C5B7020BC309B00A40766 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 25 | F75C5B7220BC309B00A40766 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | F75C5B7920BC30E500A40766 /* DDGDataCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DDGDataCache.swift; sourceTree = ""; }; 27 | F75C5B7B20BC313200A40766 /* DDGDataCache_Swift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DDGDataCache_Swift-Bridging-Header.h"; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | F75C5B6020BC309A00A40766 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | F75C5B5A20BC309A00A40766 = { 42 | isa = PBXGroup; 43 | children = ( 44 | F75C5B6520BC309A00A40766 /* DDGDataCache_Swift */, 45 | F75C5B6420BC309A00A40766 /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | F75C5B6420BC309A00A40766 /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | F75C5B6320BC309A00A40766 /* DDGDataCache_Swift.app */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | F75C5B6520BC309A00A40766 /* DDGDataCache_Swift */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | F75C5B7820BC30E500A40766 /* DDGDataCache */, 61 | F75C5B6620BC309A00A40766 /* AppDelegate.swift */, 62 | F75C5B6820BC309A00A40766 /* ViewController.swift */, 63 | F75C5B6A20BC309A00A40766 /* Main.storyboard */, 64 | F75C5B6D20BC309B00A40766 /* Assets.xcassets */, 65 | F75C5B6F20BC309B00A40766 /* LaunchScreen.storyboard */, 66 | F75C5B7220BC309B00A40766 /* Info.plist */, 67 | F75C5B7B20BC313200A40766 /* DDGDataCache_Swift-Bridging-Header.h */, 68 | ); 69 | path = DDGDataCache_Swift; 70 | sourceTree = ""; 71 | }; 72 | F75C5B7820BC30E500A40766 /* DDGDataCache */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | F75C5B7920BC30E500A40766 /* DDGDataCache.swift */, 76 | ); 77 | path = DDGDataCache; 78 | sourceTree = ""; 79 | }; 80 | /* End PBXGroup section */ 81 | 82 | /* Begin PBXNativeTarget section */ 83 | F75C5B6220BC309A00A40766 /* DDGDataCache_Swift */ = { 84 | isa = PBXNativeTarget; 85 | buildConfigurationList = F75C5B7520BC309B00A40766 /* Build configuration list for PBXNativeTarget "DDGDataCache_Swift" */; 86 | buildPhases = ( 87 | F75C5B5F20BC309A00A40766 /* Sources */, 88 | F75C5B6020BC309A00A40766 /* Frameworks */, 89 | F75C5B6120BC309A00A40766 /* Resources */, 90 | ); 91 | buildRules = ( 92 | ); 93 | dependencies = ( 94 | ); 95 | name = DDGDataCache_Swift; 96 | productName = DDGDataCache_Swift; 97 | productReference = F75C5B6320BC309A00A40766 /* DDGDataCache_Swift.app */; 98 | productType = "com.apple.product-type.application"; 99 | }; 100 | /* End PBXNativeTarget section */ 101 | 102 | /* Begin PBXProject section */ 103 | F75C5B5B20BC309A00A40766 /* Project object */ = { 104 | isa = PBXProject; 105 | attributes = { 106 | LastSwiftUpdateCheck = 0930; 107 | LastUpgradeCheck = 0930; 108 | ORGANIZATIONNAME = dudongge; 109 | TargetAttributes = { 110 | F75C5B6220BC309A00A40766 = { 111 | CreatedOnToolsVersion = 9.3; 112 | LastSwiftMigration = 1020; 113 | }; 114 | }; 115 | }; 116 | buildConfigurationList = F75C5B5E20BC309A00A40766 /* Build configuration list for PBXProject "DDGDataCache_Swift" */; 117 | compatibilityVersion = "Xcode 9.3"; 118 | developmentRegion = en; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | Base, 123 | ); 124 | mainGroup = F75C5B5A20BC309A00A40766; 125 | productRefGroup = F75C5B6420BC309A00A40766 /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | F75C5B6220BC309A00A40766 /* DDGDataCache_Swift */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXResourcesBuildPhase section */ 135 | F75C5B6120BC309A00A40766 /* Resources */ = { 136 | isa = PBXResourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | F75C5B7120BC309B00A40766 /* LaunchScreen.storyboard in Resources */, 140 | F75C5B6E20BC309B00A40766 /* Assets.xcassets in Resources */, 141 | F75C5B6C20BC309A00A40766 /* Main.storyboard in Resources */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXResourcesBuildPhase section */ 146 | 147 | /* Begin PBXSourcesBuildPhase section */ 148 | F75C5B5F20BC309A00A40766 /* Sources */ = { 149 | isa = PBXSourcesBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | F75C5B6920BC309A00A40766 /* ViewController.swift in Sources */, 153 | F75C5B7A20BC30E500A40766 /* DDGDataCache.swift in Sources */, 154 | F75C5B6720BC309A00A40766 /* AppDelegate.swift in Sources */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXSourcesBuildPhase section */ 159 | 160 | /* Begin PBXVariantGroup section */ 161 | F75C5B6A20BC309A00A40766 /* Main.storyboard */ = { 162 | isa = PBXVariantGroup; 163 | children = ( 164 | F75C5B6B20BC309A00A40766 /* Base */, 165 | ); 166 | name = Main.storyboard; 167 | sourceTree = ""; 168 | }; 169 | F75C5B6F20BC309B00A40766 /* LaunchScreen.storyboard */ = { 170 | isa = PBXVariantGroup; 171 | children = ( 172 | F75C5B7020BC309B00A40766 /* Base */, 173 | ); 174 | name = LaunchScreen.storyboard; 175 | sourceTree = ""; 176 | }; 177 | /* End PBXVariantGroup section */ 178 | 179 | /* Begin XCBuildConfiguration section */ 180 | F75C5B7320BC309B00A40766 /* Debug */ = { 181 | isa = XCBuildConfiguration; 182 | buildSettings = { 183 | ALWAYS_SEARCH_USER_PATHS = NO; 184 | CLANG_ANALYZER_NONNULL = YES; 185 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 186 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 187 | CLANG_CXX_LIBRARY = "libc++"; 188 | CLANG_ENABLE_MODULES = YES; 189 | CLANG_ENABLE_OBJC_ARC = YES; 190 | CLANG_ENABLE_OBJC_WEAK = YES; 191 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 192 | CLANG_WARN_BOOL_CONVERSION = YES; 193 | CLANG_WARN_COMMA = YES; 194 | CLANG_WARN_CONSTANT_CONVERSION = YES; 195 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 196 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 197 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 198 | CLANG_WARN_EMPTY_BODY = YES; 199 | CLANG_WARN_ENUM_CONVERSION = YES; 200 | CLANG_WARN_INFINITE_RECURSION = YES; 201 | CLANG_WARN_INT_CONVERSION = YES; 202 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 203 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 204 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 205 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 206 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 207 | CLANG_WARN_STRICT_PROTOTYPES = YES; 208 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 209 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 210 | CLANG_WARN_UNREACHABLE_CODE = YES; 211 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 212 | CODE_SIGN_IDENTITY = "iPhone Developer"; 213 | COPY_PHASE_STRIP = NO; 214 | DEBUG_INFORMATION_FORMAT = dwarf; 215 | ENABLE_STRICT_OBJC_MSGSEND = YES; 216 | ENABLE_TESTABILITY = YES; 217 | GCC_C_LANGUAGE_STANDARD = gnu11; 218 | GCC_DYNAMIC_NO_PIC = NO; 219 | GCC_NO_COMMON_BLOCKS = YES; 220 | GCC_OPTIMIZATION_LEVEL = 0; 221 | GCC_PREPROCESSOR_DEFINITIONS = ( 222 | "DEBUG=1", 223 | "$(inherited)", 224 | ); 225 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 226 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 227 | GCC_WARN_UNDECLARED_SELECTOR = YES; 228 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 229 | GCC_WARN_UNUSED_FUNCTION = YES; 230 | GCC_WARN_UNUSED_VARIABLE = YES; 231 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 232 | MTL_ENABLE_DEBUG_INFO = YES; 233 | ONLY_ACTIVE_ARCH = YES; 234 | SDKROOT = iphoneos; 235 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 236 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 237 | }; 238 | name = Debug; 239 | }; 240 | F75C5B7420BC309B00A40766 /* Release */ = { 241 | isa = XCBuildConfiguration; 242 | buildSettings = { 243 | ALWAYS_SEARCH_USER_PATHS = NO; 244 | CLANG_ANALYZER_NONNULL = YES; 245 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 246 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 247 | CLANG_CXX_LIBRARY = "libc++"; 248 | CLANG_ENABLE_MODULES = YES; 249 | CLANG_ENABLE_OBJC_ARC = YES; 250 | CLANG_ENABLE_OBJC_WEAK = YES; 251 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 252 | CLANG_WARN_BOOL_CONVERSION = YES; 253 | CLANG_WARN_COMMA = YES; 254 | CLANG_WARN_CONSTANT_CONVERSION = YES; 255 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 256 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 257 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 258 | CLANG_WARN_EMPTY_BODY = YES; 259 | CLANG_WARN_ENUM_CONVERSION = YES; 260 | CLANG_WARN_INFINITE_RECURSION = YES; 261 | CLANG_WARN_INT_CONVERSION = YES; 262 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 263 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 264 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 265 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 266 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 267 | CLANG_WARN_STRICT_PROTOTYPES = YES; 268 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 269 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 270 | CLANG_WARN_UNREACHABLE_CODE = YES; 271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 272 | CODE_SIGN_IDENTITY = "iPhone Developer"; 273 | COPY_PHASE_STRIP = NO; 274 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 275 | ENABLE_NS_ASSERTIONS = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu11; 278 | GCC_NO_COMMON_BLOCKS = YES; 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 286 | MTL_ENABLE_DEBUG_INFO = NO; 287 | SDKROOT = iphoneos; 288 | SWIFT_COMPILATION_MODE = wholemodule; 289 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 290 | VALIDATE_PRODUCT = YES; 291 | }; 292 | name = Release; 293 | }; 294 | F75C5B7620BC309B00A40766 /* Debug */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 298 | CLANG_ENABLE_MODULES = YES; 299 | CODE_SIGN_STYLE = Automatic; 300 | DEVELOPMENT_TEAM = 7FPUQV8RGB; 301 | INFOPLIST_FILE = DDGDataCache_Swift/Info.plist; 302 | LD_RUNPATH_SEARCH_PATHS = ( 303 | "$(inherited)", 304 | "@executable_path/Frameworks", 305 | ); 306 | PRODUCT_BUNDLE_IDENTIFIER = "-2345.DDGDataCache-Swift"; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | SWIFT_OBJC_BRIDGING_HEADER = "DDGDataCache_Swift/DDGDataCache_Swift-Bridging-Header.h"; 309 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 310 | SWIFT_VERSION = 5.0; 311 | TARGETED_DEVICE_FAMILY = "1,2"; 312 | }; 313 | name = Debug; 314 | }; 315 | F75C5B7720BC309B00A40766 /* Release */ = { 316 | isa = XCBuildConfiguration; 317 | buildSettings = { 318 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 319 | CLANG_ENABLE_MODULES = YES; 320 | CODE_SIGN_STYLE = Automatic; 321 | DEVELOPMENT_TEAM = 7FPUQV8RGB; 322 | INFOPLIST_FILE = DDGDataCache_Swift/Info.plist; 323 | LD_RUNPATH_SEARCH_PATHS = ( 324 | "$(inherited)", 325 | "@executable_path/Frameworks", 326 | ); 327 | PRODUCT_BUNDLE_IDENTIFIER = "-2345.DDGDataCache-Swift"; 328 | PRODUCT_NAME = "$(TARGET_NAME)"; 329 | SWIFT_OBJC_BRIDGING_HEADER = "DDGDataCache_Swift/DDGDataCache_Swift-Bridging-Header.h"; 330 | SWIFT_VERSION = 5.0; 331 | TARGETED_DEVICE_FAMILY = "1,2"; 332 | }; 333 | name = Release; 334 | }; 335 | /* End XCBuildConfiguration section */ 336 | 337 | /* Begin XCConfigurationList section */ 338 | F75C5B5E20BC309A00A40766 /* Build configuration list for PBXProject "DDGDataCache_Swift" */ = { 339 | isa = XCConfigurationList; 340 | buildConfigurations = ( 341 | F75C5B7320BC309B00A40766 /* Debug */, 342 | F75C5B7420BC309B00A40766 /* Release */, 343 | ); 344 | defaultConfigurationIsVisible = 0; 345 | defaultConfigurationName = Release; 346 | }; 347 | F75C5B7520BC309B00A40766 /* Build configuration list for PBXNativeTarget "DDGDataCache_Swift" */ = { 348 | isa = XCConfigurationList; 349 | buildConfigurations = ( 350 | F75C5B7620BC309B00A40766 /* Debug */, 351 | F75C5B7720BC309B00A40766 /* Release */, 352 | ); 353 | defaultConfigurationIsVisible = 0; 354 | defaultConfigurationName = Release; 355 | }; 356 | /* End XCConfigurationList section */ 357 | }; 358 | rootObject = F75C5B5B20BC309A00A40766 /* Project object */; 359 | } 360 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift.xcodeproj/project.xcworkspace/xcuserdata/dudongge.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dudongge/DDGDataCache_Swift/2ce9d885ddbeac6d8d54ac1231059f4c45a52b6c/DDGDataCache_Swift/DDGDataCache_Swift.xcodeproj/project.xcworkspace/xcuserdata/dudongge.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift.xcodeproj/xcuserdata/dudongge.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DDGDataCache_Swift.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | DDGDataCache_Swift.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DDGDataCache_Swift 4 | // 5 | // Created by dudongge on 2018/5/28. 6 | // Copyright © 2018年 dudongge. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/DDGDataCache/DDGDataCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DDGDataCache.swift 3 | // DDGDataCache_Swift 4 | // 5 | // Created by dudongge on 2018/5/25. 6 | // Copyright © 2018年 dudongge. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | /** 11 | * 注意: 使用前请在'-Bridging-Header.h' 桥接文件中导入 #import 12 | 因为要用到MD5加密的东西 13 | */ 14 | let DDGCacheKeyPath = "DDGCacheKeyPath" 15 | extension DDGDataCache 16 | { 17 | /** 18 | 写入/更新缓存(同步) [按APP版本号缓存,不同版本APP,同一接口缓存数据互不干扰] 19 | - parameter jsonResponse: 要写入的数据(JSON) 20 | - parameter URL: 数据请求URL 21 | - parameter path: 一级文件夹路径path(必须设置) 22 | - parameter subPath: 二级文件夹路径subPath(可设置-可不设置) 23 | - returns: 是否写入成功 24 | */ 25 | public class func saveJsonResponseToCacheFile(_ jsonResponse: AnyObject, 26 | URL: String, 27 | path: String, 28 | subPath: String = "") -> Bool { 29 | 30 | let data = jsonToData(jsonResponse) 31 | let atPath = cacheFilePathWithURL(URL, 32 | path: path, 33 | subPath: subPath) 34 | return FileManager.default.createFile(atPath:atPath, 35 | contents: data, 36 | attributes: nil) 37 | } 38 | 39 | /** 40 | 写入/更新缓存(异步) [按APP版本号缓存,不同版本APP,同一接口缓存数据互不干扰] 41 | - parameter jsonResponse: 要写入的数据(JSON) 42 | - parameter URL: 数据请求URL 43 | - parameter subPath: 二级文件夹路径subPath(可设置-可不设置) 44 | - parameter completed: 异步完成回调(主线程回调) 45 | */ 46 | public class func save_asyncJsonResponseToCacheFile(_ jsonResponse: AnyObject, 47 | URL: String, 48 | path: String , 49 | subPath: String = "", 50 | completed:@escaping (Bool) -> ()) { 51 | 52 | DispatchQueue.global().async{ 53 | let result = saveJsonResponseToCacheFile(jsonResponse, 54 | URL: URL, 55 | path: path, 56 | subPath: subPath) 57 | DispatchQueue.main.async(execute: { 58 | completed(result) 59 | }) 60 | } 61 | } 62 | 63 | /** 64 | 获取缓存的对象(同步) 65 | - parameter URL: 数据请求URL 66 | - parameter subPath: 二级文件夹路径subPath(可设置-可不设置) 67 | - returns: 缓存对象 68 | */ 69 | public class func cacheJsonWithURL(_ URL: String,subPath:String = "") -> AnyObject? { 70 | if let keyPath = UserDefaults.standard.string(forKey: DDGCacheKeyPath) { 71 | let path: String = self.cacheFilePathWithURL(URL, path: keyPath,subPath: subPath) 72 | let fileManager: FileManager = FileManager.default 73 | if fileManager.fileExists(atPath: path, isDirectory: nil) == true { 74 | let data: Data = fileManager.contents(atPath: path)! 75 | return self.dataToJson(data) 76 | } 77 | } 78 | return nil 79 | } 80 | 81 | /** 82 | 获取总缓存路径 83 | - returns: 缓存路径 84 | - parameter subPath: 二级文件夹路径subPath(可设置-可不设置) 85 | */ 86 | public class func cachePath() -> String { 87 | if let keyPath = UserDefaults.standard.string(forKey: DDGCacheKeyPath) { 88 | let pathOfLibrary = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as NSString 89 | let path = pathOfLibrary.appendingPathComponent(keyPath) 90 | return path 91 | } else { 92 | return "" 93 | } 94 | } 95 | /** 96 | 获取子缓存路径 97 | - returns: 子缓存路径 98 | */ 99 | public class func cacheSubPath(_ subPath: String = "") -> String { 100 | let path = self.cachePath() + "/" + subPath 101 | return path 102 | } 103 | /** 104 | 清除全部缓存 105 | */ 106 | public class func clearAllCache() -> Bool{ 107 | let fileManager: FileManager = FileManager.default 108 | let path: String = self.cachePath() 109 | if path.count == 0 { 110 | return false 111 | } 112 | do 113 | { 114 | try fileManager.removeItem(atPath: path) 115 | self.checkDirectory(self.cachePath()) 116 | return true 117 | } 118 | catch let error as NSError 119 | { 120 | print("clearCache failed , error = \(error)") 121 | return false 122 | } 123 | } 124 | /** 125 | 清除制定文件夹下全部缓存 126 | */ 127 | public class func clearCacheWithUrl(_ url: String) -> Bool{ 128 | let fileManager: FileManager = FileManager.default 129 | let path: String = self.cacheSubPath(url) 130 | 131 | do 132 | { 133 | try fileManager.removeItem(atPath: path) 134 | self.checkDirectory(self.cacheSubPath(url)) 135 | return true 136 | } 137 | catch let error as NSError 138 | { 139 | print("clearCache failed , error = \(error)") 140 | return false 141 | } 142 | } 143 | /** 144 | 获取缓存大小 145 | - returns: 缓存大小(单位:M) 146 | */ 147 | public class func cacheAllSize()-> Float { 148 | 149 | let cachePath = self.cachePath() 150 | do 151 | { 152 | let fileArr = try FileManager.default.contentsOfDirectory(atPath: cachePath) 153 | var size:Float = 0 154 | for file in fileArr{ 155 | let path = cachePath + "/\(file)" 156 | let floder = try! FileManager.default.attributesOfItem(atPath: path) 157 | for (abc, bcd) in floder { 158 | if abc == FileAttributeKey.size { 159 | size += (bcd as AnyObject).floatValue 160 | } 161 | } 162 | } 163 | let total = size / 1024.0 / 1024.0 164 | return total 165 | } 166 | catch 167 | { 168 | return 0; 169 | } 170 | } 171 | /** 172 | 获取单个文件夹下缓存大小 173 | - returns: 子缓存大小(单位:M) 174 | */ 175 | public class func cacheSizeWithUrl(_ Url: String)-> Float { 176 | 177 | let cachePath = self.cacheSubPath(Url) 178 | do 179 | { 180 | let fileArr = try FileManager.default.contentsOfDirectory(atPath: cachePath) 181 | var size:Float = 0 182 | for file in fileArr{ 183 | let path = cachePath + "/\(file)" 184 | let floder = try! FileManager.default.attributesOfItem(atPath: path) 185 | for (abc, bcd) in floder { 186 | if abc == FileAttributeKey.size { 187 | size += (bcd as AnyObject).floatValue 188 | } 189 | } 190 | } 191 | let total = size / 1024.0 / 1024.0 192 | return total 193 | } 194 | catch 195 | { 196 | return 0; 197 | } 198 | } 199 | } 200 | 201 | open class DDGDataCache { 202 | //MARK: - private 203 | fileprivate class func jsonToData(_ jsonResponse: AnyObject) -> Data? { 204 | do{ 205 | let data = try JSONSerialization.data(withJSONObject: jsonResponse, options: JSONSerialization.WritingOptions.prettyPrinted) 206 | return data; 207 | 208 | }catch 209 | { 210 | return nil 211 | } 212 | } 213 | 214 | fileprivate class func dataToJson(_ data: Data) -> AnyObject? { 215 | 216 | do{ 217 | let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) 218 | return json as AnyObject? 219 | 220 | } 221 | catch 222 | { 223 | return nil 224 | } 225 | } 226 | 227 | fileprivate class func cacheFilePathWithURL(_ URL: String, 228 | path: String , 229 | subPath:String = "") -> String { 230 | 231 | var newPath: String = "" 232 | if subPath.count == 0 { 233 | //保存最新的一级目录 234 | UserDefaults.standard.set(path, forKey: DDGCacheKeyPath) 235 | UserDefaults.standard.synchronize() 236 | newPath = self.cachePath() 237 | } else { 238 | newPath = self.cacheSubPath(subPath) 239 | } 240 | self.checkDirectory(newPath) 241 | //check路径 242 | let cacheFileNameString: String = "URL:\(URL) AppVersion:\(self.appVersionString())" 243 | let cacheFileName: String = self.md5StringFromString(cacheFileNameString) 244 | newPath = newPath + "/" + cacheFileName 245 | return newPath 246 | } 247 | 248 | fileprivate class func checkDirectory(_ path: String) { 249 | let fileManager: FileManager = FileManager.default 250 | 251 | var isDir = ObjCBool(false) //isDir判断是否为文件夹 252 | 253 | fileManager.fileExists(atPath: path, isDirectory: &isDir) 254 | 255 | if !fileManager.fileExists(atPath: path, isDirectory: &isDir) { 256 | 257 | self.createBaseDirectoryAtPath(path) 258 | 259 | } else { 260 | if !isDir.boolValue { 261 | 262 | do 263 | { 264 | try fileManager.removeItem(atPath: path) 265 | self.createBaseDirectoryAtPath(path) 266 | } 267 | catch let error as NSError 268 | { 269 | print("create cache directory failed, error = %@", error) 270 | } 271 | } 272 | } 273 | } 274 | 275 | fileprivate class func createBaseDirectoryAtPath(_ path: String) { 276 | do 277 | { 278 | try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil) 279 | print("path ="+path) 280 | self.addDoNotBackupAttribute(path) 281 | } 282 | catch let error as NSError 283 | { 284 | print("create cache directory failed, error = %@", error) 285 | } 286 | } 287 | 288 | fileprivate class func addDoNotBackupAttribute(_ path: String) { 289 | let url: URL = URL(fileURLWithPath: path) 290 | do 291 | { 292 | try (url as NSURL).setResourceValue(NSNumber(value: true as Bool), forKey: URLResourceKey.isExcludedFromBackupKey) 293 | } 294 | catch let error as NSError 295 | { 296 | print("error to set do not backup attribute, error = %@", error) 297 | } 298 | } 299 | 300 | fileprivate class func md5StringFromString(_ string: String) -> String { 301 | let str = string.cString(using: String.Encoding.utf8) 302 | let strLen = CC_LONG(string.lengthOfBytes(using: String.Encoding.utf8)) 303 | let digestLen = Int(CC_MD5_DIGEST_LENGTH) 304 | let result = UnsafeMutablePointer.allocate(capacity: digestLen); 305 | 306 | CC_MD5(str!, strLen, result); 307 | let hash = NSMutableString(); 308 | for i in 0 ..< digestLen { 309 | hash.appendFormat("%02x", result[i]); 310 | } 311 | return String(format: hash as String) 312 | } 313 | 314 | fileprivate class func appVersionString() -> String { 315 | 316 | return Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String 317 | } 318 | } 319 | 320 | 321 | 322 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/DDGDataCache_Swift-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/DDGDataCache_Swift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // DDGDataCache_Swift 4 | // 5 | // Created by dudongge on 2018/5/25. 6 | // Copyright © 2018年 dudongge. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | lazy var tableView: UITableView = { 14 | let tabelView = UITableView() 15 | tabelView.frame = CGRect(x: 10, y: 80, width:self.view.frame.size.width - 20 , height: self.view.frame.size.height - 280) 16 | tabelView.delegate = self 17 | tabelView.dataSource = self 18 | tabelView.backgroundColor = UIColor.yellow 19 | self.view.addSubview(tabelView) 20 | return tabelView 21 | }() 22 | var bottomLabel = UILabel() 23 | let dataSource = ["😜同步写入/更新缓存(只有主目录)", 24 | "📷同步写入/更新缓存(有二级目录)", 25 | "🐥异步写入/更新缓存(只有主目录)", 26 | "🍌异步写入/更新缓存(有二级目录)", 27 | "🐒获取全部缓存数据(主目录)", 28 | "🌧获取指定缓存数据(二级目录)", 29 | "🌞获取全部缓存大小", 30 | "🌛获取指定缓存大小", 31 | "🚚获取主缓存路径", 32 | "🚄获取指定缓存路径", 33 | "🍓清除全部缓存", 34 | "🍎清除指定缓存"] 35 | //构建模拟数据 36 | /** 37 | * 模拟数据请求URL 38 | */ 39 | let URLString = "https://github.com/dudongge" 40 | let URLString1 = "https://github.com/dudongge/DDGScreenShot" 41 | let URLString2 = "https://github.com/dudongge/DDGMeiTuan" 42 | let URLString3 = "https://github.com/dudongge/DGKVO" 43 | 44 | /** 45 | * 模拟服务器请求数据 46 | */ 47 | let responseObject = [ "sex" : "男", 48 | "city" : "上海", 49 | "logintime" : "1445267749", 50 | "name" : "东阁堂主", 51 | "group" : "3", 52 | "loginhit" : "4", 53 | "id" : "234328", 54 | "QQ" : "532835032" ] 55 | 56 | override func viewDidLoad() { 57 | super.viewDidLoad() 58 | self.view.backgroundColor = UIColor.white 59 | 60 | let titleLabel = UILabel() 61 | titleLabel.text = "DDGDataCache的用法介绍" 62 | titleLabel.textColor = UIColor.red 63 | titleLabel.textAlignment = .center 64 | titleLabel.frame = CGRect(x: 10, y: 50, width: self.view.frame.size.width - 20, height: 40) 65 | self.view.addSubview(titleLabel) 66 | 67 | 68 | self.tableView.reloadData() 69 | self.tableView.separatorColor = UIColor.clear 70 | self.tableView.tableFooterView = UIView() 71 | 72 | bottomLabel.text = "打印控制台信息" 73 | bottomLabel.textColor = UIColor.red 74 | bottomLabel.textAlignment = .center 75 | bottomLabel.numberOfLines = 0 76 | bottomLabel.frame = CGRect(x: 10, y: self.tableView.frame.origin.y + self.tableView.frame.size.height , width: self.view.frame.size.width - 20, height: 200) 77 | self.view.addSubview(bottomLabel) 78 | bottomLabel.backgroundColor = UIColor.green 79 | } 80 | 81 | override func didReceiveMemoryWarning() { 82 | super.didReceiveMemoryWarning() 83 | } 84 | 85 | } 86 | extension ViewController: UITableViewDelegate { 87 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 88 | switch indexPath.row { 89 | case 0: 90 | //同步写入 91 | if DDGDataCache.saveJsonResponseToCacheFile(self.responseObject as AnyObject, 92 | URL: self.URLString, 93 | path: "appCache") { 94 | let logStr = "😆(同步写入主目录)保存/更新成功" 95 | self.showLogs(logStr) 96 | } else { 97 | let logStr = "😤(同步写入主目录)保存/更新失败" 98 | self.showLogs(logStr) 99 | } 100 | case 1: 101 | //同步写入--有二级目录 102 | if DDGDataCache.saveJsonResponseToCacheFile(self.responseObject as AnyObject, 103 | URL: self.URLString1, 104 | path: "appCache", 105 | subPath: "userInfo") { 106 | let logStr = "😆(同步二级目录)保存/更新成功" 107 | self.showLogs(logStr) 108 | } else { 109 | let logStr = "😤(同步二级目录)保存/更新失败" 110 | self.showLogs(logStr) 111 | } 112 | case 2: 113 | DDGDataCache.save_asyncJsonResponseToCacheFile(self.responseObject as AnyObject, 114 | URL: self.URLString2, 115 | path: "appCache") { (succ) in 116 | if succ { 117 | self.showLogs("😆(异步写入主目录)保存/更新成功") 118 | } else { 119 | self.showLogs("😤(异步写入主目录)保存/更新失败") 120 | } 121 | } 122 | case 3: 123 | DDGDataCache.save_asyncJsonResponseToCacheFile(self.responseObject as AnyObject, 124 | URL: self.URLString3, 125 | path: "appCache", 126 | subPath: "userInfo") { (succ) in 127 | if succ { 128 | self.showLogs("😆(异步写入二级目录)保存/更新成功") 129 | } else { 130 | self.showLogs("😤(异步写入二级目录)保存/更新失败") 131 | } 132 | } 133 | case 4: 134 | //获取全部缓存 135 | if let json = DDGDataCache.cacheJsonWithURL(URLString) { 136 | self.showLogs(json.description) 137 | print(json.description ?? "") 138 | } 139 | case 5: 140 | //获取指定缓存数据 141 | if let json = DDGDataCache.cacheJsonWithURL(URLString,subPath: "userInfo") { 142 | self.showLogs(json.description) 143 | print(json) 144 | } 145 | //print("缓存大小(M)=\(cacheSize)") 146 | case 6: 147 | //获取全部缓存大小 148 | let allSize = DDGDataCache.cacheAllSize() 149 | let size = String(format: "%.6f", allSize) 150 | self.showLogs("缓存大小(M)=\(size)") 151 | 152 | case 7: 153 | //获取指定缓存大小 154 | let allSize = DDGDataCache.cacheSizeWithUrl("userInfo") 155 | self.showLogs("缓存大小(M)=\(allSize)") 156 | case 8: 157 | //获取总的缓存路径 158 | let cachePath = DDGDataCache.cachePath() 159 | self.showLogs("缓存路径=" + cachePath) 160 | case 9: 161 | //获取指定缓存路径 162 | let cacheSubpath = DDGDataCache.cacheSubPath("userInfo") 163 | self.showLogs("缓存路径=" + cacheSubpath) 164 | 165 | case 10: 166 | //清除全部缓存 167 | if DDGDataCache.clearAllCache() { 168 | self.showLogs("😆清除缓存成功") 169 | } else { 170 | self.showLogs("😤清除缓存失败") 171 | } 172 | 173 | case 11: 174 | //清除指定缓存 175 | if DDGDataCache.clearCacheWithUrl("userInfo") { 176 | self.showLogs("😆清除缓存成功") 177 | } else { 178 | self.showLogs("😤清除缓存失败") 179 | } 180 | print( #function) 181 | default: 182 | break 183 | } 184 | } 185 | func showLogs(_ log: String) { 186 | print(log) 187 | bottomLabel.text = log 188 | } 189 | } 190 | extension ViewController: UITableViewDataSource { 191 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 192 | return self.dataSource.count 193 | } 194 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 195 | let cell = UITableViewCell(style: .default, reuseIdentifier: "DDGDataCacheId") 196 | cell.textLabel?.text = self.dataSource[indexPath.row] 197 | cell.textLabel?.textAlignment = .center 198 | return cell 199 | } 200 | } 201 | extension ViewController { 202 | 203 | } 204 | -------------------------------------------------------------------------------- /DDGDataCache_Swift/gif/DDGDataCache.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dudongge/DDGDataCache_Swift/2ce9d885ddbeac6d8d54ac1231059f4c45a52b6c/DDGDataCache_Swift/gif/DDGDataCache.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 dudongge 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## DDGDataCache 3 | OC版本同步发出 请移步:[DDGDataCache_OC](https://github.com/dudongge/DDGDataCache_OC) 4 | # 5 | 或许有这样的需求,要求页面在无网状态先显示上一次显示的数据,这就涉及到缓存, 6 | 但是缓存又分为文件缓存,归档等,realm 太过笨重,归档太麻烦,最后选择了文件缓存, 7 | 看了很多博客,在参考了别人的缓存开源项目,功能太过简单单一化, 8 | 比如:我想删除某一个文件下的缓存信息,大部分是只提供了删除所有缓存, 9 | 不可以按目录删除。我总结了一个库,可以异步按照目录删除。 10 | 简单方便,快捷神速,是居家iOS码农必备之利器,先看功能效果 11 | 。简单方便,快捷神速,是居家iOS码农必备之利器,具体功能模块如下。 12 | 13 | ![image](https://raw.githubusercontent.com/dudongge/DDGDataCache_Swift/master/DDGDataCache_Swift/gif/DDGDataCache.gif) 14 | 15 | ``` 16 | //构建模拟数据 17 | /** 18 | * 模拟数据请求URL 19 | */ 20 | let URLString = "https://github.com/dudongge" 21 | let URLString1 = "https://github.com/dudongge/DDGScreenShot" 22 | let URLString2 = "https://github.com/dudongge/DDGMeiTuan" 23 | let URLString3 = "https://github.com/dudongge/DGKVO" 24 | 25 | /** 26 | * 模拟服务器请求数据 27 | */ 28 | let responseObject = [ "sex" : "男", 29 | "city" : "上海", 30 | "logintime" : "1445267749", 31 | "name" : "东阁堂主", 32 | "group" : "3", 33 | "loginhit" : "4", 34 | "id" : "234328", 35 | "QQ" : "532835032" ] 36 | ``` 37 | 1,同步写入 38 | ``` 39 | 写入/更新缓存(同步) [按APP版本号缓存,不同版本APP,同一接口缓存数据互不干扰] 40 | - parameter jsonResponse: 要写入的数据(JSON) 41 | - parameter URL: 数据请求URL 42 | - parameter path: 一级文件夹路径path(必须设置) 43 | - parameter subPath: 二级文件夹路径subPath(可设置-可不设置) 44 | - returns: 是否写入成功 45 | if DDGDataCache.saveJsonResponseToCacheFile(self.responseObject as AnyObject, 46 | URL: self.URLString, 47 | path: "appCache") { 48 | print("😆(同步)保存/更新成功") 49 | } else { 50 | print("😤(同步)保存/更新失败") 51 | } 52 | ``` 53 | 1,异步写入 54 | ``` 55 | 写入/更新缓存(异步) [按APP版本号缓存,不同版本APP,同一接口缓存数据互不干扰] 56 | - parameter jsonResponse: 要写入的数据(JSON) 57 | - parameter URL: 数据请求URL 58 | - parameter subPath: 二级文件夹路径subPath(可设置-可不设置) 59 | - parameter completed: 异步完成回调(主线程回调) 60 | 61 | DDGDataCache.save_asyncJsonResponseToCacheFile(self.responseObject as AnyObject, 62 | URL: self.URLString3, 63 | path: "appCache", 64 | subPath: "userInfo") { (succ) in 65 | if succ { 66 | print("😆(异步)保存/更新成功") 67 | } else { 68 | print("😤(异步)保存/更新失败") 69 | } 70 | } 71 | ``` 72 | 2.获取已经缓存的数据 73 | ``` 74 | 获取缓存的对象(同步) 75 | - parameter URL: 数据请求URL 76 | - parameter subPath: 二级文件夹路径subPath(可设置-可不设置) 77 | - returns: 缓存对象 78 | 79 | if let json = DDGDataCache.cacheJsonWithURL(URLString) { 80 | print(json) 81 | } 82 | //获取指定缓存数据 83 | if let json = DDGDataCache.cacheJsonWithURL(URLString,subPath: "userInfo") { 84 | print(json) 85 | } 86 | ``` 87 | 3.获取缓存数据的大小 88 | ``` 89 | //获取总的缓存大小 90 | let allSize = DDGDataCache.cacheAllSize() 91 | let size = String(format: "%.6f", allSize) 92 | print("缓存大小(M)=\(size)") 93 | //获取制定路径的缓存大小(传入二级路径) 94 | let allSize = DDGDataCache.cacheSizeWithUrl("userInfo") 95 | print("缓存大小(M)=\(allSize)") 96 | ``` 97 | 4,删除缓存 98 | ``` 99 | //清除全部缓存 100 | if DDGDataCache.clearAllCache() { 101 | print("😆清除缓存成功") 102 | } else { 103 | print("😤清除缓存失败") 104 | } 105 | //清除指定缓存 106 | if DDGDataCache.clearCacheWithUrl("userInfo") { 107 | print("😆清除缓存成功") 108 | } else { 109 | print("😤清除缓存失败") 110 | } 111 | ``` 112 | 113 | ## 直接把代码拖入 114 | ``` 115 | 直接将DDGDataCache文件夹下的文件拖入即可 116 | 117 | ``` 118 | ## 注意点(决定成功的关键) 119 | ``` 120 | 注意: 使用前请在'-Bridging-Header.h' 121 | 桥接文件中导入 #import 122 | 因为要用到MD5加密的东西 123 | ``` 124 | 125 | 126 | ## License 127 | 128 | DDGDataCache is available under the MIT license. See the LICENSE file for more info. 129 | 如果有问题欢迎提出,QQ:532835032 ,如果对您有帮助,希望您动动鼠标,不吝给个star.! 130 | 131 | 132 | ## instructions (备注) 133 | 134 | 鉴于还有部分童鞋还在OC上开发,本库相同功能翻译成OC,大家多了一个选择,附上链接,希望可以帮到你:[DDGDataCache_OC](https://github.com/dudongge/DDGDataCache_OC) 135 | 136 | 137 | 138 | --------------------------------------------------------------------------------