├── .gitignore ├── .swift-version ├── Cartfile ├── Cartfile.resolved ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Example.xcworkspace │ └── contents.xcworkspacedata ├── Example │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── Main.storyboard │ ├── Transformer.swift │ ├── Utilities.swift │ ├── View │ │ ├── CollectionViewCell.swift │ │ └── CollectionViewCell.xib │ └── ViewController.swift └── Podfile ├── KingfisherExtension.podspec ├── KingfisherExtension.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── KingfisherExtension.xcscheme ├── KingfisherExtension ├── ImageStyle.swift ├── Info.plist ├── KingfisherExtension.h ├── UIButton+Kingfisher.swift ├── UIImage+Navi.swift ├── UIImageView+Kingfisher.swift └── UIView+Kingfisher.swift ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | .idea 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | Pods/ 38 | Podfile.lock 39 | 40 | # Carthage 41 | # 42 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 43 | # Carthage/Checkouts 44 | 45 | Carthage 46 | 47 | .DS_Store 48 | WHATSNEW.md 49 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "onevcat/Kingfisher" 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "onevcat/Kingfisher" "3.0.1" 2 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | AD4D3EA09EB1BCD0711784A6 /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C206E54F70DC419EFFD7BF5 /* Pods_Example.framework */; }; 11 | ED95B8B01D644752007DEA62 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED95B8AF1D644752007DEA62 /* AppDelegate.swift */; }; 12 | ED95B8B71D644752007DEA62 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ED95B8B61D644752007DEA62 /* Assets.xcassets */; }; 13 | ED95B8BA1D644752007DEA62 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ED95B8B81D644752007DEA62 /* LaunchScreen.storyboard */; }; 14 | ED95B8C21D64477B007DEA62 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ED95B8C11D64477B007DEA62 /* Main.storyboard */; }; 15 | ED95B8C91D644783007DEA62 /* Transformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED95B8C31D644783007DEA62 /* Transformer.swift */; }; 16 | ED95B8CA1D644783007DEA62 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED95B8C41D644783007DEA62 /* Utilities.swift */; }; 17 | ED95B8CB1D644783007DEA62 /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED95B8C61D644783007DEA62 /* CollectionViewCell.swift */; }; 18 | ED95B8CC1D644783007DEA62 /* CollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = ED95B8C71D644783007DEA62 /* CollectionViewCell.xib */; }; 19 | ED95B8CD1D644783007DEA62 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED95B8C81D644783007DEA62 /* ViewController.swift */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 2C206E54F70DC419EFFD7BF5 /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 510CEFBACF2F8BD46E8472AF /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; }; 25 | 6915458786C7AB4ECE47F01B /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; 26 | ED95B8AC1D644752007DEA62 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | ED95B8AF1D644752007DEA62 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 28 | ED95B8B61D644752007DEA62 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 29 | ED95B8B91D644752007DEA62 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 30 | ED95B8BB1D644752007DEA62 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | ED95B8C11D64477B007DEA62 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 32 | ED95B8C31D644783007DEA62 /* Transformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Transformer.swift; sourceTree = ""; }; 33 | ED95B8C41D644783007DEA62 /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; 34 | ED95B8C61D644783007DEA62 /* CollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCell.swift; sourceTree = ""; }; 35 | ED95B8C71D644783007DEA62 /* CollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CollectionViewCell.xib; sourceTree = ""; }; 36 | ED95B8C81D644783007DEA62 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | ED95B8A91D644752007DEA62 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | AD4D3EA09EB1BCD0711784A6 /* Pods_Example.framework in Frameworks */, 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | /* End PBXFrameworksBuildPhase section */ 49 | 50 | /* Begin PBXGroup section */ 51 | 6D18B6BA89ACE47287FC4B80 /* Frameworks */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | 2C206E54F70DC419EFFD7BF5 /* Pods_Example.framework */, 55 | ); 56 | name = Frameworks; 57 | sourceTree = ""; 58 | }; 59 | 72CA4D52A80BB11F1B93A497 /* Pods */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 510CEFBACF2F8BD46E8472AF /* Pods-Example.debug.xcconfig */, 63 | 6915458786C7AB4ECE47F01B /* Pods-Example.release.xcconfig */, 64 | ); 65 | name = Pods; 66 | sourceTree = ""; 67 | }; 68 | ED95B8A31D644752007DEA62 = { 69 | isa = PBXGroup; 70 | children = ( 71 | ED95B8AE1D644752007DEA62 /* Example */, 72 | ED95B8AD1D644752007DEA62 /* Products */, 73 | 72CA4D52A80BB11F1B93A497 /* Pods */, 74 | 6D18B6BA89ACE47287FC4B80 /* Frameworks */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | ED95B8AD1D644752007DEA62 /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | ED95B8AC1D644752007DEA62 /* Example.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | ED95B8AE1D644752007DEA62 /* Example */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | ED95B8AF1D644752007DEA62 /* AppDelegate.swift */, 90 | ED95B8C81D644783007DEA62 /* ViewController.swift */, 91 | ED95B8C31D644783007DEA62 /* Transformer.swift */, 92 | ED95B8C41D644783007DEA62 /* Utilities.swift */, 93 | ED95B8C51D644783007DEA62 /* View */, 94 | ED95B8C11D64477B007DEA62 /* Main.storyboard */, 95 | ED95B8B61D644752007DEA62 /* Assets.xcassets */, 96 | ED95B8B81D644752007DEA62 /* LaunchScreen.storyboard */, 97 | ED95B8BB1D644752007DEA62 /* Info.plist */, 98 | ); 99 | path = Example; 100 | sourceTree = ""; 101 | }; 102 | ED95B8C51D644783007DEA62 /* View */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | ED95B8C61D644783007DEA62 /* CollectionViewCell.swift */, 106 | ED95B8C71D644783007DEA62 /* CollectionViewCell.xib */, 107 | ); 108 | path = View; 109 | sourceTree = ""; 110 | }; 111 | /* End PBXGroup section */ 112 | 113 | /* Begin PBXNativeTarget section */ 114 | ED95B8AB1D644752007DEA62 /* Example */ = { 115 | isa = PBXNativeTarget; 116 | buildConfigurationList = ED95B8BE1D644752007DEA62 /* Build configuration list for PBXNativeTarget "Example" */; 117 | buildPhases = ( 118 | ABD6F1F3836737799102B65D /* [CP] Check Pods Manifest.lock */, 119 | ED95B8A81D644752007DEA62 /* Sources */, 120 | ED95B8A91D644752007DEA62 /* Frameworks */, 121 | ED95B8AA1D644752007DEA62 /* Resources */, 122 | 496DF4F1F2DB033F4B64A267 /* [CP] Embed Pods Frameworks */, 123 | 7C8B8B5108974DD3029A6ADC /* [CP] Copy Pods Resources */, 124 | D1FCC2B33A736165206B3EE1 /* Embed Pods Frameworks */, 125 | ); 126 | buildRules = ( 127 | ); 128 | dependencies = ( 129 | ); 130 | name = Example; 131 | productName = Example; 132 | productReference = ED95B8AC1D644752007DEA62 /* Example.app */; 133 | productType = "com.apple.product-type.application"; 134 | }; 135 | /* End PBXNativeTarget section */ 136 | 137 | /* Begin PBXProject section */ 138 | ED95B8A41D644752007DEA62 /* Project object */ = { 139 | isa = PBXProject; 140 | attributes = { 141 | LastSwiftUpdateCheck = 0730; 142 | LastUpgradeCheck = 0800; 143 | ORGANIZATIONNAME = Limon; 144 | TargetAttributes = { 145 | ED95B8AB1D644752007DEA62 = { 146 | CreatedOnToolsVersion = 7.3.1; 147 | LastSwiftMigration = 0800; 148 | }; 149 | }; 150 | }; 151 | buildConfigurationList = ED95B8A71D644752007DEA62 /* Build configuration list for PBXProject "Example" */; 152 | compatibilityVersion = "Xcode 3.2"; 153 | developmentRegion = English; 154 | hasScannedForEncodings = 0; 155 | knownRegions = ( 156 | en, 157 | Base, 158 | ); 159 | mainGroup = ED95B8A31D644752007DEA62; 160 | productRefGroup = ED95B8AD1D644752007DEA62 /* Products */; 161 | projectDirPath = ""; 162 | projectRoot = ""; 163 | targets = ( 164 | ED95B8AB1D644752007DEA62 /* Example */, 165 | ); 166 | }; 167 | /* End PBXProject section */ 168 | 169 | /* Begin PBXResourcesBuildPhase section */ 170 | ED95B8AA1D644752007DEA62 /* Resources */ = { 171 | isa = PBXResourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | ED95B8C21D64477B007DEA62 /* Main.storyboard in Resources */, 175 | ED95B8BA1D644752007DEA62 /* LaunchScreen.storyboard in Resources */, 176 | ED95B8CC1D644783007DEA62 /* CollectionViewCell.xib in Resources */, 177 | ED95B8B71D644752007DEA62 /* Assets.xcassets in Resources */, 178 | ); 179 | runOnlyForDeploymentPostprocessing = 0; 180 | }; 181 | /* End PBXResourcesBuildPhase section */ 182 | 183 | /* Begin PBXShellScriptBuildPhase section */ 184 | 496DF4F1F2DB033F4B64A267 /* [CP] Embed Pods Frameworks */ = { 185 | isa = PBXShellScriptBuildPhase; 186 | buildActionMask = 2147483647; 187 | files = ( 188 | ); 189 | inputPaths = ( 190 | ); 191 | name = "[CP] Embed Pods Frameworks"; 192 | outputPaths = ( 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | shellPath = /bin/sh; 196 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; 197 | showEnvVarsInLog = 0; 198 | }; 199 | 7C8B8B5108974DD3029A6ADC /* [CP] Copy Pods Resources */ = { 200 | isa = PBXShellScriptBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | ); 204 | inputPaths = ( 205 | ); 206 | name = "[CP] Copy Pods Resources"; 207 | outputPaths = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | shellPath = /bin/sh; 211 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-resources.sh\"\n"; 212 | showEnvVarsInLog = 0; 213 | }; 214 | ABD6F1F3836737799102B65D /* [CP] Check Pods Manifest.lock */ = { 215 | isa = PBXShellScriptBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | inputPaths = ( 220 | ); 221 | name = "[CP] Check Pods Manifest.lock"; 222 | outputPaths = ( 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | shellPath = /bin/sh; 226 | shellScript = "diff \"${PODS_ROOT}/../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"; 227 | showEnvVarsInLog = 0; 228 | }; 229 | D1FCC2B33A736165206B3EE1 /* Embed Pods Frameworks */ = { 230 | isa = PBXShellScriptBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | ); 234 | inputPaths = ( 235 | ); 236 | name = "Embed Pods Frameworks"; 237 | outputPaths = ( 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | shellPath = /bin/sh; 241 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; 242 | showEnvVarsInLog = 0; 243 | }; 244 | /* End PBXShellScriptBuildPhase section */ 245 | 246 | /* Begin PBXSourcesBuildPhase section */ 247 | ED95B8A81D644752007DEA62 /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | ED95B8CD1D644783007DEA62 /* ViewController.swift in Sources */, 252 | ED95B8CA1D644783007DEA62 /* Utilities.swift in Sources */, 253 | ED95B8B01D644752007DEA62 /* AppDelegate.swift in Sources */, 254 | ED95B8CB1D644783007DEA62 /* CollectionViewCell.swift in Sources */, 255 | ED95B8C91D644783007DEA62 /* Transformer.swift in Sources */, 256 | ); 257 | runOnlyForDeploymentPostprocessing = 0; 258 | }; 259 | /* End PBXSourcesBuildPhase section */ 260 | 261 | /* Begin PBXVariantGroup section */ 262 | ED95B8B81D644752007DEA62 /* LaunchScreen.storyboard */ = { 263 | isa = PBXVariantGroup; 264 | children = ( 265 | ED95B8B91D644752007DEA62 /* Base */, 266 | ); 267 | name = LaunchScreen.storyboard; 268 | sourceTree = ""; 269 | }; 270 | /* End PBXVariantGroup section */ 271 | 272 | /* Begin XCBuildConfiguration section */ 273 | ED95B8BC1D644752007DEA62 /* Debug */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_ANALYZER_NONNULL = YES; 278 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 279 | CLANG_CXX_LIBRARY = "libc++"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_WARN_BOOL_CONVERSION = YES; 283 | CLANG_WARN_CONSTANT_CONVERSION = YES; 284 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 285 | CLANG_WARN_EMPTY_BODY = YES; 286 | CLANG_WARN_ENUM_CONVERSION = YES; 287 | CLANG_WARN_INFINITE_RECURSION = YES; 288 | CLANG_WARN_INT_CONVERSION = YES; 289 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 290 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 291 | CLANG_WARN_UNREACHABLE_CODE = YES; 292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 293 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 294 | COPY_PHASE_STRIP = NO; 295 | DEBUG_INFORMATION_FORMAT = dwarf; 296 | ENABLE_STRICT_OBJC_MSGSEND = YES; 297 | ENABLE_TESTABILITY = YES; 298 | GCC_C_LANGUAGE_STANDARD = gnu99; 299 | GCC_DYNAMIC_NO_PIC = NO; 300 | GCC_NO_COMMON_BLOCKS = YES; 301 | GCC_OPTIMIZATION_LEVEL = 0; 302 | GCC_PREPROCESSOR_DEFINITIONS = ( 303 | "DEBUG=1", 304 | "$(inherited)", 305 | ); 306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 307 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 308 | GCC_WARN_UNDECLARED_SELECTOR = YES; 309 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 310 | GCC_WARN_UNUSED_FUNCTION = YES; 311 | GCC_WARN_UNUSED_VARIABLE = YES; 312 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 313 | MTL_ENABLE_DEBUG_INFO = YES; 314 | ONLY_ACTIVE_ARCH = YES; 315 | SDKROOT = iphoneos; 316 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 317 | }; 318 | name = Debug; 319 | }; 320 | ED95B8BD1D644752007DEA62 /* Release */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | ALWAYS_SEARCH_USER_PATHS = NO; 324 | CLANG_ANALYZER_NONNULL = YES; 325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 326 | CLANG_CXX_LIBRARY = "libc++"; 327 | CLANG_ENABLE_MODULES = YES; 328 | CLANG_ENABLE_OBJC_ARC = YES; 329 | CLANG_WARN_BOOL_CONVERSION = YES; 330 | CLANG_WARN_CONSTANT_CONVERSION = YES; 331 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 332 | CLANG_WARN_EMPTY_BODY = YES; 333 | CLANG_WARN_ENUM_CONVERSION = YES; 334 | CLANG_WARN_INFINITE_RECURSION = YES; 335 | CLANG_WARN_INT_CONVERSION = YES; 336 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 337 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 338 | CLANG_WARN_UNREACHABLE_CODE = YES; 339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 340 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 341 | COPY_PHASE_STRIP = NO; 342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 343 | ENABLE_NS_ASSERTIONS = NO; 344 | ENABLE_STRICT_OBJC_MSGSEND = YES; 345 | GCC_C_LANGUAGE_STANDARD = gnu99; 346 | GCC_NO_COMMON_BLOCKS = YES; 347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 349 | GCC_WARN_UNDECLARED_SELECTOR = YES; 350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 351 | GCC_WARN_UNUSED_FUNCTION = YES; 352 | GCC_WARN_UNUSED_VARIABLE = YES; 353 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 354 | MTL_ENABLE_DEBUG_INFO = NO; 355 | SDKROOT = iphoneos; 356 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 357 | VALIDATE_PRODUCT = YES; 358 | }; 359 | name = Release; 360 | }; 361 | ED95B8BF1D644752007DEA62 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | baseConfigurationReference = 510CEFBACF2F8BD46E8472AF /* Pods-Example.debug.xcconfig */; 364 | buildSettings = { 365 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | INFOPLIST_FILE = Example/Info.plist; 368 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 369 | PRODUCT_BUNDLE_IDENTIFIER = top.limon.Example; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | SWIFT_VERSION = 3.0; 372 | }; 373 | name = Debug; 374 | }; 375 | ED95B8C01D644752007DEA62 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | baseConfigurationReference = 6915458786C7AB4ECE47F01B /* Pods-Example.release.xcconfig */; 378 | buildSettings = { 379 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 380 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 381 | INFOPLIST_FILE = Example/Info.plist; 382 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 383 | PRODUCT_BUNDLE_IDENTIFIER = top.limon.Example; 384 | PRODUCT_NAME = "$(TARGET_NAME)"; 385 | SWIFT_VERSION = 3.0; 386 | }; 387 | name = Release; 388 | }; 389 | /* End XCBuildConfiguration section */ 390 | 391 | /* Begin XCConfigurationList section */ 392 | ED95B8A71D644752007DEA62 /* Build configuration list for PBXProject "Example" */ = { 393 | isa = XCConfigurationList; 394 | buildConfigurations = ( 395 | ED95B8BC1D644752007DEA62 /* Debug */, 396 | ED95B8BD1D644752007DEA62 /* Release */, 397 | ); 398 | defaultConfigurationIsVisible = 0; 399 | defaultConfigurationName = Release; 400 | }; 401 | ED95B8BE1D644752007DEA62 /* Build configuration list for PBXNativeTarget "Example" */ = { 402 | isa = XCConfigurationList; 403 | buildConfigurations = ( 404 | ED95B8BF1D644752007DEA62 /* Debug */, 405 | ED95B8C01D644752007DEA62 /* Release */, 406 | ); 407 | defaultConfigurationIsVisible = 0; 408 | defaultConfigurationName = Release; 409 | }; 410 | /* End XCConfigurationList section */ 411 | }; 412 | rootObject = ED95B8A41D644752007DEA62 /* Project object */; 413 | } 414 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by Limon on 8/17/16. 6 | // Copyright © 2016 Limon. 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: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | return true 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /Example/Example/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 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Example/Example/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 | -------------------------------------------------------------------------------- /Example/Example/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 | 40 | 41 | -------------------------------------------------------------------------------- /Example/Example/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 | -------------------------------------------------------------------------------- /Example/Example/Transformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transformer.swift 3 | // Example 4 | // 5 | // Created by Limon on 6/24/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import KingfisherExtension 11 | 12 | enum Style { 13 | static let square: ImageStyle = .rectangle(size: CGSize(width: 60.0, height: 60.0)) 14 | static let round1: ImageStyle = .roundedRectangle(size: CGSize(width: 60.0, height: 60.0), cornerRadius: 8.0, borderWidth: 0) 15 | static let round2: ImageStyle = .roundedRectangle(size: CGSize(width: 60.0, height: 60.0), cornerRadius: 16.0, borderWidth: 0) 16 | static let round3: ImageStyle = .roundedRectangle(size: CGSize(width: 60.0, height: 60.0), cornerRadius: 60.0 * 0.5, borderWidth: 0) 17 | } 18 | 19 | struct Transformer { 20 | let URLString: String 21 | let style: ImageStyle 22 | } 23 | 24 | extension Transformer: ImageResizable { 25 | var placeholderImage: UIImage? { 26 | 27 | switch style { 28 | case .original, .rectangle: 29 | return DefaultImage.pixel 30 | case .roundedRectangle: 31 | return DefaultImage.oval 32 | } 33 | } 34 | } 35 | 36 | struct DefaultImage { 37 | static let oval = UIImage(named: "default_avatar_oval") 38 | static let pixel = UIImage(named: "pixel") 39 | } 40 | -------------------------------------------------------------------------------- /Example/Example/Utilities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.swift 3 | // KingfisherExtension 4 | // 5 | // Created by Limon on 6/24/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let ScreenBounds = UIScreen.main.bounds 12 | let ScreenWidth = ceil(UIScreen.main.bounds.size.width) 13 | let ScreenHeight = ceil(UIScreen.main.bounds.size.height) 14 | 15 | extension UICollectionReusableView { 16 | static var kfe_className: String { 17 | return "\(self)" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Example/Example/View/CollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewCell.swift 3 | // KingfisherExtension 4 | // 5 | // Created by catch on 15/11/18. 6 | // Copyright © 2015年 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CollectionViewCell: UICollectionViewCell { 12 | 13 | @IBOutlet weak var imageView: UIImageView! 14 | @IBOutlet weak var imageView1: UIImageView! 15 | @IBOutlet weak var imageView2: UIImageView! 16 | @IBOutlet weak var imageView3: UIImageView! 17 | @IBOutlet weak var button: UIButton! 18 | 19 | override func awakeFromNib() { 20 | super.awakeFromNib() 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Example/Example/View/CollectionViewCell.xib: -------------------------------------------------------------------------------- 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 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /Example/Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // KingfisherExtension 4 | // 5 | // Created by catch on 15/11/17. 6 | // Copyright © 2015年 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import KingfisherExtension 11 | 12 | class ViewController: UIViewController { 13 | 14 | @IBOutlet fileprivate weak var collectionView: UICollectionView! 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | collectionView.contentInset.top = 20.0 19 | collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: CollectionViewCell.kfe_className) 20 | } 21 | } 22 | 23 | 24 | extension ViewController: UICollectionViewDataSource { 25 | 26 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 27 | return 10 28 | } 29 | 30 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 31 | 32 | let URLString = "https://raw.githubusercontent.com/onevcat/Kingfisher/master/images/kingfisher-\((indexPath as NSIndexPath).row + 1).jpg" 33 | 34 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.kfe_className, for: indexPath) as! CollectionViewCell 35 | 36 | let squareTransformer = Transformer(URLString: URLString, style: Style.square) 37 | let transformer1 = Transformer(URLString: URLString, style: Style.round1) 38 | let transformer2 = Transformer(URLString: URLString, style: Style.round2) 39 | let transformer3 = Transformer(URLString: URLString, style: Style.round3) 40 | 41 | cell.imageView.kfe_setImage(byTransformer: squareTransformer) 42 | cell.imageView1.kfe_setImage(byTransformer: transformer1) 43 | cell.imageView2.kfe_setImage(byTransformer: transformer2) 44 | cell.imageView3.kfe_setImage(byTransformer: transformer3) 45 | 46 | cell.button.kfe_setImage(byTransformer: transformer3) 47 | 48 | return cell 49 | } 50 | } 51 | 52 | 53 | extension ViewController: UICollectionViewDelegateFlowLayout { 54 | 55 | func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout, 56 | sizeForItemAt indexPath: IndexPath) -> CGSize { 57 | return CGSize(width: ScreenWidth, height: 100) 58 | } 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :ios, '8.0' 3 | 4 | use_frameworks! 5 | 6 | def pods 7 | pod 'KingfisherExtension', :path => '../' 8 | pod 'Kingfisher' 9 | end 10 | 11 | target 'Example' do 12 | pods 13 | end 14 | 15 | -------------------------------------------------------------------------------- /KingfisherExtension.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "KingfisherExtension" 4 | s.version = "1.0.1" 5 | s.summary = "Kingfisher Extension" 6 | 7 | s.description = <<-DESC 8 | KingfisherExtension base on Kingfisher. Remake image before caching by style. 9 | DESC 10 | 11 | s.homepage = "https://github.com/Limon-O-O/KingfisherExtension" 12 | 13 | s.license = { :type => "MIT", :file => "LICENSE" } 14 | 15 | s.authors = { "Limon" => "fengninglong@gmail.com" } 16 | s.social_media_url = "https://twitter.com/Limon______" 17 | 18 | s.ios.deployment_target = "8.0" 19 | 20 | s.source = { :git => "https://github.com/Limon-O-O/KingfisherExtension.git", :tag => s.version } 21 | s.source_files = "KingfisherExtension/*.swift" 22 | s.requires_arc = true 23 | 24 | s.dependency 'Kingfisher' 25 | 26 | end 27 | -------------------------------------------------------------------------------- /KingfisherExtension.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | ED2C97F61D1D2C720099CE73 /* KingfisherExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = ED2C97F51D1D2C720099CE73 /* KingfisherExtension.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | ED2C98011D1D2CB70099CE73 /* UIImageView+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2C98001D1D2CB70099CE73 /* UIImageView+Kingfisher.swift */; }; 12 | ED2C98031D1D2F3F0099CE73 /* ImageStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2C98021D1D2F3F0099CE73 /* ImageStyle.swift */; }; 13 | ED2C98051D1D2FB00099CE73 /* UIImage+Navi.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2C98041D1D2FB00099CE73 /* UIImage+Navi.swift */; }; 14 | ED5E62101D2D126B00551706 /* UIButton+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5E620F1D2D126B00551706 /* UIButton+Kingfisher.swift */; }; 15 | ED5E62121D2E05BC00551706 /* UIView+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED5E62111D2E05BC00551706 /* UIView+Kingfisher.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | ED2C97F31D1D2C720099CE73 /* KingfisherExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KingfisherExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | ED2C97F51D1D2C720099CE73 /* KingfisherExtension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KingfisherExtension.h; sourceTree = ""; }; 21 | ED2C97F71D1D2C720099CE73 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22 | ED2C98001D1D2CB70099CE73 /* UIImageView+Kingfisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+Kingfisher.swift"; sourceTree = ""; }; 23 | ED2C98021D1D2F3F0099CE73 /* ImageStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageStyle.swift; sourceTree = ""; }; 24 | ED2C98041D1D2FB00099CE73 /* UIImage+Navi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Navi.swift"; sourceTree = ""; }; 25 | ED5E620F1D2D126B00551706 /* UIButton+Kingfisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIButton+Kingfisher.swift"; sourceTree = ""; }; 26 | ED5E62111D2E05BC00551706 /* UIView+Kingfisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Kingfisher.swift"; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | ED2C97EF1D1D2C720099CE73 /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | ); 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXFrameworksBuildPhase section */ 38 | 39 | /* Begin PBXGroup section */ 40 | ED2C97C81D1D2A420099CE73 = { 41 | isa = PBXGroup; 42 | children = ( 43 | ED2C97F41D1D2C720099CE73 /* KingfisherExtension */, 44 | ED2C97D21D1D2A420099CE73 /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | ED2C97D21D1D2A420099CE73 /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | ED2C97F31D1D2C720099CE73 /* KingfisherExtension.framework */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | ED2C97F41D1D2C720099CE73 /* KingfisherExtension */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | ED2C97F51D1D2C720099CE73 /* KingfisherExtension.h */, 60 | ED2C98021D1D2F3F0099CE73 /* ImageStyle.swift */, 61 | ED2C98041D1D2FB00099CE73 /* UIImage+Navi.swift */, 62 | ED5E62111D2E05BC00551706 /* UIView+Kingfisher.swift */, 63 | ED5E620F1D2D126B00551706 /* UIButton+Kingfisher.swift */, 64 | ED2C98001D1D2CB70099CE73 /* UIImageView+Kingfisher.swift */, 65 | ED2C97F71D1D2C720099CE73 /* Info.plist */, 66 | ); 67 | path = KingfisherExtension; 68 | sourceTree = ""; 69 | }; 70 | /* End PBXGroup section */ 71 | 72 | /* Begin PBXHeadersBuildPhase section */ 73 | ED2C97F01D1D2C720099CE73 /* Headers */ = { 74 | isa = PBXHeadersBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ED2C97F61D1D2C720099CE73 /* KingfisherExtension.h in Headers */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXHeadersBuildPhase section */ 82 | 83 | /* Begin PBXNativeTarget section */ 84 | ED2C97F21D1D2C720099CE73 /* KingfisherExtension */ = { 85 | isa = PBXNativeTarget; 86 | buildConfigurationList = ED2C97FC1D1D2C720099CE73 /* Build configuration list for PBXNativeTarget "KingfisherExtension" */; 87 | buildPhases = ( 88 | ED2C97EE1D1D2C720099CE73 /* Sources */, 89 | ED2C97EF1D1D2C720099CE73 /* Frameworks */, 90 | ED2C97F01D1D2C720099CE73 /* Headers */, 91 | ED2C97F11D1D2C720099CE73 /* Resources */, 92 | ED355FF91D8D3C9D001091B9 /* Stripping Unwanted Architectures */, 93 | ); 94 | buildRules = ( 95 | ); 96 | dependencies = ( 97 | ); 98 | name = KingfisherExtension; 99 | productName = KingfisherExtension; 100 | productReference = ED2C97F31D1D2C720099CE73 /* KingfisherExtension.framework */; 101 | productType = "com.apple.product-type.framework"; 102 | }; 103 | /* End PBXNativeTarget section */ 104 | 105 | /* Begin PBXProject section */ 106 | ED2C97C91D1D2A420099CE73 /* Project object */ = { 107 | isa = PBXProject; 108 | attributes = { 109 | LastSwiftUpdateCheck = 0730; 110 | LastUpgradeCheck = 0800; 111 | ORGANIZATIONNAME = KingfisherExtension; 112 | TargetAttributes = { 113 | ED2C97F21D1D2C720099CE73 = { 114 | CreatedOnToolsVersion = 7.3.1; 115 | LastSwiftMigration = 0800; 116 | }; 117 | }; 118 | }; 119 | buildConfigurationList = ED2C97CC1D1D2A420099CE73 /* Build configuration list for PBXProject "KingfisherExtension" */; 120 | compatibilityVersion = "Xcode 3.2"; 121 | developmentRegion = English; 122 | hasScannedForEncodings = 0; 123 | knownRegions = ( 124 | en, 125 | Base, 126 | ); 127 | mainGroup = ED2C97C81D1D2A420099CE73; 128 | productRefGroup = ED2C97D21D1D2A420099CE73 /* Products */; 129 | projectDirPath = ""; 130 | projectRoot = ""; 131 | targets = ( 132 | ED2C97F21D1D2C720099CE73 /* KingfisherExtension */, 133 | ); 134 | }; 135 | /* End PBXProject section */ 136 | 137 | /* Begin PBXResourcesBuildPhase section */ 138 | ED2C97F11D1D2C720099CE73 /* Resources */ = { 139 | isa = PBXResourcesBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXResourcesBuildPhase section */ 146 | 147 | /* Begin PBXShellScriptBuildPhase section */ 148 | ED355FF91D8D3C9D001091B9 /* Stripping Unwanted Architectures */ = { 149 | isa = PBXShellScriptBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | ); 153 | inputPaths = ( 154 | ); 155 | name = "Stripping Unwanted Architectures"; 156 | outputPaths = ( 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | shellPath = /bin/sh; 160 | shellScript = "APP_PATH=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\n\n# This script loops through the frameworks embedded in the application and\n# removes unused architectures.\nfind \"$APP_PATH\" -name '*.framework' -type d | while read -r FRAMEWORK\ndo\nFRAMEWORK_EXECUTABLE_NAME=$(defaults read \"$FRAMEWORK/Info.plist\" CFBundleExecutable)\nFRAMEWORK_EXECUTABLE_PATH=\"$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME\"\necho \"Executable is $FRAMEWORK_EXECUTABLE_PATH\"\n\nEXTRACTED_ARCHS=()\n\nfor ARCH in $ARCHS\ndo\necho \"Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME\"\nlipo -extract \"$ARCH\" \"$FRAMEWORK_EXECUTABLE_PATH\" -o \"$FRAMEWORK_EXECUTABLE_PATH-$ARCH\"\nEXTRACTED_ARCHS+=(\"$FRAMEWORK_EXECUTABLE_PATH-$ARCH\")\ndone\n\necho \"Merging extracted architectures: ${ARCHS}\"\nlipo -o \"$FRAMEWORK_EXECUTABLE_PATH-merged\" -create \"${EXTRACTED_ARCHS[@]}\"\nrm \"${EXTRACTED_ARCHS[@]}\"\n\necho \"Replacing original executable with thinned version\"\nrm \"$FRAMEWORK_EXECUTABLE_PATH\"\nmv \"$FRAMEWORK_EXECUTABLE_PATH-merged\" \"$FRAMEWORK_EXECUTABLE_PATH\"\n\ndone"; 161 | }; 162 | /* End PBXShellScriptBuildPhase section */ 163 | 164 | /* Begin PBXSourcesBuildPhase section */ 165 | ED2C97EE1D1D2C720099CE73 /* Sources */ = { 166 | isa = PBXSourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | ED2C98011D1D2CB70099CE73 /* UIImageView+Kingfisher.swift in Sources */, 170 | ED2C98031D1D2F3F0099CE73 /* ImageStyle.swift in Sources */, 171 | ED5E62121D2E05BC00551706 /* UIView+Kingfisher.swift in Sources */, 172 | ED2C98051D1D2FB00099CE73 /* UIImage+Navi.swift in Sources */, 173 | ED5E62101D2D126B00551706 /* UIButton+Kingfisher.swift in Sources */, 174 | ); 175 | runOnlyForDeploymentPostprocessing = 0; 176 | }; 177 | /* End PBXSourcesBuildPhase section */ 178 | 179 | /* Begin XCBuildConfiguration section */ 180 | ED2C97E11D1D2A420099CE73 /* Debug */ = { 181 | isa = XCBuildConfiguration; 182 | buildSettings = { 183 | ALWAYS_SEARCH_USER_PATHS = NO; 184 | CLANG_ANALYZER_NONNULL = YES; 185 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 186 | CLANG_CXX_LIBRARY = "libc++"; 187 | CLANG_ENABLE_MODULES = YES; 188 | CLANG_ENABLE_OBJC_ARC = YES; 189 | CLANG_WARN_BOOL_CONVERSION = YES; 190 | CLANG_WARN_CONSTANT_CONVERSION = YES; 191 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 192 | CLANG_WARN_EMPTY_BODY = YES; 193 | CLANG_WARN_ENUM_CONVERSION = YES; 194 | CLANG_WARN_INFINITE_RECURSION = YES; 195 | CLANG_WARN_INT_CONVERSION = YES; 196 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 197 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 198 | CLANG_WARN_UNREACHABLE_CODE = YES; 199 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 200 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 201 | COPY_PHASE_STRIP = NO; 202 | DEBUG_INFORMATION_FORMAT = dwarf; 203 | ENABLE_STRICT_OBJC_MSGSEND = YES; 204 | ENABLE_TESTABILITY = YES; 205 | GCC_C_LANGUAGE_STANDARD = gnu99; 206 | GCC_DYNAMIC_NO_PIC = NO; 207 | GCC_NO_COMMON_BLOCKS = YES; 208 | GCC_OPTIMIZATION_LEVEL = 0; 209 | GCC_PREPROCESSOR_DEFINITIONS = ( 210 | "DEBUG=1", 211 | "$(inherited)", 212 | ); 213 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 214 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 215 | GCC_WARN_UNDECLARED_SELECTOR = YES; 216 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 217 | GCC_WARN_UNUSED_FUNCTION = YES; 218 | GCC_WARN_UNUSED_VARIABLE = YES; 219 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 220 | MTL_ENABLE_DEBUG_INFO = YES; 221 | ONLY_ACTIVE_ARCH = YES; 222 | SDKROOT = iphoneos; 223 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 224 | }; 225 | name = Debug; 226 | }; 227 | ED2C97E21D1D2A420099CE73 /* Release */ = { 228 | isa = XCBuildConfiguration; 229 | buildSettings = { 230 | ALWAYS_SEARCH_USER_PATHS = NO; 231 | CLANG_ANALYZER_NONNULL = YES; 232 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 233 | CLANG_CXX_LIBRARY = "libc++"; 234 | CLANG_ENABLE_MODULES = YES; 235 | CLANG_ENABLE_OBJC_ARC = YES; 236 | CLANG_WARN_BOOL_CONVERSION = YES; 237 | CLANG_WARN_CONSTANT_CONVERSION = YES; 238 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 239 | CLANG_WARN_EMPTY_BODY = YES; 240 | CLANG_WARN_ENUM_CONVERSION = YES; 241 | CLANG_WARN_INFINITE_RECURSION = YES; 242 | CLANG_WARN_INT_CONVERSION = YES; 243 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 244 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 245 | CLANG_WARN_UNREACHABLE_CODE = YES; 246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 247 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 248 | COPY_PHASE_STRIP = NO; 249 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 250 | ENABLE_NS_ASSERTIONS = NO; 251 | ENABLE_STRICT_OBJC_MSGSEND = YES; 252 | GCC_C_LANGUAGE_STANDARD = gnu99; 253 | GCC_NO_COMMON_BLOCKS = YES; 254 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 255 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 256 | GCC_WARN_UNDECLARED_SELECTOR = YES; 257 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 258 | GCC_WARN_UNUSED_FUNCTION = YES; 259 | GCC_WARN_UNUSED_VARIABLE = YES; 260 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 261 | MTL_ENABLE_DEBUG_INFO = NO; 262 | SDKROOT = iphoneos; 263 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 264 | VALIDATE_PRODUCT = YES; 265 | }; 266 | name = Release; 267 | }; 268 | ED2C97FD1D1D2C720099CE73 /* Debug */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | APPLICATION_EXTENSION_API_ONLY = YES; 272 | CLANG_ENABLE_MODULES = YES; 273 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 274 | CURRENT_PROJECT_VERSION = 1; 275 | DEFINES_MODULE = YES; 276 | DYLIB_COMPATIBILITY_VERSION = 1; 277 | DYLIB_CURRENT_VERSION = 1; 278 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 279 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; 280 | INFOPLIST_FILE = KingfisherExtension/Info.plist; 281 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 282 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 283 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 284 | PRODUCT_BUNDLE_IDENTIFIER = top.limon.KingfisherExtension; 285 | PRODUCT_NAME = "$(TARGET_NAME)"; 286 | SKIP_INSTALL = YES; 287 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 288 | SWIFT_VERSION = 3.0; 289 | TARGETED_DEVICE_FAMILY = "1,2"; 290 | VERSIONING_SYSTEM = "apple-generic"; 291 | VERSION_INFO_PREFIX = ""; 292 | }; 293 | name = Debug; 294 | }; 295 | ED2C97FE1D1D2C720099CE73 /* Release */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | APPLICATION_EXTENSION_API_ONLY = YES; 299 | CLANG_ENABLE_MODULES = YES; 300 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 301 | CURRENT_PROJECT_VERSION = 1; 302 | DEFINES_MODULE = YES; 303 | DYLIB_COMPATIBILITY_VERSION = 1; 304 | DYLIB_CURRENT_VERSION = 1; 305 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 306 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Carthage/Build/iOS"; 307 | INFOPLIST_FILE = KingfisherExtension/Info.plist; 308 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 309 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 310 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 311 | PRODUCT_BUNDLE_IDENTIFIER = top.limon.KingfisherExtension; 312 | PRODUCT_NAME = "$(TARGET_NAME)"; 313 | SKIP_INSTALL = YES; 314 | SWIFT_VERSION = 3.0; 315 | TARGETED_DEVICE_FAMILY = "1,2"; 316 | VERSIONING_SYSTEM = "apple-generic"; 317 | VERSION_INFO_PREFIX = ""; 318 | }; 319 | name = Release; 320 | }; 321 | /* End XCBuildConfiguration section */ 322 | 323 | /* Begin XCConfigurationList section */ 324 | ED2C97CC1D1D2A420099CE73 /* Build configuration list for PBXProject "KingfisherExtension" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | ED2C97E11D1D2A420099CE73 /* Debug */, 328 | ED2C97E21D1D2A420099CE73 /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | ED2C97FC1D1D2C720099CE73 /* Build configuration list for PBXNativeTarget "KingfisherExtension" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | ED2C97FD1D1D2C720099CE73 /* Debug */, 337 | ED2C97FE1D1D2C720099CE73 /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | /* End XCConfigurationList section */ 343 | }; 344 | rootObject = ED2C97C91D1D2A420099CE73 /* Project object */; 345 | } 346 | -------------------------------------------------------------------------------- /KingfisherExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /KingfisherExtension.xcodeproj/xcshareddata/xcschemes/KingfisherExtension.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /KingfisherExtension/ImageStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageStyle.swift 3 | // KingfisherExtension 4 | // 5 | // Created by Limon on 6/24/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Kingfisher 11 | 12 | public func ==(lhs: ImageStyle, rhs: ImageStyle) -> Bool { 13 | 14 | switch (lhs, rhs) { 15 | 16 | case (.original, .original): 17 | return true 18 | 19 | case (.rectangle(let sizeA), .rectangle(let sizeB)) where sizeA == sizeB: 20 | return true 21 | 22 | case (.roundedRectangle(let sizeA, let cornerRadiusA, let borderWidthA), .roundedRectangle(let sizeB, let cornerRadiusB, let borderWidthB)) where (sizeA == sizeB && cornerRadiusA == cornerRadiusB && borderWidthA == borderWidthB): 23 | return true 24 | 25 | default: 26 | return false 27 | } 28 | } 29 | 30 | public enum ImageStyle: Equatable { 31 | 32 | case original 33 | case rectangle(size: CGSize) 34 | case roundedRectangle(size: CGSize, cornerRadius: CGFloat, borderWidth: CGFloat) 35 | 36 | var hashString: String { 37 | 38 | switch self { 39 | 40 | case .original: 41 | return "Original-" 42 | 43 | case .rectangle(let size): 44 | return "Rectangle-\(size)-" 45 | 46 | case .roundedRectangle(let size, let cornerRadius, let borderWidth): 47 | return "RoundedRectangle-\(size)-\(cornerRadius)-\(borderWidth)-" 48 | } 49 | } 50 | } 51 | 52 | public protocol ImageResizable { 53 | 54 | var URLString: String { get } 55 | var style: ImageStyle { get } 56 | var placeholderImage: UIImage? { get } 57 | } 58 | 59 | extension ImageResizable { 60 | 61 | public var key: String { 62 | return style.hashString + URLString 63 | } 64 | 65 | public var originalImageKey: String { 66 | return URLString 67 | } 68 | 69 | public var localStyledImage: UIImage? { 70 | return KingfisherManager.shared.cache.retrieveImageInMemoryCache(forKey: key) ?? KingfisherManager.shared.cache.retrieveImageInDiskCache(forKey: key, options: [.backgroundDecode]) 71 | } 72 | 73 | public var localOriginalImage: UIImage? { 74 | return KingfisherManager.shared.cache.retrieveImageInMemoryCache(forKey: originalImageKey) ?? KingfisherManager.shared.cache.retrieveImageInDiskCache(forKey: originalImageKey) 75 | } 76 | 77 | public var placeholderImage: UIImage? { 78 | return nil 79 | } 80 | 81 | public func removeImage() { 82 | 83 | guard !originalImageKey.isEmpty else { return } 84 | 85 | KingfisherManager.shared.cache.removeImage(forKey: originalImageKey) 86 | KingfisherManager.shared.cache.removeImage(forKey: key) 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /KingfisherExtension/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /KingfisherExtension/KingfisherExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // KingfisherExtension.h 3 | // KingfisherExtension 4 | // 5 | // Created by Limon on 6/24/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for KingfisherExtension. 12 | FOUNDATION_EXPORT double KingfisherExtensionVersionNumber; 13 | 14 | //! Project version string for KingfisherExtension. 15 | FOUNDATION_EXPORT const unsigned char KingfisherExtensionVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /KingfisherExtension/UIButton+Kingfisher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+Kingfisher.swift 3 | // KingfisherExtension 4 | // 5 | // Created by Limon on 7/6/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import Kingfisher 10 | 11 | extension UIButton { 12 | 13 | public func kfe_setBackgroundImageWithURLString(_ URLString: String?, 14 | forState state: UIControlState, 15 | placeholderImage: UIImage? = nil, 16 | optionsInfo: KingfisherOptionsInfo? = nil, 17 | progressBlock: DownloadProgressBlock? = nil, 18 | completionHandler: CompletionHandler? = nil) -> RetrieveImageTask? 19 | { 20 | return kfe_setImageWithURLString(URLString, forState: state, isSetingBackgroundImage: true, placeholderImage: placeholderImage, optionsInfo: optionsInfo, progressBlock: progressBlock, completionHandler: completionHandler) 21 | 22 | } 23 | 24 | public func kfe_setImageWithURLString(_ URLString: String?, 25 | forState state: UIControlState, 26 | placeholderImage: UIImage? = nil, 27 | optionsInfo: KingfisherOptionsInfo? = nil, 28 | progressBlock: DownloadProgressBlock? = nil, 29 | completionHandler: CompletionHandler? = nil) -> RetrieveImageTask? 30 | { 31 | 32 | return kfe_setImageWithURLString(URLString, forState: state, isSetingBackgroundImage: false, placeholderImage: placeholderImage, optionsInfo: optionsInfo, progressBlock: progressBlock, completionHandler: completionHandler) 33 | 34 | } 35 | 36 | private func kfe_setImageWithURLString(_ URLString: String?, 37 | forState state: UIControlState, 38 | isSetingBackgroundImage: Bool, 39 | placeholderImage: UIImage? = nil, 40 | optionsInfo: KingfisherOptionsInfo? = nil, 41 | progressBlock: DownloadProgressBlock? = nil, 42 | completionHandler: CompletionHandler? = nil) -> RetrieveImageTask? 43 | { 44 | 45 | guard let URLString = URLString, let URL = URL(string: URLString), !URLString.isEmpty else { 46 | print("[KingfisherExtension] \((#file as NSString).lastPathComponent)[\(#line)], \(#function): Image Downlaod error: URL Error") 47 | isSetingBackgroundImage ? setBackgroundImage(nil, for: state) : setImage(nil, for: state) 48 | return nil 49 | } 50 | 51 | guard let image = KingfisherManager.shared.cache.retrieveImageInMemoryCache(forKey: URLString) ?? KingfisherManager.shared.cache.retrieveImageInDiskCache(forKey: URLString) else { 52 | 53 | let optionInfoBuffer: KingfisherOptionsInfo = [ 54 | .backgroundDecode, 55 | .transition(ImageTransition.fade(0.35)) 56 | ] 57 | 58 | return kf.setImage(with: URL, 59 | for: state, 60 | placeholder: placeholderImage, 61 | options: optionsInfo ?? optionInfoBuffer, 62 | progressBlock: progressBlock, 63 | completionHandler: completionHandler) 64 | } 65 | 66 | DispatchQueue.main.async { 67 | UIView.performWithoutAnimation { 68 | isSetingBackgroundImage ? self.setBackgroundImage(image, for: state) : self.setImage(image, for: state) 69 | } 70 | } 71 | 72 | return nil 73 | } 74 | 75 | } 76 | 77 | extension UIButton { 78 | 79 | public func kfe_setImage(byTransformer transformer: ImageResizable, forState state: UIControlState = UIControlState(), toDisk: Bool = true, completionHandler: ((_ image: UIImage?) -> Void)? = nil) { 80 | 81 | kfe_setImage(byTransformer: transformer, action: { [weak self] image in 82 | 83 | self?.setImage(image, for: state) 84 | 85 | }, toDisk: toDisk, completionHandler: completionHandler) 86 | } 87 | 88 | public func kfe_setBackgroundImage(byTransformer transformer: ImageResizable, forState state: UIControlState = UIControlState(), toDisk: Bool = true, completionHandler: ((_ image: UIImage?) -> Void)? = nil) { 89 | 90 | kfe_setImage(byTransformer: transformer, action: { [weak self] image in 91 | 92 | self?.setBackgroundImage(image, for: state) 93 | 94 | }, toDisk: toDisk, completionHandler: completionHandler) 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /KingfisherExtension/UIImage+Navi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Navi.swift 3 | // KingfisherExtension 4 | // 5 | // Created by Limon on 6/24/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // ref http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/ 12 | // but with better scale logic 13 | 14 | private let screenScale = UIScreen.main.scale 15 | 16 | // MARK: - API 17 | 18 | public extension UIImage { 19 | 20 | public func navi_avatarImageWithStyle(_ avatarStyle: ImageStyle) -> UIImage { 21 | 22 | var avatarImage: UIImage? 23 | 24 | switch avatarStyle { 25 | 26 | case .original: 27 | return self 28 | 29 | case .rectangle(let size): 30 | avatarImage = navi_centerCropWithSize(size) 31 | 32 | case .roundedRectangle(let size, let cornerRadius, let borderWidth): 33 | avatarImage = navi_centerCropWithSize(size)?.navi_roundWithCornerRadius(cornerRadius, borderWidth: borderWidth) 34 | } 35 | 36 | return avatarImage ?? self 37 | } 38 | } 39 | 40 | // MARK: - Resize 41 | 42 | public extension UIImage { 43 | 44 | public func navi_resizeToSize(_ size: CGSize, withTransform transform: CGAffineTransform, drawTransposed: Bool, interpolationQuality: CGInterpolationQuality) -> UIImage? { 45 | 46 | let pixelSize = CGSize(width: size.width * screenScale, height: size.height * screenScale) 47 | 48 | let newRect = CGRect(origin: CGPoint.zero, size: pixelSize).integral 49 | let transposedRect = CGRect(origin: CGPoint.zero, size: CGSize(width: pixelSize.height, height: pixelSize.width)) 50 | 51 | let bitmapContext = CGContext(data: nil, width: Int(newRect.width), height: Int(newRect.height), bitsPerComponent: (cgImage?.bitsPerComponent)!, bytesPerRow: 0, space: (cgImage?.colorSpace!)!, bitmapInfo: (cgImage?.bitmapInfo.rawValue)!) 52 | 53 | bitmapContext?.concatenate(transform) 54 | 55 | bitmapContext!.interpolationQuality = interpolationQuality 56 | 57 | bitmapContext?.draw(cgImage!, in: drawTransposed ? transposedRect : newRect) 58 | 59 | if let newCGImage = bitmapContext?.makeImage() { 60 | let image = UIImage(cgImage: newCGImage, scale: screenScale, orientation: imageOrientation) 61 | return image 62 | } 63 | 64 | return nil 65 | } 66 | 67 | public func navi_transformForOrientationWithSize(_ size: CGSize) -> CGAffineTransform { 68 | 69 | var transform = CGAffineTransform.identity 70 | 71 | switch imageOrientation { 72 | 73 | case .down, .downMirrored: 74 | transform = transform.translatedBy(x: size.width, y: size.height) 75 | transform = transform.rotated(by: CGFloat(M_PI)) 76 | 77 | case .left, .leftMirrored: 78 | transform = transform.translatedBy(x: size.width, y: 0) 79 | transform = transform.rotated(by: CGFloat(M_PI_2)) 80 | 81 | case .right, .rightMirrored: 82 | transform = transform.translatedBy(x: 0, y: size.height) 83 | transform = transform.rotated(by: CGFloat(-M_PI_2)) 84 | 85 | default: 86 | break 87 | } 88 | 89 | switch imageOrientation { 90 | 91 | case .upMirrored, .downMirrored: 92 | transform = transform.translatedBy(x: size.width, y: 0) 93 | transform = transform.scaledBy(x: -1, y: 1) 94 | 95 | case .leftMirrored, .rightMirrored: 96 | transform = transform.translatedBy(x: size.height, y: 0) 97 | transform = transform.scaledBy(x: -1, y: 1) 98 | 99 | default: 100 | break 101 | } 102 | 103 | return transform 104 | } 105 | 106 | public func navi_resizeToSize(_ size: CGSize, withInterpolationQuality interpolationQuality: CGInterpolationQuality) -> UIImage? { 107 | 108 | let drawTransposed: Bool 109 | 110 | switch imageOrientation { 111 | case .left, .leftMirrored, .right, .rightMirrored: 112 | drawTransposed = true 113 | default: 114 | drawTransposed = false 115 | } 116 | 117 | let image = navi_resizeToSize(size, withTransform: navi_transformForOrientationWithSize(size), drawTransposed: drawTransposed, interpolationQuality: interpolationQuality) 118 | return image 119 | } 120 | 121 | public func navi_cropWithBounds(_ bounds: CGRect) -> UIImage? { 122 | 123 | if let newCGImage = cgImage?.cropping(to: bounds) { 124 | let image = UIImage(cgImage: newCGImage, scale: screenScale, orientation: imageOrientation) 125 | return image 126 | } 127 | 128 | return nil 129 | } 130 | 131 | public func navi_centerCropWithSize(_ size: CGSize) -> UIImage? { 132 | 133 | let pixelSize = CGSize(width: size.width * screenScale, height: size.height * screenScale) 134 | 135 | let horizontalRatio = pixelSize.width / self.size.width 136 | let verticalRatio = pixelSize.height / self.size.height 137 | 138 | let ratio: CGFloat 139 | 140 | let originalX: CGFloat 141 | let originalY: CGFloat 142 | 143 | if horizontalRatio > verticalRatio { 144 | ratio = horizontalRatio 145 | 146 | originalX = 0 147 | originalY = (self.size.height - pixelSize.height / ratio) / 2 148 | 149 | } else { 150 | ratio = verticalRatio 151 | 152 | originalX = (self.size.width - pixelSize.width / ratio) / 2 153 | originalY = 0 154 | } 155 | 156 | let bounds = CGRect(x: originalX, y: originalY, width: pixelSize.width / ratio, height: pixelSize.height / ratio) 157 | 158 | let image = navi_cropWithBounds(bounds)?.navi_resizeToSize(size, withInterpolationQuality: .default) 159 | return image 160 | } 161 | } 162 | 163 | // MARK: - Round 164 | 165 | public extension UIImage { 166 | 167 | fileprivate func navi_CGContextAddRoundedRect(_ context: CGContext, rect: CGRect, ovalWidth: CGFloat, ovalHeight: CGFloat) { 168 | 169 | if ovalWidth <= 0 || ovalHeight <= 0 { 170 | context.addRect(rect) 171 | 172 | } else { 173 | context.saveGState() 174 | 175 | context.translateBy(x: rect.minX, y: rect.minY) 176 | 177 | context.scaleBy(x: ovalWidth, y: ovalHeight) 178 | 179 | let fw = rect.width / ovalWidth 180 | let fh = rect.height / ovalHeight 181 | 182 | context.move(to: CGPoint(x: fw, y: fh/2)) 183 | context.addArc(tangent1End: CGPoint(x: fw, y: fh), tangent2End: CGPoint(x: fw/2, y: fh), radius: 1.0) 184 | context.addArc(tangent1End: CGPoint(x: 0.0, y: fh), tangent2End: CGPoint(x: 0.0, y: fh/2), radius: 1.0) 185 | context.addArc(tangent1End: CGPoint(x: 0.0, y: 0.0), tangent2End: CGPoint(x: fw/2, y: 0.0), radius: 1.0) 186 | context.addArc(tangent1End: CGPoint(x: fw, y: 0.0), tangent2End: CGPoint(x: fw, y: fh/2), radius: 1.0) 187 | context.closePath() 188 | context.restoreGState() 189 | } 190 | } 191 | 192 | public func navi_roundWithCornerRadius(_ cornerRadius: CGFloat, borderWidth: CGFloat) -> UIImage? { 193 | 194 | let image = navi_imageWithAlpha() 195 | 196 | let cornerRadius = cornerRadius * screenScale 197 | let borderWidth = borderWidth * screenScale 198 | 199 | let pixelSize = CGSize(width: image.size.width * screenScale, height: image.size.height * screenScale) 200 | 201 | guard let bitmapContext = CGContext(data: nil, width: Int(pixelSize.width), height: Int(pixelSize.height), bitsPerComponent: (image.cgImage?.bitsPerComponent)!, bytesPerRow: 0, space: (image.cgImage?.colorSpace!)!, bitmapInfo: (image.cgImage?.bitmapInfo.rawValue)!) else { 202 | return nil 203 | } 204 | 205 | bitmapContext.beginPath() 206 | 207 | let rect = CGRect(x: borderWidth, y: borderWidth, width: pixelSize.width - borderWidth * 2, height: pixelSize.height - borderWidth * 2) 208 | navi_CGContextAddRoundedRect(bitmapContext, rect: rect, ovalWidth: cornerRadius, ovalHeight: cornerRadius) 209 | 210 | bitmapContext.closePath() 211 | 212 | bitmapContext.clip() 213 | 214 | let imageRect = CGRect(origin: CGPoint.zero, size: pixelSize) 215 | bitmapContext.draw(image.cgImage!, in: imageRect) 216 | 217 | if let newCGImage = bitmapContext.makeImage() { 218 | let image = UIImage(cgImage: newCGImage, scale: screenScale, orientation: imageOrientation) 219 | return image 220 | } 221 | 222 | return nil 223 | } 224 | } 225 | 226 | // MARK: - Alpha 227 | 228 | public extension UIImage { 229 | 230 | public func navi_hasAlpha() -> Bool { 231 | 232 | guard let alpha = cgImage?.alphaInfo else { return false } 233 | 234 | switch alpha { 235 | 236 | case .first, .last, .premultipliedFirst, .premultipliedLast: 237 | return true 238 | 239 | default: 240 | return false 241 | } 242 | } 243 | 244 | public func navi_imageWithAlpha() -> UIImage { 245 | 246 | if navi_hasAlpha() { 247 | return self 248 | } 249 | 250 | let pixelSize = CGSize(width: self.size.width * screenScale, height: self.size.height * screenScale) 251 | 252 | let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo().rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue) 253 | 254 | let offscreenContext = CGContext(data: nil, width: Int(pixelSize.width), height: Int(pixelSize.height), bitsPerComponent: (cgImage?.bitsPerComponent)!, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: bitmapInfo.rawValue) 255 | 256 | offscreenContext?.draw(cgImage!, in: CGRect(origin: CGPoint.zero, size: pixelSize)) 257 | 258 | if let alphaCGImage = offscreenContext?.makeImage() { 259 | let image = UIImage(cgImage: alphaCGImage, scale: screenScale, orientation: imageOrientation) 260 | return image 261 | 262 | } else { 263 | return self 264 | } 265 | } 266 | } 267 | 268 | 269 | -------------------------------------------------------------------------------- /KingfisherExtension/UIImageView+Kingfisher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+Kingfisher.swift 3 | // KingfisherExtension 4 | // 5 | // Created by Limon on 6/24/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import Kingfisher 10 | 11 | extension UIImageView { 12 | 13 | public func kfe_setImageWithURLString(_ URLString: String?, 14 | placeholderImage: UIImage? = nil, 15 | optionsInfo: KingfisherOptionsInfo? = nil, 16 | progressBlock: DownloadProgressBlock? = nil, 17 | completionHandler: CompletionHandler? = nil) -> RetrieveImageTask? 18 | { 19 | 20 | guard let URLString = URLString, let URL = URL(string: URLString), !URLString.isEmpty else { 21 | print("[KingfisherExtension] \((#file as NSString).lastPathComponent)[\(#line)], \(#function): Image Downlaod error: URL Error") 22 | image = nil 23 | return nil 24 | } 25 | 26 | guard let image = KingfisherManager.shared.cache.retrieveImageInMemoryCache(forKey: URLString) ?? KingfisherManager.shared.cache.retrieveImageInDiskCache(forKey: URLString) else { 27 | 28 | let optionInfoBuffer: KingfisherOptionsInfo = [ 29 | .backgroundDecode, 30 | .transition(ImageTransition.fade(0.35)) 31 | ] 32 | 33 | return kf.setImage(with: URL, 34 | placeholder: placeholderImage, 35 | options: optionsInfo ?? optionInfoBuffer, 36 | progressBlock: progressBlock, 37 | completionHandler: completionHandler) 38 | } 39 | 40 | DispatchQueue.main.async { 41 | UIView.performWithoutAnimation { 42 | self.image = image 43 | } 44 | } 45 | 46 | return nil 47 | } 48 | 49 | public func kfe_setImage(byTransformer transformer: ImageResizable, toDisk: Bool = true, completionHandler: ((_ image: UIImage?) -> Void)? = nil) { 50 | 51 | kfe_setImage(byTransformer: transformer, action: { [weak self] image in 52 | 53 | self?.image = image 54 | 55 | }, toDisk: toDisk, completionHandler: completionHandler) 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /KingfisherExtension/UIView+Kingfisher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Kingfisher.swift 3 | // KingfisherExtension 4 | // 5 | // Created by Limon on 7/7/16. 6 | // Copyright © 2016 KingfisherExtension. All rights reserved. 7 | // 8 | 9 | import Kingfisher 10 | 11 | extension UIView { 12 | 13 | private func kfe_resizeImage(byOriginalImage originalImage: UIImage, transformer: ImageResizable, action: @escaping (_ reducedImage: UIImage) -> Void, toDisk: Bool, completionHandler: ((_ image: UIImage?) -> Void)?) { 14 | 15 | DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { 16 | 17 | let reducedImage = originalImage.navi_avatarImageWithStyle(transformer.style) 18 | 19 | let showImage = { 20 | 21 | UIView.transition(with: self, duration: 0.3, options: .transitionCrossDissolve, animations: { 22 | 23 | action(reducedImage) 24 | 25 | }, completion: { _ in 26 | 27 | completionHandler?(reducedImage) 28 | }) 29 | } 30 | 31 | KingfisherManager.shared.cache.store(reducedImage, original: nil, forKey: transformer.key, toDisk: toDisk, completionHandler: { 32 | showImage() 33 | }) 34 | } 35 | } 36 | 37 | func kfe_setImage(byTransformer transformer: ImageResizable, action: @escaping (_ image: UIImage?) -> Void, toDisk: Bool, completionHandler: ((_ image: UIImage?) -> Void)?) { 38 | 39 | guard !transformer.URLString.isEmpty, let URL = URL(string: transformer.URLString) else { 40 | 41 | print("[KingfisherExtension] \((#file as NSString).lastPathComponent)[\(#line)], \(#function): Image Downlaod error: URL Error") 42 | 43 | action(nil) 44 | completionHandler?(nil) 45 | return 46 | } 47 | 48 | if let localStyledImage = transformer.localStyledImage { 49 | 50 | action(localStyledImage) 51 | completionHandler?(localStyledImage) 52 | 53 | } else if let localOriginalImage = transformer.localOriginalImage { 54 | 55 | kfe_resizeImage(byOriginalImage: localOriginalImage, transformer: transformer, action: { reducedImage in 56 | 57 | action(reducedImage) 58 | 59 | }, toDisk: toDisk, completionHandler: completionHandler) 60 | 61 | } else { 62 | 63 | action(transformer.placeholderImage) 64 | 65 | KingfisherManager.shared.downloader.downloadImage(with: URL, options: [.backgroundDecode], progressBlock: nil) { [weak self] image, error, imageURL, originalData in 66 | 67 | guard let originalImage = image, let strongSelf = self else { return } 68 | 69 | strongSelf.kfe_resizeImage(byOriginalImage: originalImage, transformer: transformer, action: { reducedImage in 70 | 71 | action(reducedImage) 72 | 73 | }, toDisk: toDisk, completionHandler: completionHandler) 74 | 75 | if toDisk { 76 | KingfisherManager.shared.cache.store(originalImage, original: originalData, forKey: URL.absoluteString, toDisk: true, completionHandler: nil) 77 | } 78 | } 79 | } 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Limon 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 | 3 | 4 | 5 |

6 | 7 | # KingfisherExtension 8 | 9 | KingfisherExtension base on [Kingfisher](https://github.com/onevcat/Kingfisher). Remake image before caching by style. 10 | 11 | ![](http://ww4.sinaimg.cn/large/006tNc79jw1f5l757g4qoj30af0ijdie.jpg) 12 | 13 | ## Requirements 14 | 15 | iOS 8.0 16 | 17 | Swift 3.0 18 | 19 | ## Usage 20 | 21 | 1. Make your Transformer conform ImageReducible protocol. 22 | 23 | ``` swift 24 | struct Transformer: ImageReducible { 25 | let URLString: String 26 | let style: ImageStyle 27 | } 28 | ``` 29 | 30 | 2. And, set transformer for your imageView 31 | 32 | ``` swift 33 | let round: ImageStyle = .RoundedRectangle(size: CGSize(width: 60.0, height: 60.0), cornerRadius: 16.0, borderWidth: 0) 34 | let transformer = Transformer(URLString: URLString, style: round) 35 | imageView.kfe_setImage(byTransformer: transformer) 36 | ``` 37 | 38 | Check the demo for more information. 39 | 40 | ## Installation 41 | 42 | ### CocoaPods 43 | 44 | ```ruby 45 | pod 'KingfisherExtension', '~> 1.0.1' 46 | ``` 47 | 48 | ### Carthage 49 | 50 | ```swift 51 | github "Limon-O-O/KingfisherExtension" 52 | ``` 53 | 54 | ## Contact 55 | 56 | Contact me on [Twitter](https://twitter.com/Limon______) or [Weibo](http://weibo.com/u/1783821582) . If you find an issue, just [open a ticket](https://github.com/Limon-O-O/KingfisherExtension/issues/new) on it. Pull requests are warmly welcome as well. 57 | 58 | ## License 59 | 60 | KingfisherExtension is available under the MIT license. See the LICENSE file for more info. 61 | 62 | 63 | --------------------------------------------------------------------------------