├── .gitignore ├── DLImageLoader Demo ├── DLImageLoader Demo.xcodeproj │ └── project.pbxproj ├── DLImageLoader Demo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift ├── Podfile └── Podfile.lock ├── DLImageLoader.podspec ├── DLImageLoader ├── CacheManager.swift ├── DLImageLoader.swift ├── Strategies.swift └── Transformation.swift ├── LICENSE ├── README.md └── dlil.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | -------------------------------------------------------------------------------- /DLImageLoader Demo/DLImageLoader Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6442AC75DA76513A76C55EE9 /* Pods_DLImageLoader_Demo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB44F7834C9524BF1B9BD574 /* Pods_DLImageLoader_Demo.framework */; }; 11 | D80956581BA8B5D600DED40C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D80956571BA8B5D600DED40C /* AppDelegate.swift */; }; 12 | D809565A1BA8B5D600DED40C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D80956591BA8B5D600DED40C /* ViewController.swift */; }; 13 | D809565D1BA8B5D600DED40C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D809565B1BA8B5D600DED40C /* Main.storyboard */; }; 14 | D809565F1BA8B5D600DED40C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D809565E1BA8B5D600DED40C /* Assets.xcassets */; }; 15 | D80956621BA8B5D600DED40C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D80956601BA8B5D600DED40C /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 4D5427782EFA3F84EE724F14 /* Pods-DLImageLoader Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DLImageLoader Demo.debug.xcconfig"; path = "Target Support Files/Pods-DLImageLoader Demo/Pods-DLImageLoader Demo.debug.xcconfig"; sourceTree = ""; }; 20 | 8ED65C44CF557CC30A58018C /* Pods-DLImageLoader Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DLImageLoader Demo.release.xcconfig"; path = "Target Support Files/Pods-DLImageLoader Demo/Pods-DLImageLoader Demo.release.xcconfig"; sourceTree = ""; }; 21 | AB44F7834C9524BF1B9BD574 /* Pods_DLImageLoader_Demo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DLImageLoader_Demo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | D80956541BA8B5D600DED40C /* DLImageLoader Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DLImageLoader Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | D80956571BA8B5D600DED40C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | D80956591BA8B5D600DED40C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 25 | D809565C1BA8B5D600DED40C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | D809565E1BA8B5D600DED40C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | D80956611BA8B5D600DED40C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | D80956631BA8B5D600DED40C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | D80956511BA8B5D600DED40C /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | 6442AC75DA76513A76C55EE9 /* Pods_DLImageLoader_Demo.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 571CA4DC93AFAC8E2499C2EB /* Pods */ = { 44 | isa = PBXGroup; 45 | children = ( 46 | 4D5427782EFA3F84EE724F14 /* Pods-DLImageLoader Demo.debug.xcconfig */, 47 | 8ED65C44CF557CC30A58018C /* Pods-DLImageLoader Demo.release.xcconfig */, 48 | ); 49 | path = Pods; 50 | sourceTree = ""; 51 | }; 52 | 7BC0D983089451F8A59FF78E /* Frameworks */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | AB44F7834C9524BF1B9BD574 /* Pods_DLImageLoader_Demo.framework */, 56 | ); 57 | name = Frameworks; 58 | sourceTree = ""; 59 | }; 60 | D809564B1BA8B5D600DED40C = { 61 | isa = PBXGroup; 62 | children = ( 63 | D80956561BA8B5D600DED40C /* DLImageLoader Demo */, 64 | D80956551BA8B5D600DED40C /* Products */, 65 | 571CA4DC93AFAC8E2499C2EB /* Pods */, 66 | 7BC0D983089451F8A59FF78E /* Frameworks */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | D80956551BA8B5D600DED40C /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | D80956541BA8B5D600DED40C /* DLImageLoader Demo.app */, 74 | ); 75 | name = Products; 76 | sourceTree = ""; 77 | }; 78 | D80956561BA8B5D600DED40C /* DLImageLoader Demo */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | D80956571BA8B5D600DED40C /* AppDelegate.swift */, 82 | D80956591BA8B5D600DED40C /* ViewController.swift */, 83 | D809565B1BA8B5D600DED40C /* Main.storyboard */, 84 | D809565E1BA8B5D600DED40C /* Assets.xcassets */, 85 | D80956601BA8B5D600DED40C /* LaunchScreen.storyboard */, 86 | D80956631BA8B5D600DED40C /* Info.plist */, 87 | ); 88 | path = "DLImageLoader Demo"; 89 | sourceTree = ""; 90 | }; 91 | /* End PBXGroup section */ 92 | 93 | /* Begin PBXNativeTarget section */ 94 | D80956531BA8B5D600DED40C /* DLImageLoader Demo */ = { 95 | isa = PBXNativeTarget; 96 | buildConfigurationList = D80956661BA8B5D600DED40C /* Build configuration list for PBXNativeTarget "DLImageLoader Demo" */; 97 | buildPhases = ( 98 | F6E8C9F46511A26B29392D53 /* [CP] Check Pods Manifest.lock */, 99 | D80956501BA8B5D600DED40C /* Sources */, 100 | D80956511BA8B5D600DED40C /* Frameworks */, 101 | D80956521BA8B5D600DED40C /* Resources */, 102 | 900F8B406591584548760626 /* [CP] Embed Pods Frameworks */, 103 | ); 104 | buildRules = ( 105 | ); 106 | dependencies = ( 107 | ); 108 | name = "DLImageLoader Demo"; 109 | productName = "DLImageLoader Demo"; 110 | productReference = D80956541BA8B5D600DED40C /* DLImageLoader Demo.app */; 111 | productType = "com.apple.product-type.application"; 112 | }; 113 | /* End PBXNativeTarget section */ 114 | 115 | /* Begin PBXProject section */ 116 | D809564C1BA8B5D600DED40C /* Project object */ = { 117 | isa = PBXProject; 118 | attributes = { 119 | LastUpgradeCheck = 1020; 120 | ORGANIZATIONNAME = "Andrew Lunevich"; 121 | TargetAttributes = { 122 | D80956531BA8B5D600DED40C = { 123 | CreatedOnToolsVersion = 7.1; 124 | LastSwiftMigration = 1020; 125 | }; 126 | }; 127 | }; 128 | buildConfigurationList = D809564F1BA8B5D600DED40C /* Build configuration list for PBXProject "DLImageLoader Demo" */; 129 | compatibilityVersion = "Xcode 3.2"; 130 | developmentRegion = en; 131 | hasScannedForEncodings = 0; 132 | knownRegions = ( 133 | en, 134 | Base, 135 | ); 136 | mainGroup = D809564B1BA8B5D600DED40C; 137 | productRefGroup = D80956551BA8B5D600DED40C /* Products */; 138 | projectDirPath = ""; 139 | projectRoot = ""; 140 | targets = ( 141 | D80956531BA8B5D600DED40C /* DLImageLoader Demo */, 142 | ); 143 | }; 144 | /* End PBXProject section */ 145 | 146 | /* Begin PBXResourcesBuildPhase section */ 147 | D80956521BA8B5D600DED40C /* Resources */ = { 148 | isa = PBXResourcesBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | D80956621BA8B5D600DED40C /* LaunchScreen.storyboard in Resources */, 152 | D809565F1BA8B5D600DED40C /* Assets.xcassets in Resources */, 153 | D809565D1BA8B5D600DED40C /* Main.storyboard in Resources */, 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | /* End PBXResourcesBuildPhase section */ 158 | 159 | /* Begin PBXShellScriptBuildPhase section */ 160 | 900F8B406591584548760626 /* [CP] Embed Pods Frameworks */ = { 161 | isa = PBXShellScriptBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | ); 165 | inputPaths = ( 166 | "${PODS_ROOT}/Target Support Files/Pods-DLImageLoader Demo/Pods-DLImageLoader Demo-frameworks.sh", 167 | "${BUILT_PRODUCTS_DIR}/DLImageLoader/DLImageLoader.framework", 168 | ); 169 | name = "[CP] Embed Pods Frameworks"; 170 | outputPaths = ( 171 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DLImageLoader.framework", 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | shellPath = /bin/sh; 175 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DLImageLoader Demo/Pods-DLImageLoader Demo-frameworks.sh\"\n"; 176 | showEnvVarsInLog = 0; 177 | }; 178 | F6E8C9F46511A26B29392D53 /* [CP] Check Pods Manifest.lock */ = { 179 | isa = PBXShellScriptBuildPhase; 180 | buildActionMask = 2147483647; 181 | files = ( 182 | ); 183 | inputFileListPaths = ( 184 | ); 185 | inputPaths = ( 186 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 187 | "${PODS_ROOT}/Manifest.lock", 188 | ); 189 | name = "[CP] Check Pods Manifest.lock"; 190 | outputFileListPaths = ( 191 | ); 192 | outputPaths = ( 193 | "$(DERIVED_FILE_DIR)/Pods-DLImageLoader Demo-checkManifestLockResult.txt", 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | shellPath = /bin/sh; 197 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 198 | showEnvVarsInLog = 0; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | D80956501BA8B5D600DED40C /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | D809565A1BA8B5D600DED40C /* ViewController.swift in Sources */, 208 | D80956581BA8B5D600DED40C /* AppDelegate.swift in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | D809565B1BA8B5D600DED40C /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | D809565C1BA8B5D600DED40C /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | D80956601BA8B5D600DED40C /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | D80956611BA8B5D600DED40C /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | D80956641BA8B5D600DED40C /* Debug */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = dwarf; 265 | ENABLE_STRICT_OBJC_MSGSEND = YES; 266 | ENABLE_TESTABILITY = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_DYNAMIC_NO_PIC = NO; 269 | GCC_NO_COMMON_BLOCKS = YES; 270 | GCC_OPTIMIZATION_LEVEL = 0; 271 | GCC_PREPROCESSOR_DEFINITIONS = ( 272 | "DEBUG=1", 273 | "$(inherited)", 274 | ); 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 282 | MTL_ENABLE_DEBUG_INFO = YES; 283 | ONLY_ACTIVE_ARCH = YES; 284 | SDKROOT = iphoneos; 285 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 286 | SWIFT_VERSION = 5.0; 287 | TARGETED_DEVICE_FAMILY = "1,2"; 288 | }; 289 | name = Debug; 290 | }; 291 | D80956651BA8B5D600DED40C /* Release */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | ALWAYS_SEARCH_USER_PATHS = NO; 295 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 296 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 297 | CLANG_CXX_LIBRARY = "libc++"; 298 | CLANG_ENABLE_MODULES = YES; 299 | CLANG_ENABLE_OBJC_ARC = YES; 300 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 301 | CLANG_WARN_BOOL_CONVERSION = YES; 302 | CLANG_WARN_COMMA = YES; 303 | CLANG_WARN_CONSTANT_CONVERSION = YES; 304 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 305 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 306 | CLANG_WARN_EMPTY_BODY = YES; 307 | CLANG_WARN_ENUM_CONVERSION = YES; 308 | CLANG_WARN_INFINITE_RECURSION = YES; 309 | CLANG_WARN_INT_CONVERSION = YES; 310 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 311 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 312 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 313 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 314 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 315 | CLANG_WARN_STRICT_PROTOTYPES = YES; 316 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 320 | COPY_PHASE_STRIP = NO; 321 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 322 | ENABLE_NS_ASSERTIONS = NO; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | GCC_C_LANGUAGE_STANDARD = gnu99; 325 | GCC_NO_COMMON_BLOCKS = YES; 326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 328 | GCC_WARN_UNDECLARED_SELECTOR = YES; 329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 330 | GCC_WARN_UNUSED_FUNCTION = YES; 331 | GCC_WARN_UNUSED_VARIABLE = YES; 332 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 333 | MTL_ENABLE_DEBUG_INFO = NO; 334 | SDKROOT = iphoneos; 335 | SWIFT_COMPILATION_MODE = wholemodule; 336 | SWIFT_VERSION = 5.0; 337 | TARGETED_DEVICE_FAMILY = "1,2"; 338 | VALIDATE_PRODUCT = YES; 339 | }; 340 | name = Release; 341 | }; 342 | D80956671BA8B5D600DED40C /* Debug */ = { 343 | isa = XCBuildConfiguration; 344 | baseConfigurationReference = 4D5427782EFA3F84EE724F14 /* Pods-DLImageLoader Demo.debug.xcconfig */; 345 | buildSettings = { 346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 347 | INFOPLIST_FILE = "DLImageLoader Demo/Info.plist"; 348 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 349 | PRODUCT_BUNDLE_IDENTIFIER = "com.lunevich.DLImageLoader-Demo"; 350 | PRODUCT_NAME = "$(TARGET_NAME)"; 351 | SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; 352 | SWIFT_VERSION = 5.0; 353 | }; 354 | name = Debug; 355 | }; 356 | D80956681BA8B5D600DED40C /* Release */ = { 357 | isa = XCBuildConfiguration; 358 | baseConfigurationReference = 8ED65C44CF557CC30A58018C /* Pods-DLImageLoader Demo.release.xcconfig */; 359 | buildSettings = { 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | INFOPLIST_FILE = "DLImageLoader Demo/Info.plist"; 362 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 363 | PRODUCT_BUNDLE_IDENTIFIER = "com.lunevich.DLImageLoader-Demo"; 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; 366 | SWIFT_VERSION = 5.0; 367 | }; 368 | name = Release; 369 | }; 370 | /* End XCBuildConfiguration section */ 371 | 372 | /* Begin XCConfigurationList section */ 373 | D809564F1BA8B5D600DED40C /* Build configuration list for PBXProject "DLImageLoader Demo" */ = { 374 | isa = XCConfigurationList; 375 | buildConfigurations = ( 376 | D80956641BA8B5D600DED40C /* Debug */, 377 | D80956651BA8B5D600DED40C /* Release */, 378 | ); 379 | defaultConfigurationIsVisible = 0; 380 | defaultConfigurationName = Release; 381 | }; 382 | D80956661BA8B5D600DED40C /* Build configuration list for PBXNativeTarget "DLImageLoader Demo" */ = { 383 | isa = XCConfigurationList; 384 | buildConfigurations = ( 385 | D80956671BA8B5D600DED40C /* Debug */, 386 | D80956681BA8B5D600DED40C /* Release */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | defaultConfigurationName = Release; 390 | }; 391 | /* End XCConfigurationList section */ 392 | }; 393 | rootObject = D809564C1BA8B5D600DED40C /* Project object */; 394 | } 395 | -------------------------------------------------------------------------------- /DLImageLoader Demo/DLImageLoader Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DLImageLoader Demo 4 | // 5 | // Created by Andrew Lunevich on 9/15/15. 6 | // Copyright © 2015 Andrew Lunevich. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, 17 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | 20 | return true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DLImageLoader Demo/DLImageLoader Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /DLImageLoader Demo/DLImageLoader Demo/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 | 27 | 28 | -------------------------------------------------------------------------------- /DLImageLoader Demo/DLImageLoader Demo/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 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /DLImageLoader Demo/DLImageLoader Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | NSAppTransportSecurity 40 | 41 | NSAllowsArbitraryLoads 42 | 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /DLImageLoader Demo/DLImageLoader Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // DLImageLoader Demo 4 | // 5 | // Created by Andrew Lunevich on 9/15/15. 6 | // Copyright © 2015 Andrew Lunevich. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import DLImageLoader 11 | 12 | class ViewController: UIViewController { 13 | 14 | @IBOutlet weak var imageView: UIImageView! 15 | 16 | private var task: URLSessionDataTask? 17 | 18 | deinit { 19 | task?.cancel() 20 | } 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | 25 | refreshDidPress(self) 26 | } 27 | 28 | @IBAction func clearDidPress(_ sender: Any) { 29 | DLImageLoader.shared.clearCache() 30 | } 31 | 32 | @IBAction func refreshDidPress(_ sender: Any) { 33 | let url = URL(string: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Swift_logo.svg/2000px-Swift_logo.svg.png") 34 | 35 | task = DLImageLoader.shared.load(url, into: imageView) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /DLImageLoader Demo/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | use_frameworks! 3 | 4 | target "DLImageLoader Demo" do 5 | platform :ios, '13.0' 6 | pod "DLImageLoader", :path => "../" 7 | end 8 | -------------------------------------------------------------------------------- /DLImageLoader Demo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - DLImageLoader (4.2.0) 3 | 4 | DEPENDENCIES: 5 | - DLImageLoader (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | DLImageLoader: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | DLImageLoader: 482a35d19dabeea7fb882cbc7c303ac168f7aa93 13 | 14 | PODFILE CHECKSUM: 88c9b4f5f65bc0f4b6e86a2837b957d0ca671840 15 | 16 | COCOAPODS: 1.12.0 17 | -------------------------------------------------------------------------------- /DLImageLoader.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'DLImageLoader' 3 | s.version = '4.2.1' 4 | s.summary = 'DLImageLoader is a reusable instrument for asynchronous image loading and caching.' 5 | s.description = <<-DESC 6 | DLImageLoader for iOS. 7 | The library is a reusable instrument for asynchronous image loading, caching and displaying. 8 | DESC 9 | s.homepage = 'https://github.com/AndreyLunevich/DLImageLoader-iOS' 10 | s.license = { :type => 'Apache License, Version 2.0', :file => 'LICENSE' } 11 | s.author = { 'Andrew Lunevich' => 'andrey.lunevich@gmail.com' } 12 | s.platform = :ios 13 | s.source = { :git => 'https://github.com/AndreyLunevich/DLImageLoader-iOS.git', :tag => s.version.to_s } 14 | s.source_files = 'DLImageLoader', 'DLImageLoader/**/*.swift' 15 | 16 | s.ios.deployment_target = '13.0' 17 | 18 | s.swift_version = '5.8' 19 | end -------------------------------------------------------------------------------- /DLImageLoader/CacheManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CacheManager.swift 3 | // 4 | // Created by Andrey Lunevich 5 | // Copyright © 2015 Andrey Lunevich. All rights reserved. 6 | 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | import UIKit 20 | 21 | public final class CacheManager { 22 | 23 | public class var cacheDirectoryPath: String { 24 | let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0] as NSString 25 | 26 | return path.appendingPathComponent("dlil-cache") 27 | } 28 | 29 | public enum Storage { 30 | case memory 31 | case disk(path: String) 32 | case all(diskPath: String) 33 | } 34 | 35 | private let storage: Storage 36 | private let cache = NSCache() 37 | 38 | public init(storage: Storage = .all(diskPath: cacheDirectoryPath)) throws { 39 | self.storage = storage 40 | 41 | try setupStorage(storage) 42 | } 43 | 44 | /** 45 | Get the image from the cache by the key (image url). 46 | At first will try to get image from memory cache 47 | If image will not found, will try to get image from disk cache 48 | - parameter key: Url of image that using as cache key. 49 | */ 50 | internal func image(forKey key: String, storage: Storage? = nil) throws -> UIImage? { 51 | let storage = storage ?? self.storage 52 | 53 | try setupStorage(storage) 54 | 55 | switch storage { 56 | case .memory: 57 | return cache.object(forKey: key as NSString) 58 | 59 | case .disk(let path): 60 | return UIImage(contentsOfFile: imagePath(base: path, key: key)) 61 | 62 | case .all(let diskPath): 63 | var image = cache.object(forKey: key as NSString) 64 | 65 | if image == nil { 66 | image = UIImage(contentsOfFile: imagePath(base: diskPath, key: key)) 67 | } 68 | 69 | return image 70 | } 71 | } 72 | 73 | /** 74 | Save the image in the cache for the key (image url). 75 | - parameter image: UIImage to save in cache. 76 | - parameter key: Url of image that using as cache key 77 | */ 78 | internal func saveImage(_ image: UIImage, forKey key: String, storage: Storage? = nil) throws { 79 | let storage = storage ?? self.storage 80 | 81 | try setupStorage(storage) 82 | 83 | DispatchQueue.global(qos: .background).async { 84 | switch storage { 85 | case .memory: 86 | self.cache.setObject(image, forKey: key as NSString) 87 | 88 | case .disk(let path): 89 | try? self.saveImage(image, byPath: self.imagePath(base: path, key: key)) 90 | 91 | case .all(let diskPath): 92 | self.cache.setObject(image, forKey: key as NSString) 93 | 94 | try? self.saveImage(image, byPath: self.imagePath(base: diskPath, key: key)) 95 | } 96 | } 97 | } 98 | 99 | /** 100 | Clear memory and disk cache 101 | */ 102 | internal func clear(_ completion: ((_ error: Error?) -> Void)? = nil) { 103 | cache.removeAllObjects() 104 | 105 | DispatchQueue.global(qos: .background).async { 106 | var error: Error? 107 | 108 | switch self.storage { 109 | case .memory: 110 | break 111 | 112 | case .disk(let path), .all(let path): 113 | let fileManager = FileManager.default 114 | 115 | do { 116 | let files = try fileManager.contentsOfDirectory(atPath: path) 117 | for file in files { 118 | try fileManager.removeItem(atPath: self.imagePath(base: path, key: file)) 119 | } 120 | } catch let err { 121 | error = err 122 | } 123 | } 124 | 125 | DispatchQueue.main.async { 126 | completion?(error) 127 | } 128 | } 129 | } 130 | 131 | // MARK: - private methods 132 | 133 | private func setupStorage(_ storage: Storage) throws { 134 | switch storage { 135 | case .memory: 136 | break 137 | 138 | case .disk(let path), .all(let path): 139 | var isDir: ObjCBool = false 140 | let fileManager = FileManager.default 141 | if !fileManager.fileExists(atPath: path, isDirectory: &isDir) { 142 | try fileManager.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) 143 | } 144 | } 145 | } 146 | 147 | private func saveImage(_ image: UIImage, byPath path: String) throws { 148 | // create file if not exist 149 | let fileManager = FileManager.default 150 | if !fileManager.fileExists(atPath: path) { 151 | fileManager.createFile(atPath: path, contents: nil, attributes: nil) 152 | } 153 | 154 | try image.pngData()?.write(to: URL(fileURLWithPath: path), options: .atomic) 155 | } 156 | 157 | private func imagePath(base: String, key: String) -> String { 158 | return (base as NSString).appendingPathComponent(key.replacingOccurrences(of: "/", with: "_")) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /DLImageLoader/DLImageLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DLILManager.swift 3 | // 4 | // Created by Andrey Lunevich 5 | // Copyright © 2015 Andrey Lunevich. All rights reserved. 6 | 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | import UIKit 20 | 21 | public final class DLImageLoader { 22 | 23 | public typealias Result = (_ result: Swift.Result) -> Void 24 | 25 | public enum Error: Swift.Error { 26 | case invalidUrl 27 | case loadingFailed(Swift.Error) 28 | case corruptedImage 29 | } 30 | 31 | public var enableLog = false 32 | 33 | /** 34 | Instance method 35 | - returns: DLImageLoader instance. 36 | */ 37 | public static let shared = DLImageLoader() 38 | 39 | private let session: URLSession 40 | private var cache: CacheManager? 41 | 42 | private init() { 43 | session = URLSession(configuration: URLSessionConfiguration.default, 44 | delegate: nil, 45 | delegateQueue: OperationQueue.main) 46 | 47 | do { 48 | setupCache(try CacheManager()) 49 | } catch { 50 | log(message: error.localizedDescription) 51 | } 52 | } 53 | 54 | @discardableResult 55 | public func setupCache(_ cache: CacheManager) -> Self { 56 | self.cache?.clear() 57 | 58 | self.cache = cache 59 | 60 | return self 61 | } 62 | 63 | /** 64 | Load image from url 65 | - parameter url: The url of image. 66 | - parameter into: UIImageView in which will display image. 67 | - parameter completion: Completion block that will be called after image loading. 68 | */ 69 | @discardableResult 70 | public func load(_ url: URL?, 71 | placeholder: UIImage? = nil, 72 | into imageView: UIImageView, 73 | apply transformations: [Transformation] = [], 74 | cacheStrategy: CacheStrategy = .tranformed(key: nil), 75 | completion: Result? = nil) -> URLSessionDataTask? { 76 | imageView.image = placeholder 77 | 78 | guard let url = url else { 79 | completion?(.failure(.invalidUrl)) 80 | 81 | return nil 82 | } 83 | 84 | return load(URLRequest(url: url), 85 | into: imageView, 86 | apply: transformations, 87 | cacheStrategy: cacheStrategy, 88 | completion: completion) 89 | } 90 | 91 | /** 92 | Load image from request 93 | - parameter request: The request of image. 94 | - parameter into: UIImageView in which will display image. 95 | - parameter completion: Completion block that will be called after image loading. 96 | */ 97 | @discardableResult 98 | public func load(_ request: URLRequest, 99 | placeholder: UIImage? = nil, 100 | into imageView: UIImageView, 101 | apply transformations: [Transformation] = [], 102 | cacheStrategy: CacheStrategy = .tranformed(key: nil), 103 | completion: Result? = nil) -> URLSessionDataTask? { 104 | imageView.image = placeholder 105 | 106 | return load(request, apply: transformations, cacheStrategy: cacheStrategy) { result in 107 | switch result { 108 | case .success(let image): 109 | if let completion = completion { 110 | completion(.success(image)) 111 | } else { 112 | imageView.image = image 113 | imageView.setNeedsDisplay() 114 | } 115 | 116 | case .failure(let error): 117 | completion?(.failure(error)) 118 | } 119 | } 120 | } 121 | 122 | /** 123 | Load image from url 124 | - parameter url: The url of image. 125 | - parameter completion: Completion block that will be called after image loading. 126 | */ 127 | @discardableResult 128 | public func load(_ url: URL?, 129 | apply transformations: [Transformation] = [], 130 | cacheStrategy: CacheStrategy = .tranformed(key: nil), 131 | completion: Result? = nil) -> URLSessionDataTask? { 132 | guard let url = url else { 133 | completion?(.failure(.invalidUrl)) 134 | 135 | return nil 136 | } 137 | 138 | return load(URLRequest(url: url), 139 | apply: transformations, 140 | cacheStrategy: cacheStrategy, 141 | completion: completion) 142 | } 143 | 144 | /** 145 | Load image from request 146 | - parameter request: The request of image. 147 | - parameter completion: Completion block that will be called after image loading. 148 | */ 149 | @discardableResult 150 | public func load(_ request: URLRequest, 151 | apply transformations: [Transformation] = [], 152 | cacheStrategy: CacheStrategy = .tranformed(key: nil), 153 | completion: Result? = nil) -> URLSessionDataTask? { 154 | guard let url = request.url?.absoluteString, !url.isEmpty else { 155 | completion?(.failure(.invalidUrl)) 156 | 157 | return nil 158 | } 159 | 160 | log(message: "loading image from url => \(url)") 161 | 162 | if let image = try? image(for: cacheStrategy, url: url) { 163 | log(message: "got an image from the cache") 164 | 165 | completion?(.success(image)) 166 | 167 | return nil 168 | } 169 | 170 | let task = session.dataTask(with: request) { [weak self] (data, response, error) in 171 | if let error = error { 172 | completion?(.failure(.loadingFailed(error))) 173 | 174 | self?.log(message: "error image loading \(error)") 175 | } else { 176 | if let data = data, let image = UIImage(data: data) { 177 | DispatchQueue.global(qos: .userInitiated).async { 178 | var result = image 179 | for transformation in transformations { 180 | result = transformation.transform(result) 181 | } 182 | 183 | // save loaded image to cache 184 | try? self?.saveImage(original: image, transformed: result, strategy: cacheStrategy, url: url) 185 | 186 | DispatchQueue.main.async { 187 | completion?(.success(result)) 188 | 189 | self?.log(message: "loaded image from url => \(url)") 190 | } 191 | } 192 | } else { 193 | completion?(.failure(.corruptedImage)) 194 | } 195 | } 196 | } 197 | 198 | task.resume() 199 | 200 | return task 201 | } 202 | 203 | /** 204 | Cancel task 205 | - parameter url: Url to stop a task 206 | */ 207 | public func cancelOperation(url: URL?) { 208 | allTasks(of: session) { tasks in 209 | for task in tasks where task.currentRequest?.url == url { 210 | task.cancel() 211 | } 212 | } 213 | } 214 | 215 | /** 216 | Stop all active tasks 217 | */ 218 | public func cancelAllOperations() { 219 | allTasks(of: session) { tasks in 220 | for task in tasks { 221 | task.cancel() 222 | } 223 | } 224 | } 225 | 226 | /** 227 | Clear cache of DLImageLoader 228 | */ 229 | public func clearCache(_ completion: ((_ error: Swift.Error?) -> Void)? = nil) { 230 | cache?.clear(completion) 231 | } 232 | 233 | 234 | // MARK: Private Methods 235 | 236 | private func image(for strategy: CacheStrategy, url: String) throws -> UIImage? { 237 | var image: UIImage? 238 | 239 | switch strategy { 240 | case .original(let key), .tranformed(let key): 241 | image = try cache?.image(forKey: key ?? url) 242 | 243 | case .both(let original, let tranformed): 244 | image = try cache?.image(forKey: original ?? url) 245 | 246 | if image == nil { 247 | image = try cache?.image(forKey: tranformed ?? url) 248 | } 249 | } 250 | 251 | return image 252 | } 253 | 254 | private func saveImage(original: UIImage, transformed: UIImage, strategy: CacheStrategy, url: String) throws { 255 | switch strategy { 256 | case .original(let key): 257 | try cache?.saveImage(original, forKey: key ?? url) 258 | 259 | case .tranformed(let key): 260 | try cache?.saveImage(transformed, forKey: key ?? "\(url)+transformed") 261 | 262 | case .both(let originalKey, let tranformedKey): 263 | try cache?.saveImage(original, forKey: originalKey ?? url) 264 | 265 | try cache?.saveImage(transformed, forKey: tranformedKey ?? "\(url)+transformed") 266 | } 267 | } 268 | 269 | private func allTasks(of session: URLSession, completionHandler: @escaping ([URLSessionTask]) -> Void) { 270 | session.getTasksWithCompletionHandler { (data, upload, download) in 271 | let tasks = data as [URLSessionTask] + upload as [URLSessionTask] + download as [URLSessionTask] 272 | 273 | completionHandler(tasks) 274 | } 275 | } 276 | 277 | private func log(message: String) { 278 | if enableLog { 279 | print("DLImageLoader: \(message)") 280 | } 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /DLImageLoader/Strategies.swift: -------------------------------------------------------------------------------- 1 | public enum CacheStrategy { 2 | 3 | case original(key: String?) 4 | case tranformed(key: String?) 5 | case both(original: String?, tranformed: String?) 6 | } 7 | -------------------------------------------------------------------------------- /DLImageLoader/Transformation.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | public protocol Transformation { 4 | 5 | func transform(_ image: UIImage) -> UIImage 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-present, Andrey Lunevich 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DLImageLoader-iOS 2 | ================= 3 | 4 | Image Loader for iOS.
5 | This project aims to provide a reusable instrument for asynchronous image loading, caching and displaying. 6 | 7 | ![Screenshot](https://raw.githubusercontent.com/AndreyLunevich/DLImageLoader-iOS/master/dlil.png) 8 | 9 | ## Instalation 10 | 11 | | Swift | DLImageLoader | 12 | | ----- | ------------- | 13 | | 5.X | _ | 14 | | 4.X | 4.2.0 | 15 | | 2.2 | 1.2.0-swift | 16 | 17 | [Objective-C](https://github.com/AndreyLunevich/DLImageLoader-iOS/tree/objc) - "DLImageLoader", "~> 2.2.0" 18 | 19 | ### Cocoapods 20 | 21 | [CocoaPods](http://cocoapods.org) is the recommended way to add DLImageLoader to your project. 22 | 23 | 1. Add a pod entry for DLImageLoader to your Podfile `pod 'DLImageLoader'` 24 | 2. Install the pod(s) by running `pod install`. 25 | 26 | ## Usage 27 | 28 | ### Simple 29 | 30 |
31 | DLImageLoader.shared.load("image_url_here", into: "UIImageView here")
32 | 
33 | 34 | ### Complete 35 | 36 |
37 | DLImageLoader.shared.load("image_url_here", into: "UIImageView here") { result in
38 |     switch result {
39 |     case .success(let image):
40 | 
41 |     case .failure(let error):
42 | 
43 |     }
44 | }
45 | 
46 | 47 | ### Cancel loading operations 48 | 49 |
50 | DLImageLoader.shared.cancelOperation(url: "image_url_here")
51 | 
52 | 53 |
54 | DLImageLoader.shared.cancelAllOperations()
55 | 
56 | 57 | 58 | ## Plans 59 | 60 | Objective-C version will be fully moved to [objc](https://github.com/AndreyLunevich/DLImageLoader-iOS/tree/objc) branch 61 | 62 | ## Applications using DLImageLoader 63 | 64 | [Share TV](https://itunes.apple.com/br/app/share-tv-rede-social-para/id1097456577?mt=8) | 65 | [Nootri The Nutrition Manager](https://itunes.apple.com/US/app/id912109727?mt=8) | 66 | [Plusarium](https://itunes.apple.com/us/app/plusarium/id901280642?l=ru&ls=1&mt=8) | 67 | [Naomuseum](https://itunes.apple.com/ru/app/naomuseum/id847290457?mt=8) | [Aerobia](https://itunes.apple.com/us/app/aerobia/id566375588?mt=8) | [StreetForm](https://itunes.apple.com/us/app/easy/id874395902?ls=1&mt=8) 68 | 69 | ## License 70 | 71 | See [LICENSE](https://github.com/AndreyLunevich/DLImageLoader-iOS/blob/master/LICENSE) for more information. -------------------------------------------------------------------------------- /dlil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AndreyLunevich/DLImageLoader-iOS/977df6f4d114e4a12749fcc4538e86c1f0201b1b/dlil.png --------------------------------------------------------------------------------