Ver código fonte

demo project

ibireme 9 anos atrás
pai
commit
1ecf07f134
97 arquivos alterados com 3694 adições e 78 exclusões
  1. BIN
      Demo/Demo.gif
  2. 623 0
      Demo/YYWebImageDemo.xcodeproj/project.pbxproj
  3. 7 0
      Demo/YYWebImageDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  4. 30 0
      Demo/YYWebImageDemo.xcodeproj/project.xcworkspace/xcshareddata/YYWebImageDemo.xcscmblueprint
  5. 17 0
      Demo/YYWebImageDemo/AppDelegate.h
  6. 45 0
      Demo/YYWebImageDemo/AppDelegate.m
  7. 38 0
      Demo/YYWebImageDemo/Assets.xcassets/AppIcon.appiconset/Contents.json
  8. 28 0
      Demo/YYWebImageDemo/Base.lproj/LaunchScreen.storyboard
  9. 27 0
      Demo/YYWebImageDemo/Base.lproj/Main.storyboard
  10. 83 0
      Demo/YYWebImageDemo/CALayer+YYAdd.h
  11. 296 0
      Demo/YYWebImageDemo/CALayer+YYAdd.m
  12. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@2x.png
  13. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@3x.png
  14. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@2x.png
  15. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@3x.png
  16. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@2x.png
  17. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@3x.png
  18. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@2x.png
  19. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@3x.png
  20. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@2x.png
  21. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@3x.png
  22. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@2x.png
  23. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@3x.png
  24. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@2x.png
  25. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@3x.png
  26. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@2x.png
  27. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@3x.png
  28. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@2x.png
  29. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@3x.png
  30. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@2x.png
  31. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@3x.png
  32. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@2x.png
  33. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@3x.png
  34. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@2x.png
  35. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@3x.png
  36. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@2x.png
  37. BIN
      Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@3x.png
  38. 45 0
      Demo/YYWebImageDemo/Info.plist
  39. BIN
      Demo/YYWebImageDemo/ResourceTwitter.bundle/fav02l-sheet.png
  40. BIN
      Demo/YYWebImageDemo/ResourceTwitter.bundle/fav02l-sheet@2x.png
  41. 74 0
      Demo/YYWebImageDemo/UIControl+YYAdd.h
  42. 108 0
      Demo/YYWebImageDemo/UIControl+YYAdd.m
  43. 43 0
      Demo/YYWebImageDemo/UIGestureRecognizer+YYAdd.h
  44. 77 0
      Demo/YYWebImageDemo/UIGestureRecognizer+YYAdd.m
  45. 51 0
      Demo/YYWebImageDemo/UIView+YYAdd.h
  46. 139 0
      Demo/YYWebImageDemo/UIView+YYAdd.m
  47. 15 0
      Demo/YYWebImageDemo/ViewController.h
  48. 24 0
      Demo/YYWebImageDemo/ViewController.m
  49. 41 0
      Demo/YYWebImageDemo/YYBPGCoder.h
  50. 272 0
      Demo/YYWebImageDemo/YYBPGCoder.m
  51. 13 0
      Demo/YYWebImageDemo/YYImageBenchmark.h
  52. 742 0
      Demo/YYWebImageDemo/YYImageBenchmark.m
  53. 13 0
      Demo/YYWebImageDemo/YYImageDisplayExample.h
  54. 143 0
      Demo/YYWebImageDemo/YYImageDisplayExample.m
  55. 13 0
      Demo/YYWebImageDemo/YYImageExample.h
  56. 65 0
      Demo/YYWebImageDemo/YYImageExample.m
  57. 21 0
      Demo/YYWebImageDemo/YYImageExampleHelper.h
  58. 72 0
      Demo/YYWebImageDemo/YYImageExampleHelper.m
  59. 13 0
      Demo/YYWebImageDemo/YYImageProgressiveExample.h
  60. 117 0
      Demo/YYWebImageDemo/YYImageProgressiveExample.m
  61. 13 0
      Demo/YYWebImageDemo/YYWebImageExample.h
  62. 230 0
      Demo/YYWebImageDemo/YYWebImageExample.m
  63. BIN
      Demo/YYWebImageDemo/cube@2x.png
  64. BIN
      Demo/YYWebImageDemo/google@2x.webp
  65. 16 0
      Demo/YYWebImageDemo/main.m
  66. BIN
      Demo/YYWebImageDemo/mew_baseline.gif
  67. BIN
      Demo/YYWebImageDemo/mew_baseline.jpg
  68. BIN
      Demo/YYWebImageDemo/mew_baseline.png
  69. BIN
      Demo/YYWebImageDemo/mew_interlaced.gif
  70. BIN
      Demo/YYWebImageDemo/mew_interlaced.png
  71. BIN
      Demo/YYWebImageDemo/mew_progressive.jpg
  72. BIN
      Demo/YYWebImageDemo/niconiconi@2x.gif
  73. BIN
      Demo/YYWebImageDemo/nyancat@2x.webp
  74. BIN
      Demo/YYWebImageDemo/pia@2x.png
  75. BIN
      Demo/YYWebImageDemo/wall-e@2x.webp
  76. 20 22
      Framework/YYWebImage-Static.xcodeproj/project.pbxproj
  77. 8 2
      YYWebImage/Cache/YYCache.h
  78. 1 1
      YYWebImage/Cache/YYCache.m
  79. 7 7
      YYWebImage/Cache/YYDiskCache.h
  80. 2 2
      YYWebImage/Cache/YYDiskCache.m
  81. 1 1
      YYWebImage/Cache/YYKVStorage.h
  82. 2 2
      YYWebImage/Cache/YYKVStorage.m
  83. 10 3
      YYWebImage/Cache/YYMemoryCache.h
  84. 53 15
      YYWebImage/Cache/YYMemoryCache.m
  85. 2 2
      YYWebImage/Categories/_YYWebImageSetter.m
  86. 1 1
      YYWebImage/Image/YYAnimatedImageView.h
  87. 1 1
      YYWebImage/Image/YYAnimatedImageView.m
  88. 4 2
      YYWebImage/Image/YYFrameImage.h
  89. 1 1
      YYWebImage/Image/YYFrameImage.m
  90. 11 2
      YYWebImage/Image/YYImage.h
  91. 1 1
      YYWebImage/Image/YYImage.m
  92. 1 1
      YYWebImage/Image/YYImageCoder.h
  93. 1 1
      YYWebImage/Image/YYImageCoder.m
  94. 4 2
      YYWebImage/Image/YYSpriteSheetImage.h
  95. 1 1
      YYWebImage/Image/YYSpriteSheetImage.m
  96. 4 4
      YYWebImage/YYWebImage.h
  97. 4 4
      YYWebImage/YYWebImageOperation.m

BIN
Demo/Demo.gif


+ 623 - 0
Demo/YYWebImageDemo.xcodeproj/project.pbxproj

@@ -0,0 +1,623 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		ABC4238E1BE3244A00703518 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC4238D1BE3244A00703518 /* main.m */; };
+		ABC423911BE3244A00703518 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423901BE3244A00703518 /* AppDelegate.m */; };
+		ABC423941BE3244A00703518 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423931BE3244A00703518 /* ViewController.m */; };
+		ABC423971BE3244A00703518 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ABC423951BE3244A00703518 /* Main.storyboard */; };
+		ABC423991BE3244A00703518 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ABC423981BE3244A00703518 /* Assets.xcassets */; };
+		ABC4239C1BE3244A00703518 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ABC4239A1BE3244A00703518 /* LaunchScreen.storyboard */; };
+		ABC423A61BE324E800703518 /* WebP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423A51BE324E800703518 /* WebP.framework */; };
+		ABC423D01BE324F000703518 /* YYCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423AA1BE324F000703518 /* YYCache.m */; };
+		ABC423D11BE324F000703518 /* YYDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423AC1BE324F000703518 /* YYDiskCache.m */; };
+		ABC423D21BE324F000703518 /* YYKVStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423AE1BE324F000703518 /* YYKVStorage.m */; };
+		ABC423D31BE324F000703518 /* YYMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423B01BE324F000703518 /* YYMemoryCache.m */; };
+		ABC423D41BE324F000703518 /* _YYWebImageSetter.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423B31BE324F000703518 /* _YYWebImageSetter.m */; };
+		ABC423D51BE324F000703518 /* CALayer+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423B51BE324F000703518 /* CALayer+YYWebImage.m */; };
+		ABC423D61BE324F000703518 /* MKAnnotationView+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423B71BE324F000703518 /* MKAnnotationView+YYWebImage.m */; };
+		ABC423D71BE324F000703518 /* UIButton+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423B91BE324F000703518 /* UIButton+YYWebImage.m */; };
+		ABC423D81BE324F000703518 /* UIImage+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423BB1BE324F000703518 /* UIImage+YYWebImage.m */; };
+		ABC423D91BE324F000703518 /* UIImageView+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423BD1BE324F000703518 /* UIImageView+YYWebImage.m */; };
+		ABC423DA1BE324F000703518 /* YYAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423C01BE324F000703518 /* YYAnimatedImageView.m */; };
+		ABC423DB1BE324F000703518 /* YYFrameImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423C21BE324F000703518 /* YYFrameImage.m */; };
+		ABC423DC1BE324F000703518 /* YYImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423C41BE324F000703518 /* YYImage.m */; };
+		ABC423DD1BE324F000703518 /* YYImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423C61BE324F000703518 /* YYImageCoder.m */; };
+		ABC423DE1BE324F000703518 /* YYSpriteSheetImage.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423C81BE324F000703518 /* YYSpriteSheetImage.m */; };
+		ABC423DF1BE324F000703518 /* YYImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423CA1BE324F000703518 /* YYImageCache.m */; };
+		ABC423E01BE324F000703518 /* YYWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423CD1BE324F000703518 /* YYWebImageManager.m */; };
+		ABC423E11BE324F000703518 /* YYWebImageOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423CF1BE324F000703518 /* YYWebImageOperation.m */; };
+		ABC423E51BE3252800703518 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423E41BE3252800703518 /* libsqlite3.tbd */; };
+		ABC423E71BE3252D00703518 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423E61BE3252D00703518 /* libz.tbd */; };
+		ABC423E91BE3253300703518 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423E81BE3253300703518 /* MobileCoreServices.framework */; };
+		ABC423EB1BE3253800703518 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423EA1BE3253800703518 /* AssetsLibrary.framework */; };
+		ABC423ED1BE3253D00703518 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423EC1BE3253D00703518 /* QuartzCore.framework */; };
+		ABC423EF1BE3254400703518 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423EE1BE3254400703518 /* ImageIO.framework */; };
+		ABC423F11BE3254C00703518 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423F01BE3254C00703518 /* CoreFoundation.framework */; };
+		ABC423F21BE3255200703518 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABC423E21BE3251C00703518 /* UIKit.framework */; };
+		ABC424011BE325EF00703518 /* YYImageExample.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423F41BE325EF00703518 /* YYImageExample.m */; };
+		ABC424021BE325EF00703518 /* YYImageDisplayExample.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423F61BE325EF00703518 /* YYImageDisplayExample.m */; };
+		ABC424031BE325EF00703518 /* YYImageProgressiveExample.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423F81BE325EF00703518 /* YYImageProgressiveExample.m */; };
+		ABC424041BE325EF00703518 /* YYWebImageExample.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423FA1BE325EF00703518 /* YYWebImageExample.m */; };
+		ABC424061BE325EF00703518 /* YYImageExampleHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC423FE1BE325EF00703518 /* YYImageExampleHelper.m */; };
+		ABC424181BE3265500703518 /* ResourceTwitter.bundle in Resources */ = {isa = PBXBuildFile; fileRef = ABC4240A1BE3265500703518 /* ResourceTwitter.bundle */; };
+		ABC424191BE3265500703518 /* EmoticonWeibo.bundle in Resources */ = {isa = PBXBuildFile; fileRef = ABC4240B1BE3265500703518 /* EmoticonWeibo.bundle */; };
+		ABC4241A1BE3265500703518 /* niconiconi@2x.gif in Resources */ = {isa = PBXBuildFile; fileRef = ABC4240C1BE3265500703518 /* niconiconi@2x.gif */; };
+		ABC4241B1BE3265500703518 /* google@2x.webp in Resources */ = {isa = PBXBuildFile; fileRef = ABC4240D1BE3265500703518 /* google@2x.webp */; };
+		ABC4241C1BE3265500703518 /* nyancat@2x.webp in Resources */ = {isa = PBXBuildFile; fileRef = ABC4240E1BE3265500703518 /* nyancat@2x.webp */; };
+		ABC4241D1BE3265500703518 /* pia@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = ABC4240F1BE3265500703518 /* pia@2x.png */; };
+		ABC4241E1BE3265500703518 /* cube@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = ABC424101BE3265500703518 /* cube@2x.png */; };
+		ABC4241F1BE3265500703518 /* wall-e@2x.webp in Resources */ = {isa = PBXBuildFile; fileRef = ABC424111BE3265500703518 /* wall-e@2x.webp */; };
+		ABC424201BE3265500703518 /* mew_baseline.jpg in Resources */ = {isa = PBXBuildFile; fileRef = ABC424121BE3265500703518 /* mew_baseline.jpg */; };
+		ABC424211BE3265500703518 /* mew_progressive.jpg in Resources */ = {isa = PBXBuildFile; fileRef = ABC424131BE3265500703518 /* mew_progressive.jpg */; };
+		ABC424221BE3265500703518 /* mew_baseline.png in Resources */ = {isa = PBXBuildFile; fileRef = ABC424141BE3265500703518 /* mew_baseline.png */; };
+		ABC424231BE3265500703518 /* mew_interlaced.png in Resources */ = {isa = PBXBuildFile; fileRef = ABC424151BE3265500703518 /* mew_interlaced.png */; };
+		ABC424241BE3265500703518 /* mew_baseline.gif in Resources */ = {isa = PBXBuildFile; fileRef = ABC424161BE3265500703518 /* mew_baseline.gif */; };
+		ABC424251BE3265500703518 /* mew_interlaced.gif in Resources */ = {isa = PBXBuildFile; fileRef = ABC424171BE3265500703518 /* mew_interlaced.gif */; };
+		ABC4242C1BE3268800703518 /* UIView+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC424271BE3268800703518 /* UIView+YYAdd.m */; };
+		ABC4242D1BE3268800703518 /* UIControl+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC424291BE3268800703518 /* UIControl+YYAdd.m */; };
+		ABC4242E1BE3268800703518 /* UIGestureRecognizer+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC4242B1BE3268800703518 /* UIGestureRecognizer+YYAdd.m */; };
+		ABC424311BE3284000703518 /* CALayer+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = ABC424301BE3284000703518 /* CALayer+YYAdd.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		ABC423891BE3244A00703518 /* YYWebImageDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YYWebImageDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		ABC4238D1BE3244A00703518 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		ABC4238F1BE3244A00703518 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		ABC423901BE3244A00703518 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+		ABC423921BE3244A00703518 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+		ABC423931BE3244A00703518 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+		ABC423961BE3244A00703518 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		ABC423981BE3244A00703518 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		ABC4239B1BE3244A00703518 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		ABC4239D1BE3244A00703518 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		ABC423A51BE324E800703518 /* WebP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebP.framework; path = ../Vendor/WebP.framework; sourceTree = "<group>"; };
+		ABC423A91BE324F000703518 /* YYCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYCache.h; sourceTree = "<group>"; };
+		ABC423AA1BE324F000703518 /* YYCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYCache.m; sourceTree = "<group>"; };
+		ABC423AB1BE324F000703518 /* YYDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYDiskCache.h; sourceTree = "<group>"; };
+		ABC423AC1BE324F000703518 /* YYDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYDiskCache.m; sourceTree = "<group>"; };
+		ABC423AD1BE324F000703518 /* YYKVStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYKVStorage.h; sourceTree = "<group>"; };
+		ABC423AE1BE324F000703518 /* YYKVStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYKVStorage.m; sourceTree = "<group>"; };
+		ABC423AF1BE324F000703518 /* YYMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYMemoryCache.h; sourceTree = "<group>"; };
+		ABC423B01BE324F000703518 /* YYMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYMemoryCache.m; sourceTree = "<group>"; };
+		ABC423B21BE324F000703518 /* _YYWebImageSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _YYWebImageSetter.h; sourceTree = "<group>"; };
+		ABC423B31BE324F000703518 /* _YYWebImageSetter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _YYWebImageSetter.m; sourceTree = "<group>"; };
+		ABC423B41BE324F000703518 /* CALayer+YYWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CALayer+YYWebImage.h"; sourceTree = "<group>"; };
+		ABC423B51BE324F000703518 /* CALayer+YYWebImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CALayer+YYWebImage.m"; sourceTree = "<group>"; };
+		ABC423B61BE324F000703518 /* MKAnnotationView+YYWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+YYWebImage.h"; sourceTree = "<group>"; };
+		ABC423B71BE324F000703518 /* MKAnnotationView+YYWebImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+YYWebImage.m"; sourceTree = "<group>"; };
+		ABC423B81BE324F000703518 /* UIButton+YYWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIButton+YYWebImage.h"; sourceTree = "<group>"; };
+		ABC423B91BE324F000703518 /* UIButton+YYWebImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIButton+YYWebImage.m"; sourceTree = "<group>"; };
+		ABC423BA1BE324F000703518 /* UIImage+YYWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+YYWebImage.h"; sourceTree = "<group>"; };
+		ABC423BB1BE324F000703518 /* UIImage+YYWebImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+YYWebImage.m"; sourceTree = "<group>"; };
+		ABC423BC1BE324F000703518 /* UIImageView+YYWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+YYWebImage.h"; sourceTree = "<group>"; };
+		ABC423BD1BE324F000703518 /* UIImageView+YYWebImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+YYWebImage.m"; sourceTree = "<group>"; };
+		ABC423BF1BE324F000703518 /* YYAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYAnimatedImageView.h; sourceTree = "<group>"; };
+		ABC423C01BE324F000703518 /* YYAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYAnimatedImageView.m; sourceTree = "<group>"; };
+		ABC423C11BE324F000703518 /* YYFrameImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYFrameImage.h; sourceTree = "<group>"; };
+		ABC423C21BE324F000703518 /* YYFrameImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYFrameImage.m; sourceTree = "<group>"; };
+		ABC423C31BE324F000703518 /* YYImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImage.h; sourceTree = "<group>"; };
+		ABC423C41BE324F000703518 /* YYImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImage.m; sourceTree = "<group>"; };
+		ABC423C51BE324F000703518 /* YYImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageCoder.h; sourceTree = "<group>"; };
+		ABC423C61BE324F000703518 /* YYImageCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageCoder.m; sourceTree = "<group>"; };
+		ABC423C71BE324F000703518 /* YYSpriteSheetImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYSpriteSheetImage.h; sourceTree = "<group>"; };
+		ABC423C81BE324F000703518 /* YYSpriteSheetImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYSpriteSheetImage.m; sourceTree = "<group>"; };
+		ABC423C91BE324F000703518 /* YYImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageCache.h; sourceTree = "<group>"; };
+		ABC423CA1BE324F000703518 /* YYImageCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageCache.m; sourceTree = "<group>"; };
+		ABC423CB1BE324F000703518 /* YYWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYWebImage.h; sourceTree = "<group>"; };
+		ABC423CC1BE324F000703518 /* YYWebImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYWebImageManager.h; sourceTree = "<group>"; };
+		ABC423CD1BE324F000703518 /* YYWebImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYWebImageManager.m; sourceTree = "<group>"; };
+		ABC423CE1BE324F000703518 /* YYWebImageOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYWebImageOperation.h; sourceTree = "<group>"; };
+		ABC423CF1BE324F000703518 /* YYWebImageOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYWebImageOperation.m; sourceTree = "<group>"; };
+		ABC423E21BE3251C00703518 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		ABC423E41BE3252800703518 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
+		ABC423E61BE3252D00703518 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
+		ABC423E81BE3253300703518 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
+		ABC423EA1BE3253800703518 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
+		ABC423EC1BE3253D00703518 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		ABC423EE1BE3254400703518 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
+		ABC423F01BE3254C00703518 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+		ABC423F31BE325EF00703518 /* YYImageExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageExample.h; sourceTree = "<group>"; };
+		ABC423F41BE325EF00703518 /* YYImageExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageExample.m; sourceTree = "<group>"; };
+		ABC423F51BE325EF00703518 /* YYImageDisplayExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageDisplayExample.h; sourceTree = "<group>"; };
+		ABC423F61BE325EF00703518 /* YYImageDisplayExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageDisplayExample.m; sourceTree = "<group>"; };
+		ABC423F71BE325EF00703518 /* YYImageProgressiveExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageProgressiveExample.h; sourceTree = "<group>"; };
+		ABC423F81BE325EF00703518 /* YYImageProgressiveExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageProgressiveExample.m; sourceTree = "<group>"; };
+		ABC423F91BE325EF00703518 /* YYWebImageExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYWebImageExample.h; sourceTree = "<group>"; };
+		ABC423FA1BE325EF00703518 /* YYWebImageExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYWebImageExample.m; sourceTree = "<group>"; };
+		ABC423FB1BE325EF00703518 /* YYImageBenchmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageBenchmark.h; sourceTree = "<group>"; };
+		ABC423FC1BE325EF00703518 /* YYImageBenchmark.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageBenchmark.m; sourceTree = "<group>"; };
+		ABC423FD1BE325EF00703518 /* YYImageExampleHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageExampleHelper.h; sourceTree = "<group>"; };
+		ABC423FE1BE325EF00703518 /* YYImageExampleHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageExampleHelper.m; sourceTree = "<group>"; };
+		ABC423FF1BE325EF00703518 /* YYBPGCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYBPGCoder.h; sourceTree = "<group>"; };
+		ABC424001BE325EF00703518 /* YYBPGCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYBPGCoder.m; sourceTree = "<group>"; };
+		ABC4240A1BE3265500703518 /* ResourceTwitter.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ResourceTwitter.bundle; sourceTree = "<group>"; };
+		ABC4240B1BE3265500703518 /* EmoticonWeibo.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = EmoticonWeibo.bundle; sourceTree = "<group>"; };
+		ABC4240C1BE3265500703518 /* niconiconi@2x.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "niconiconi@2x.gif"; sourceTree = "<group>"; };
+		ABC4240D1BE3265500703518 /* google@2x.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = "google@2x.webp"; sourceTree = "<group>"; };
+		ABC4240E1BE3265500703518 /* nyancat@2x.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = "nyancat@2x.webp"; sourceTree = "<group>"; };
+		ABC4240F1BE3265500703518 /* pia@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pia@2x.png"; sourceTree = "<group>"; };
+		ABC424101BE3265500703518 /* cube@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cube@2x.png"; sourceTree = "<group>"; };
+		ABC424111BE3265500703518 /* wall-e@2x.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = "wall-e@2x.webp"; sourceTree = "<group>"; };
+		ABC424121BE3265500703518 /* mew_baseline.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = mew_baseline.jpg; sourceTree = "<group>"; };
+		ABC424131BE3265500703518 /* mew_progressive.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = mew_progressive.jpg; sourceTree = "<group>"; };
+		ABC424141BE3265500703518 /* mew_baseline.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mew_baseline.png; sourceTree = "<group>"; };
+		ABC424151BE3265500703518 /* mew_interlaced.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mew_interlaced.png; sourceTree = "<group>"; };
+		ABC424161BE3265500703518 /* mew_baseline.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = mew_baseline.gif; sourceTree = "<group>"; };
+		ABC424171BE3265500703518 /* mew_interlaced.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = mew_interlaced.gif; sourceTree = "<group>"; };
+		ABC424261BE3268800703518 /* UIView+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+YYAdd.h"; sourceTree = "<group>"; };
+		ABC424271BE3268800703518 /* UIView+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+YYAdd.m"; sourceTree = "<group>"; };
+		ABC424281BE3268800703518 /* UIControl+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+YYAdd.h"; sourceTree = "<group>"; };
+		ABC424291BE3268800703518 /* UIControl+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+YYAdd.m"; sourceTree = "<group>"; };
+		ABC4242A1BE3268800703518 /* UIGestureRecognizer+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIGestureRecognizer+YYAdd.h"; sourceTree = "<group>"; };
+		ABC4242B1BE3268800703518 /* UIGestureRecognizer+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIGestureRecognizer+YYAdd.m"; sourceTree = "<group>"; };
+		ABC4242F1BE3284000703518 /* CALayer+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CALayer+YYAdd.h"; sourceTree = "<group>"; };
+		ABC424301BE3284000703518 /* CALayer+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CALayer+YYAdd.m"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		ABC423861BE3244A00703518 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				ABC423A61BE324E800703518 /* WebP.framework in Frameworks */,
+				ABC423F21BE3255200703518 /* UIKit.framework in Frameworks */,
+				ABC423F11BE3254C00703518 /* CoreFoundation.framework in Frameworks */,
+				ABC423EF1BE3254400703518 /* ImageIO.framework in Frameworks */,
+				ABC423ED1BE3253D00703518 /* QuartzCore.framework in Frameworks */,
+				ABC423EB1BE3253800703518 /* AssetsLibrary.framework in Frameworks */,
+				ABC423E91BE3253300703518 /* MobileCoreServices.framework in Frameworks */,
+				ABC423E71BE3252D00703518 /* libz.tbd in Frameworks */,
+				ABC423E51BE3252800703518 /* libsqlite3.tbd in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		ABC423801BE3244A00703518 = {
+			isa = PBXGroup;
+			children = (
+				ABC423A51BE324E800703518 /* WebP.framework */,
+				ABC423A71BE324F000703518 /* YYWebImage */,
+				ABC4238B1BE3244A00703518 /* YYWebImageDemo */,
+				ABC4238A1BE3244A00703518 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		ABC4238A1BE3244A00703518 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				ABC423891BE3244A00703518 /* YYWebImageDemo.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		ABC4238B1BE3244A00703518 /* YYWebImageDemo */ = {
+			isa = PBXGroup;
+			children = (
+				ABC423F31BE325EF00703518 /* YYImageExample.h */,
+				ABC423F41BE325EF00703518 /* YYImageExample.m */,
+				ABC423F51BE325EF00703518 /* YYImageDisplayExample.h */,
+				ABC423F61BE325EF00703518 /* YYImageDisplayExample.m */,
+				ABC423F71BE325EF00703518 /* YYImageProgressiveExample.h */,
+				ABC423F81BE325EF00703518 /* YYImageProgressiveExample.m */,
+				ABC423F91BE325EF00703518 /* YYWebImageExample.h */,
+				ABC423FA1BE325EF00703518 /* YYWebImageExample.m */,
+				ABC423FD1BE325EF00703518 /* YYImageExampleHelper.h */,
+				ABC423FE1BE325EF00703518 /* YYImageExampleHelper.m */,
+				ABC424091BE3264600703518 /* Resources */,
+				ABC424081BE3262E00703518 /* Not available */,
+				ABC4238C1BE3244A00703518 /* Supporting Files */,
+			);
+			path = YYWebImageDemo;
+			sourceTree = "<group>";
+		};
+		ABC4238C1BE3244A00703518 /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				ABC4238F1BE3244A00703518 /* AppDelegate.h */,
+				ABC423901BE3244A00703518 /* AppDelegate.m */,
+				ABC423921BE3244A00703518 /* ViewController.h */,
+				ABC423931BE3244A00703518 /* ViewController.m */,
+				ABC424261BE3268800703518 /* UIView+YYAdd.h */,
+				ABC424271BE3268800703518 /* UIView+YYAdd.m */,
+				ABC4242F1BE3284000703518 /* CALayer+YYAdd.h */,
+				ABC424301BE3284000703518 /* CALayer+YYAdd.m */,
+				ABC424281BE3268800703518 /* UIControl+YYAdd.h */,
+				ABC424291BE3268800703518 /* UIControl+YYAdd.m */,
+				ABC4242A1BE3268800703518 /* UIGestureRecognizer+YYAdd.h */,
+				ABC4242B1BE3268800703518 /* UIGestureRecognizer+YYAdd.m */,
+				ABC423F01BE3254C00703518 /* CoreFoundation.framework */,
+				ABC423EE1BE3254400703518 /* ImageIO.framework */,
+				ABC423EC1BE3253D00703518 /* QuartzCore.framework */,
+				ABC423EA1BE3253800703518 /* AssetsLibrary.framework */,
+				ABC423E81BE3253300703518 /* MobileCoreServices.framework */,
+				ABC423E61BE3252D00703518 /* libz.tbd */,
+				ABC423E41BE3252800703518 /* libsqlite3.tbd */,
+				ABC423E21BE3251C00703518 /* UIKit.framework */,
+				ABC423951BE3244A00703518 /* Main.storyboard */,
+				ABC423981BE3244A00703518 /* Assets.xcassets */,
+				ABC4239A1BE3244A00703518 /* LaunchScreen.storyboard */,
+				ABC4239D1BE3244A00703518 /* Info.plist */,
+				ABC4238D1BE3244A00703518 /* main.m */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+		ABC423A71BE324F000703518 /* YYWebImage */ = {
+			isa = PBXGroup;
+			children = (
+				ABC423A81BE324F000703518 /* Cache */,
+				ABC423BE1BE324F000703518 /* Image */,
+				ABC423B11BE324F000703518 /* Categories */,
+				ABC423C91BE324F000703518 /* YYImageCache.h */,
+				ABC423CA1BE324F000703518 /* YYImageCache.m */,
+				ABC423CB1BE324F000703518 /* YYWebImage.h */,
+				ABC423CC1BE324F000703518 /* YYWebImageManager.h */,
+				ABC423CD1BE324F000703518 /* YYWebImageManager.m */,
+				ABC423CE1BE324F000703518 /* YYWebImageOperation.h */,
+				ABC423CF1BE324F000703518 /* YYWebImageOperation.m */,
+			);
+			name = YYWebImage;
+			path = ../YYWebImage;
+			sourceTree = "<group>";
+		};
+		ABC423A81BE324F000703518 /* Cache */ = {
+			isa = PBXGroup;
+			children = (
+				ABC423A91BE324F000703518 /* YYCache.h */,
+				ABC423AA1BE324F000703518 /* YYCache.m */,
+				ABC423AB1BE324F000703518 /* YYDiskCache.h */,
+				ABC423AC1BE324F000703518 /* YYDiskCache.m */,
+				ABC423AD1BE324F000703518 /* YYKVStorage.h */,
+				ABC423AE1BE324F000703518 /* YYKVStorage.m */,
+				ABC423AF1BE324F000703518 /* YYMemoryCache.h */,
+				ABC423B01BE324F000703518 /* YYMemoryCache.m */,
+			);
+			path = Cache;
+			sourceTree = "<group>";
+		};
+		ABC423B11BE324F000703518 /* Categories */ = {
+			isa = PBXGroup;
+			children = (
+				ABC423B21BE324F000703518 /* _YYWebImageSetter.h */,
+				ABC423B31BE324F000703518 /* _YYWebImageSetter.m */,
+				ABC423B41BE324F000703518 /* CALayer+YYWebImage.h */,
+				ABC423B51BE324F000703518 /* CALayer+YYWebImage.m */,
+				ABC423B61BE324F000703518 /* MKAnnotationView+YYWebImage.h */,
+				ABC423B71BE324F000703518 /* MKAnnotationView+YYWebImage.m */,
+				ABC423B81BE324F000703518 /* UIButton+YYWebImage.h */,
+				ABC423B91BE324F000703518 /* UIButton+YYWebImage.m */,
+				ABC423BA1BE324F000703518 /* UIImage+YYWebImage.h */,
+				ABC423BB1BE324F000703518 /* UIImage+YYWebImage.m */,
+				ABC423BC1BE324F000703518 /* UIImageView+YYWebImage.h */,
+				ABC423BD1BE324F000703518 /* UIImageView+YYWebImage.m */,
+			);
+			path = Categories;
+			sourceTree = "<group>";
+		};
+		ABC423BE1BE324F000703518 /* Image */ = {
+			isa = PBXGroup;
+			children = (
+				ABC423BF1BE324F000703518 /* YYAnimatedImageView.h */,
+				ABC423C01BE324F000703518 /* YYAnimatedImageView.m */,
+				ABC423C11BE324F000703518 /* YYFrameImage.h */,
+				ABC423C21BE324F000703518 /* YYFrameImage.m */,
+				ABC423C31BE324F000703518 /* YYImage.h */,
+				ABC423C41BE324F000703518 /* YYImage.m */,
+				ABC423C51BE324F000703518 /* YYImageCoder.h */,
+				ABC423C61BE324F000703518 /* YYImageCoder.m */,
+				ABC423C71BE324F000703518 /* YYSpriteSheetImage.h */,
+				ABC423C81BE324F000703518 /* YYSpriteSheetImage.m */,
+			);
+			path = Image;
+			sourceTree = "<group>";
+		};
+		ABC424081BE3262E00703518 /* Not available */ = {
+			isa = PBXGroup;
+			children = (
+				ABC423FB1BE325EF00703518 /* YYImageBenchmark.h */,
+				ABC423FC1BE325EF00703518 /* YYImageBenchmark.m */,
+				ABC423FF1BE325EF00703518 /* YYBPGCoder.h */,
+				ABC424001BE325EF00703518 /* YYBPGCoder.m */,
+			);
+			name = "Not available";
+			sourceTree = "<group>";
+		};
+		ABC424091BE3264600703518 /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				ABC4240A1BE3265500703518 /* ResourceTwitter.bundle */,
+				ABC4240B1BE3265500703518 /* EmoticonWeibo.bundle */,
+				ABC4240C1BE3265500703518 /* niconiconi@2x.gif */,
+				ABC4240D1BE3265500703518 /* google@2x.webp */,
+				ABC4240E1BE3265500703518 /* nyancat@2x.webp */,
+				ABC4240F1BE3265500703518 /* pia@2x.png */,
+				ABC424101BE3265500703518 /* cube@2x.png */,
+				ABC424111BE3265500703518 /* wall-e@2x.webp */,
+				ABC424121BE3265500703518 /* mew_baseline.jpg */,
+				ABC424131BE3265500703518 /* mew_progressive.jpg */,
+				ABC424141BE3265500703518 /* mew_baseline.png */,
+				ABC424151BE3265500703518 /* mew_interlaced.png */,
+				ABC424161BE3265500703518 /* mew_baseline.gif */,
+				ABC424171BE3265500703518 /* mew_interlaced.gif */,
+			);
+			name = Resources;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		ABC423881BE3244A00703518 /* YYWebImageDemo */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = ABC423A01BE3244A00703518 /* Build configuration list for PBXNativeTarget "YYWebImageDemo" */;
+			buildPhases = (
+				ABC423851BE3244A00703518 /* Sources */,
+				ABC423861BE3244A00703518 /* Frameworks */,
+				ABC423871BE3244A00703518 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = YYWebImageDemo;
+			productName = YYWebImageDemo;
+			productReference = ABC423891BE3244A00703518 /* YYWebImageDemo.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		ABC423811BE3244A00703518 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0710;
+				ORGANIZATIONNAME = ibireme;
+				TargetAttributes = {
+					ABC423881BE3244A00703518 = {
+						CreatedOnToolsVersion = 7.1;
+					};
+				};
+			};
+			buildConfigurationList = ABC423841BE3244A00703518 /* Build configuration list for PBXProject "YYWebImageDemo" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = ABC423801BE3244A00703518;
+			productRefGroup = ABC4238A1BE3244A00703518 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				ABC423881BE3244A00703518 /* YYWebImageDemo */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		ABC423871BE3244A00703518 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				ABC4241D1BE3265500703518 /* pia@2x.png in Resources */,
+				ABC4239C1BE3244A00703518 /* LaunchScreen.storyboard in Resources */,
+				ABC424181BE3265500703518 /* ResourceTwitter.bundle in Resources */,
+				ABC4241B1BE3265500703518 /* google@2x.webp in Resources */,
+				ABC4241C1BE3265500703518 /* nyancat@2x.webp in Resources */,
+				ABC4241F1BE3265500703518 /* wall-e@2x.webp in Resources */,
+				ABC424251BE3265500703518 /* mew_interlaced.gif in Resources */,
+				ABC424211BE3265500703518 /* mew_progressive.jpg in Resources */,
+				ABC424231BE3265500703518 /* mew_interlaced.png in Resources */,
+				ABC4241A1BE3265500703518 /* niconiconi@2x.gif in Resources */,
+				ABC424221BE3265500703518 /* mew_baseline.png in Resources */,
+				ABC423991BE3244A00703518 /* Assets.xcassets in Resources */,
+				ABC423971BE3244A00703518 /* Main.storyboard in Resources */,
+				ABC424191BE3265500703518 /* EmoticonWeibo.bundle in Resources */,
+				ABC424201BE3265500703518 /* mew_baseline.jpg in Resources */,
+				ABC4241E1BE3265500703518 /* cube@2x.png in Resources */,
+				ABC424241BE3265500703518 /* mew_baseline.gif in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		ABC423851BE3244A00703518 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				ABC424031BE325EF00703518 /* YYImageProgressiveExample.m in Sources */,
+				ABC424021BE325EF00703518 /* YYImageDisplayExample.m in Sources */,
+				ABC4242E1BE3268800703518 /* UIGestureRecognizer+YYAdd.m in Sources */,
+				ABC423D91BE324F000703518 /* UIImageView+YYWebImage.m in Sources */,
+				ABC423D21BE324F000703518 /* YYKVStorage.m in Sources */,
+				ABC424061BE325EF00703518 /* YYImageExampleHelper.m in Sources */,
+				ABC423941BE3244A00703518 /* ViewController.m in Sources */,
+				ABC423911BE3244A00703518 /* AppDelegate.m in Sources */,
+				ABC424011BE325EF00703518 /* YYImageExample.m in Sources */,
+				ABC423D11BE324F000703518 /* YYDiskCache.m in Sources */,
+				ABC423DD1BE324F000703518 /* YYImageCoder.m in Sources */,
+				ABC423DF1BE324F000703518 /* YYImageCache.m in Sources */,
+				ABC423D01BE324F000703518 /* YYCache.m in Sources */,
+				ABC423E01BE324F000703518 /* YYWebImageManager.m in Sources */,
+				ABC423DB1BE324F000703518 /* YYFrameImage.m in Sources */,
+				ABC4242D1BE3268800703518 /* UIControl+YYAdd.m in Sources */,
+				ABC423D31BE324F000703518 /* YYMemoryCache.m in Sources */,
+				ABC4238E1BE3244A00703518 /* main.m in Sources */,
+				ABC423DC1BE324F000703518 /* YYImage.m in Sources */,
+				ABC423E11BE324F000703518 /* YYWebImageOperation.m in Sources */,
+				ABC424041BE325EF00703518 /* YYWebImageExample.m in Sources */,
+				ABC423D41BE324F000703518 /* _YYWebImageSetter.m in Sources */,
+				ABC423DE1BE324F000703518 /* YYSpriteSheetImage.m in Sources */,
+				ABC424311BE3284000703518 /* CALayer+YYAdd.m in Sources */,
+				ABC423DA1BE324F000703518 /* YYAnimatedImageView.m in Sources */,
+				ABC423D61BE324F000703518 /* MKAnnotationView+YYWebImage.m in Sources */,
+				ABC4242C1BE3268800703518 /* UIView+YYAdd.m in Sources */,
+				ABC423D51BE324F000703518 /* CALayer+YYWebImage.m in Sources */,
+				ABC423D81BE324F000703518 /* UIImage+YYWebImage.m in Sources */,
+				ABC423D71BE324F000703518 /* UIButton+YYWebImage.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		ABC423951BE3244A00703518 /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				ABC423961BE3244A00703518 /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		ABC4239A1BE3244A00703518 /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				ABC4239B1BE3244A00703518 /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		ABC4239E1BE3244A00703518 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.1;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+			};
+			name = Debug;
+		};
+		ABC4239F1BE3244A00703518 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.1;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		ABC423A11BE3244A00703518 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../Vendor\"";
+				INFOPLIST_FILE = YYWebImageDemo/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYWebImageDemo;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		ABC423A21BE3244A00703518 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)/../Vendor\"";
+				INFOPLIST_FILE = YYWebImageDemo/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYWebImageDemo;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		ABC423841BE3244A00703518 /* Build configuration list for PBXProject "YYWebImageDemo" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				ABC4239E1BE3244A00703518 /* Debug */,
+				ABC4239F1BE3244A00703518 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		ABC423A01BE3244A00703518 /* Build configuration list for PBXNativeTarget "YYWebImageDemo" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				ABC423A11BE3244A00703518 /* Debug */,
+				ABC423A21BE3244A00703518 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = ABC423811BE3244A00703518 /* Project object */;
+}

+ 7 - 0
Demo/YYWebImageDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:YYWebImageDemo.xcodeproj">
+   </FileRef>
+</Workspace>

+ 30 - 0
Demo/YYWebImageDemo.xcodeproj/project.xcworkspace/xcshareddata/YYWebImageDemo.xcscmblueprint

@@ -0,0 +1,30 @@
+{
+  "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "2B63CCF71525A271478FBA0FCECF929E60AF80A6",
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
+
+  },
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
+    "2B63CCF71525A271478FBA0FCECF929E60AF80A6" : 0,
+    "7D036270E758B4C9CAAD42288C450F2518AF5495" : 0
+  },
+  "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "C206B33E-2BB5-4703-A85A-81C8A02DF852",
+  "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
+    "2B63CCF71525A271478FBA0FCECF929E60AF80A6" : "YYWebImage\/",
+    "7D036270E758B4C9CAAD42288C450F2518AF5495" : "YYImage\/"
+  },
+  "DVTSourceControlWorkspaceBlueprintNameKey" : "YYWebImageDemo",
+  "DVTSourceControlWorkspaceBlueprintVersion" : 204,
+  "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Demo\/YYWebImageDemo.xcodeproj",
+  "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
+    {
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/ibireme\/YYWebImage.git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "2B63CCF71525A271478FBA0FCECF929E60AF80A6"
+    },
+    {
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/ibireme\/YYImage.git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+      "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "7D036270E758B4C9CAAD42288C450F2518AF5495"
+    }
+  ]
+}

+ 17 - 0
Demo/YYWebImageDemo/AppDelegate.h

@@ -0,0 +1,17 @@
+//
+//  AppDelegate.h
+//  YYWebImageDemo
+//
+//  Created by guoyaoyuan on 15/10/30.
+//  Copyright © 2015年 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+
+@end
+

+ 45 - 0
Demo/YYWebImageDemo/AppDelegate.m

@@ -0,0 +1,45 @@
+//
+//  AppDelegate.m
+//  YYWebImageDemo
+//
+//  Created by guoyaoyuan on 15/10/30.
+//  Copyright © 2015年 ibireme. All rights reserved.
+//
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+    // Override point for customization after application launch.
+    return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+@end

+ 38 - 0
Demo/YYWebImageDemo/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,38 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 28 - 0
Demo/YYWebImageDemo/Base.lproj/LaunchScreen.storyboard

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
+                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <animations/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>

+ 27 - 0
Demo/YYWebImageDemo/Base.lproj/Main.storyboard

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9049"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <animations/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>

+ 83 - 0
Demo/YYWebImageDemo/CALayer+YYAdd.h

@@ -0,0 +1,83 @@
+//
+//  CALayer+YYAdd.h
+//  YYKit <https://github.com/ibireme/YYKit>
+//
+//  Created by ibireme on 14/5/10.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+
+/**
+ Provides extensions for `CALayer`.
+ */
+@interface CALayer (YYAdd)
+
+/**
+ Take snapshot without transform, image's size equals to bounds.
+ */
+- (UIImage *)snapshotImage;
+
+/**
+ Shortcut to set the layer's shadow
+ 
+ @param color  Shadow Color
+ @param offset Shadow offset
+ @param radius Shadow radius
+ */
+- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
+
+/**
+ Remove all sublayers.
+ */
+- (void)removeAllSublayers;
+
+@property (nonatomic) CGFloat left;        ///< Shortcut for frame.origin.x.
+@property (nonatomic) CGFloat top;         ///< Shortcut for frame.origin.y
+@property (nonatomic) CGFloat right;       ///< Shortcut for frame.origin.x + frame.size.width
+@property (nonatomic) CGFloat bottom;      ///< Shortcut for frame.origin.y + frame.size.height
+@property (nonatomic) CGFloat width;       ///< Shortcut for frame.size.width.
+@property (nonatomic) CGFloat height;      ///< Shortcut for frame.size.height.
+@property (nonatomic) CGPoint center;      ///< Shortcut for center.
+@property (nonatomic) CGFloat centerX;     ///< Shortcut for center.x
+@property (nonatomic) CGFloat centerY;     ///< Shortcut for center.y
+@property (nonatomic) CGPoint origin;      ///< Shortcut for frame.origin.
+@property (nonatomic, getter=frameSize, setter=setFrameSize:) CGSize  size; ///< Shortcut for frame.size.
+
+
+@property (nonatomic) CGFloat transformRotation;     ///< key path "tranform.rotation"
+@property (nonatomic) CGFloat transformRotationX;    ///< key path "tranform.rotation.x"
+@property (nonatomic) CGFloat transformRotationY;    ///< key path "tranform.rotation.y"
+@property (nonatomic) CGFloat transformRotationZ;    ///< key path "tranform.rotation.z"
+@property (nonatomic) CGFloat transformScale;        ///< key path "tranform.scale"
+@property (nonatomic) CGFloat transformScaleX;       ///< key path "tranform.scale.x"
+@property (nonatomic) CGFloat transformScaleY;       ///< key path "tranform.scale.y"
+@property (nonatomic) CGFloat transformScaleZ;       ///< key path "tranform.scale.z"
+@property (nonatomic) CGFloat transformTranslationX; ///< key path "tranform.translation.x"
+@property (nonatomic) CGFloat transformTranslationY; ///< key path "tranform.translation.y"
+@property (nonatomic) CGFloat transformTranslationZ; ///< key path "tranform.translation.z"
+
+/**
+ Shortcut for transform.m34, -1/1000 is a good value.
+ It should be set before other transform shortcut.
+ */
+@property (nonatomic, assign) CGFloat transformDepth;
+
+/**
+ Add a fade animation to layer's contents when the contents is changed.
+ 
+ @param duration Animation duration
+ @param curve    Animation curve.
+ */
+- (void)addFadeAnimationWithDuration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve;
+
+/**
+ Cancel fade animation which is added with "-addFadeAnimationWithDuration:curve:".
+ */
+- (void)removePreviousFadeAnimation;
+
+@end

+ 296 - 0
Demo/YYWebImageDemo/CALayer+YYAdd.m

@@ -0,0 +1,296 @@
+//
+//  CALayer+YYAdd.m
+//  YYKit <https://github.com/ibireme/YYKit>
+//
+//  Created by ibireme on 14/5/10.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import "CALayer+YYAdd.h"
+
+
+
+@implementation CALayer (YYAdd)
+
+- (UIImage *)snapshotImage {
+    UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0);
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    [self renderInContext:context];
+    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return image;
+}
+
+- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius {
+    self.shadowColor = color.CGColor;
+    self.shadowOffset = offset;
+    self.shadowRadius = radius;
+    self.shadowOpacity = 1;
+    self.shouldRasterize = YES;
+    self.rasterizationScale = [UIScreen mainScreen].scale;
+}
+
+- (void)removeAllSublayers {
+    while (self.sublayers.count) {
+        [self.sublayers.lastObject removeFromSuperlayer];
+    }
+}
+
+- (CGFloat)left {
+    return self.frame.origin.x;
+}
+
+- (void)setLeft:(CGFloat)x {
+    CGRect frame = self.frame;
+    frame.origin.x = x;
+    self.frame = frame;
+}
+
+- (CGFloat)top {
+    return self.frame.origin.y;
+}
+
+- (void)setTop:(CGFloat)y {
+    CGRect frame = self.frame;
+    frame.origin.y = y;
+    self.frame = frame;
+}
+
+- (CGFloat)right {
+    return self.frame.origin.x + self.frame.size.width;
+}
+
+- (void)setRight:(CGFloat)right {
+    CGRect frame = self.frame;
+    frame.origin.x = right - frame.size.width;
+    self.frame = frame;
+}
+
+- (CGFloat)bottom {
+    return self.frame.origin.y + self.frame.size.height;
+}
+
+- (void)setBottom:(CGFloat)bottom {
+    CGRect frame = self.frame;
+    frame.origin.y = bottom - frame.size.height;
+    self.frame = frame;
+}
+
+- (CGFloat)width {
+    return self.frame.size.width;
+}
+
+- (void)setWidth:(CGFloat)width {
+    CGRect frame = self.frame;
+    frame.size.width = width;
+    self.frame = frame;
+}
+
+- (CGFloat)height {
+    return self.frame.size.height;
+}
+
+- (void)setHeight:(CGFloat)height {
+    CGRect frame = self.frame;
+    frame.size.height = height;
+    self.frame = frame;
+}
+
+- (CGPoint)center {
+    return CGPointMake(self.frame.origin.x + self.frame.size.width * 0.5,
+                       self.frame.origin.y + self.frame.size.height * 0.5);
+}
+
+- (void)setCenter:(CGPoint)center {
+    CGRect frame = self.frame;
+    frame.origin.x = center.x - frame.size.width * 0.5;
+    frame.origin.y = center.y - frame.size.height * 0.5;
+    self.frame = frame;
+}
+
+- (CGFloat)centerX {
+    return self.frame.origin.x + self.frame.size.width * 0.5;
+}
+
+- (void)setCenterX:(CGFloat)centerX {
+    CGRect frame = self.frame;
+    frame.origin.x = centerX - frame.size.width * 0.5;
+    self.frame = frame;
+}
+
+- (CGFloat)centerY {
+    return self.frame.origin.y + self.frame.size.height * 0.5;
+}
+
+- (void)setCenterY:(CGFloat)centerY {
+    CGRect frame = self.frame;
+    frame.origin.y = centerY - frame.size.height * 0.5;
+    self.frame = frame;
+}
+
+- (CGPoint)origin {
+    return self.frame.origin;
+}
+
+- (void)setOrigin:(CGPoint)origin {
+    CGRect frame = self.frame;
+    frame.origin = origin;
+    self.frame = frame;
+}
+
+- (CGSize)frameSize {
+    return self.frame.size;
+}
+
+- (void)setFrameSize:(CGSize)size {
+    CGRect frame = self.frame;
+    frame.size = size;
+    self.frame = frame;
+}
+
+- (CGFloat)transformRotation {
+    NSNumber *v = [self valueForKeyPath:@"transform.rotation"];
+    return v.doubleValue;
+}
+
+- (void)setTransformRotation:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.rotation"];
+}
+
+- (CGFloat)transformRotationX {
+    NSNumber *v = [self valueForKeyPath:@"transform.rotation.x"];
+    return v.doubleValue;
+}
+
+- (void)setTransformRotationX:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.rotation.x"];
+}
+
+- (CGFloat)transformRotationY {
+    NSNumber *v = [self valueForKeyPath:@"transform.rotation.y"];
+    return v.doubleValue;
+}
+
+- (void)setTransformRotationY:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.rotation.y"];
+}
+
+- (CGFloat)transformRotationZ {
+    NSNumber *v = [self valueForKeyPath:@"transform.rotation.z"];
+    return v.doubleValue;
+}
+
+- (void)setTransformRotationZ:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.rotation.z"];
+}
+
+- (CGFloat)transformScaleX {
+    NSNumber *v = [self valueForKeyPath:@"transform.scale.x"];
+    return v.doubleValue;
+}
+
+- (void)setTransformScaleX:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.scale.x"];
+}
+
+- (CGFloat)transformScaleY {
+    NSNumber *v = [self valueForKeyPath:@"transform.scale.y"];
+    return v.doubleValue;
+}
+
+- (void)setTransformScaleY:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.scale.y"];
+}
+
+- (CGFloat)transformScaleZ {
+    NSNumber *v = [self valueForKeyPath:@"transform.scale.z"];
+    return v.doubleValue;
+}
+
+- (void)setTransformScaleZ:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.scale.z"];
+}
+
+- (CGFloat)transformScale {
+    NSNumber *v = [self valueForKeyPath:@"transform.scale"];
+    return v.doubleValue;
+}
+
+- (void)setTransformScale:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.scale"];
+}
+
+- (CGFloat)transformTranslationX {
+    NSNumber *v = [self valueForKeyPath:@"transform.translation.x"];
+    return v.doubleValue;
+}
+
+- (void)setTransformTranslationX:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.translation.x"];
+}
+
+- (CGFloat)transformTranslationY {
+    NSNumber *v = [self valueForKeyPath:@"transform.translation.y"];
+    return v.doubleValue;
+}
+
+- (void)setTransformTranslationY:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.translation.y"];
+}
+
+- (CGFloat)transformTranslationZ {
+    NSNumber *v = [self valueForKeyPath:@"transform.translation.z"];
+    return v.doubleValue;
+}
+
+- (void)setTransformTranslationZ:(CGFloat)v {
+    [self setValue:@(v) forKeyPath:@"transform.translation.z"];
+}
+
+- (CGFloat)transformDepth {
+    return self.transform.m34;
+}
+
+- (void)setTransformDepth:(CGFloat)v {
+    CATransform3D d = self.transform;
+    d.m34 = v;
+    self.transform = d;
+}
+
+- (void)addFadeAnimationWithDuration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve {
+    if (duration <= 0) return;
+    
+    NSString *mediaFunction;
+    switch (curve) {
+        case UIViewAnimationCurveEaseInOut: {
+            mediaFunction = kCAMediaTimingFunctionEaseOut;
+        } break;
+        case UIViewAnimationCurveEaseIn: {
+            mediaFunction = kCAMediaTimingFunctionEaseIn;
+        } break;
+        case UIViewAnimationCurveEaseOut: {
+            mediaFunction = kCAMediaTimingFunctionEaseInEaseOut;
+        } break;
+        case UIViewAnimationCurveLinear: {
+            mediaFunction = kCAMediaTimingFunctionLinear;
+        } break;
+        default: {
+            mediaFunction = kCAMediaTimingFunctionLinear;
+        } break;
+    }
+    
+    CATransition *transition = [CATransition animation];
+    transition.duration = duration;
+    transition.timingFunction = [CAMediaTimingFunction functionWithName:mediaFunction];
+    transition.type = kCATransitionFade;
+    [self addAnimation:transition forKey:@"yykit.fade"];
+}
+
+- (void)removePreviousFadeAnimation {
+    [self removeAnimationForKey:@"yykit.fade"];
+}
+
+@end

BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@3x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@2x.png


BIN
Demo/YYWebImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@3x.png


+ 45 - 0
Demo/YYWebImageDemo/Info.plist

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>NSAppTransportSecurity</key>
+	<dict>
+		<key>NSAllowsArbitraryLoads</key>
+		<true/>
+	</dict>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+	</array>
+</dict>
+</plist>

BIN
Demo/YYWebImageDemo/ResourceTwitter.bundle/fav02l-sheet.png


BIN
Demo/YYWebImageDemo/ResourceTwitter.bundle/fav02l-sheet@2x.png


+ 74 - 0
Demo/YYWebImageDemo/UIControl+YYAdd.h

@@ -0,0 +1,74 @@
+//
+//  UIControl+YYAdd.h
+//  YYKit <https://github.com/ibireme/YYKit>
+//
+//  Created by ibireme on 13/4/5.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ Provides extensions for `UIControl`.
+ */
+@interface UIControl (YYAdd)
+
+/**
+ Removes all targets and actions for a particular event (or events)
+ from an internal dispatch table.
+ */
+- (void)removeAllTargets;
+
+/**
+ Adds or replaces a target and action for a particular event (or events)
+ to an internal dispatch table.
+ 
+ @param target         The target object—that is, the object to which the
+                       action message is sent. If this is nil, the responder
+                       chain is searched for an object willing to respond to the
+                       action message.
+ 
+ @param action         A selector identifying an action message. It cannot be NULL.
+ 
+ @param controlEvents  A bitmask specifying the control events for which the
+                       action message is sent.
+ */
+- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
+
+/**
+ Adds a block for a particular event (or events) to an internal dispatch table.
+ It will cause a strong reference to @a block.
+ 
+ @param block          The block which is invoked then the action message is
+                       sent  (cannot be nil). The block is retained.
+ 
+ @param controlEvents  A bitmask specifying the control events for which the
+                       action message is sent.
+ */
+- (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
+
+/**
+ Adds or replaces a block for a particular event (or events) to an internal
+ dispatch table. It will cause a strong reference to @a block.
+ 
+ @param block          The block which is invoked then the action message is
+                       sent (cannot be nil). The block is retained.
+ 
+ @param controlEvents  A bitmask specifying the control events for which the
+                       action message is sent.
+ */
+- (void)setBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
+
+/**
+ Removes all blocks for a particular event (or events) from an internal
+ dispatch table.
+ 
+ @param controlEvents  A bitmask specifying the control events for which the
+                       action message is sent.
+ */
+- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents;
+
+@end

+ 108 - 0
Demo/YYWebImageDemo/UIControl+YYAdd.m

@@ -0,0 +1,108 @@
+//
+//  UIControl+YYAdd.m
+//  YYKit <https://github.com/ibireme/YYKit>
+//
+//  Created by ibireme on 13/4/5.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import "UIControl+YYAdd.h"
+#import <objc/runtime.h>
+
+
+static const int block_key;
+
+@interface _YYUIControlBlockTarget : NSObject
+
+@property (nonatomic, copy) void (^block)(id sender);
+@property (nonatomic, assign) UIControlEvents events;
+
+- (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events;
+- (void)invoke:(id)sender;
+
+@end
+
+@implementation _YYUIControlBlockTarget
+
+- (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events {
+    self = [super init];
+    if (self) {
+        _block = [block copy];
+        _events = events;
+    }
+    return self;
+}
+
+- (void)invoke:(id)sender {
+    if (_block) _block(sender);
+}
+
+@end
+
+
+
+@implementation UIControl (YYAdd)
+
+- (void)removeAllTargets {
+    [[self allTargets] enumerateObjectsUsingBlock: ^(id object, BOOL *stop) {
+        [self   removeTarget:object
+                      action:NULL
+            forControlEvents:UIControlEventAllEvents];
+    }];
+}
+
+- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {
+    NSSet *targets = [self allTargets];
+    for (id currentTarget in targets) {
+        NSArray *actions = [self actionsForTarget:currentTarget forControlEvent:controlEvents];
+        for (NSString *currentAction in actions) {
+            [self   removeTarget:currentTarget action:NSSelectorFromString(currentAction)
+                forControlEvents:controlEvents];
+        }
+    }
+    [self addTarget:target action:action forControlEvents:controlEvents];
+}
+
+- (void)addBlockForControlEvents:(UIControlEvents)controlEvents
+                           block:(void (^)(id sender))block {
+    _YYUIControlBlockTarget *target = [[_YYUIControlBlockTarget alloc]
+                                       initWithBlock:block events:controlEvents];
+    [self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
+    NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
+    [targets addObject:target];
+}
+
+- (void)setBlockForControlEvents:(UIControlEvents)controlEvents
+                           block:(void (^)(id sender))block {
+    [self removeAllBlocksForControlEvents:controlEvents];
+    [self addBlockForControlEvents:controlEvents block:block];
+}
+
+- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents {
+    NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
+    NSMutableArray *removes = [NSMutableArray array];
+    [targets enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
+        _YYUIControlBlockTarget *target = (_YYUIControlBlockTarget *)obj;
+        if (target.events == controlEvents) {
+            [removes addObject:target];
+            [self   removeTarget:target
+                          action:@selector(invoke:)
+                forControlEvents:controlEvents];
+        }
+    }];
+    [targets removeObjectsInArray:removes];
+}
+
+- (NSMutableArray *)_yy_allUIControlBlockTargets {
+    NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
+    if (!targets) {
+        targets = [NSMutableArray array];
+        objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    }
+    return targets;
+}
+
+@end

+ 43 - 0
Demo/YYWebImageDemo/UIGestureRecognizer+YYAdd.h

@@ -0,0 +1,43 @@
+//
+//  UIGestureRecognizer+YYAdd.h
+//  YYKit <https://github.com/ibireme/YYKit>
+//
+//  Created by ibireme on 13/10/13.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ Provides extensions for `UIGestureRecognizer`.
+ */
+@interface UIGestureRecognizer (YYAdd)
+
+/**
+ Initializes an allocated gesture-recognizer object with a action block.
+ 
+ @param block  An action block that to handle the gesture recognized by the 
+               receiver. nil is invalid. It is retained by the gesture.
+ 
+ @return An initialized instance of a concrete UIGestureRecognizer subclass or 
+         nil if an error occurred in the attempt to initialize the object.
+ */
+- (instancetype)initWithActionBlock:(void (^)(id sender))block;
+
+/**
+ Adds an action block to a gesture-recognizer object. It is retained by the 
+ gesture.
+ 
+ @param block A block invoked by the action message. nil is not a valid value.
+ */
+- (void)addActionBlock:(void (^)(id sender))block;
+
+/**
+ Remove all action blocks.
+ */
+- (void)removeAllActionBlocks;
+
+@end

+ 77 - 0
Demo/YYWebImageDemo/UIGestureRecognizer+YYAdd.m

@@ -0,0 +1,77 @@
+//
+//  UIGestureRecognizer+YYAdd.m
+//  YYKit <https://github.com/ibireme/YYKit>
+//
+//  Created by ibireme on 13/10/13.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import "UIGestureRecognizer+YYAdd.h"
+#import <objc/runtime.h>
+
+static const int block_key;
+
+@interface _YYUIGestureRecognizerBlockTarget : NSObject
+
+@property (nonatomic, copy) void (^block)(id sender);
+
+- (id)initWithBlock:(void (^)(id sender))block;
+- (void)invoke:(id)sender;
+
+@end
+
+@implementation _YYUIGestureRecognizerBlockTarget
+
+- (id)initWithBlock:(void (^)(id sender))block{
+    self = [super init];
+    if (self) {
+        _block = [block copy];
+    }
+    return self;
+}
+
+- (void)invoke:(id)sender {
+    if (_block) _block(sender);
+}
+
+@end
+
+
+
+
+@implementation UIGestureRecognizer (YYAdd)
+
+- (instancetype)initWithActionBlock:(void (^)(id sender))block {
+    self = [self init];
+    [self addActionBlock:block];
+    return self;
+}
+
+- (void)addActionBlock:(void (^)(id sender))block {
+    _YYUIGestureRecognizerBlockTarget *target = [[_YYUIGestureRecognizerBlockTarget alloc] initWithBlock:block];
+    [self addTarget:target action:@selector(invoke:)];
+    NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
+    [targets addObject:target];
+}
+
+- (void)removeAllActionBlocks{
+    NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets];
+    [targets enumerateObjectsUsingBlock:^(id target, NSUInteger idx, BOOL *stop) {
+        [self removeTarget:target action:@selector(invoke:)];
+    }];
+    [targets removeAllObjects];
+}
+
+- (NSMutableArray *)_yy_allUIGestureRecognizerBlockTargets {
+    NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
+    if (!targets) {
+        targets = [NSMutableArray array];
+        objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    }
+    return targets;
+}
+
+@end

+ 51 - 0
Demo/YYWebImageDemo/UIView+YYAdd.h

@@ -0,0 +1,51 @@
+//
+//  UIView+YYAdd.h
+//  YYCategories <https://github.com/ibireme/YYCategories>
+//
+//  Created by ibireme on 13/4/3.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import <UIKit/UIKit.h>
+
+/**
+ Provides extensions for `UIView`.
+ */
+@interface UIView (YYAdd)
+
+/**
+ Shortcut to set the view.layer's shadow
+ 
+ @param color  Shadow Color
+ @param offset Shadow offset
+ @param radius Shadow radius
+ */
+- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
+
+/**
+ Remove all subviews.
+ 
+ @warning Never call this method inside your view's drawRect: method.
+ */
+- (void)removeAllSubviews;
+
+/**
+ Returns the view's view controller (may be nil).
+ */
+@property (nonatomic, readonly) UIViewController *viewController;
+
+@property (nonatomic) CGFloat left;        ///< Shortcut for frame.origin.x.
+@property (nonatomic) CGFloat top;         ///< Shortcut for frame.origin.y
+@property (nonatomic) CGFloat right;       ///< Shortcut for frame.origin.x + frame.size.width
+@property (nonatomic) CGFloat bottom;      ///< Shortcut for frame.origin.y + frame.size.height
+@property (nonatomic) CGFloat width;       ///< Shortcut for frame.size.width.
+@property (nonatomic) CGFloat height;      ///< Shortcut for frame.size.height.
+@property (nonatomic) CGFloat centerX;     ///< Shortcut for center.x
+@property (nonatomic) CGFloat centerY;     ///< Shortcut for center.y
+@property (nonatomic) CGPoint origin;      ///< Shortcut for frame.origin.
+@property (nonatomic) CGSize  size;        ///< Shortcut for frame.size.
+
+@end

+ 139 - 0
Demo/YYWebImageDemo/UIView+YYAdd.m

@@ -0,0 +1,139 @@
+//
+//  UIView+YYAdd.m
+//  YYCategories <https://github.com/ibireme/YYCategories>
+//
+//  Created by ibireme on 13/4/3.
+//  Copyright (c) 2015 ibireme.
+//
+//  This source code is licensed under the MIT-style license found in the
+//  LICENSE file in the root directory of this source tree.
+//
+
+#import "UIView+YYAdd.h"
+#import <QuartzCore/QuartzCore.h>
+
+@implementation UIView (YYAdd)
+
+- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius {
+    self.layer.shadowColor = color.CGColor;
+    self.layer.shadowOffset = offset;
+    self.layer.shadowRadius = radius;
+    self.layer.shadowOpacity = 1;
+    self.layer.shouldRasterize = YES;
+    self.layer.rasterizationScale = [UIScreen mainScreen].scale;
+}
+
+- (void)removeAllSubviews {
+    //[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
+    while (self.subviews.count) {
+        [self.subviews.lastObject removeFromSuperview];
+    }
+}
+
+- (UIViewController *)viewController {
+    for (UIView *view = self; view; view = view.superview) {
+        UIResponder *nextResponder = [view nextResponder];
+        if ([nextResponder isKindOfClass:[UIViewController class]]) {
+            return (UIViewController *)nextResponder;
+        }
+    }
+    return nil;
+}
+
+- (CGFloat)left {
+    return self.frame.origin.x;
+}
+
+- (void)setLeft:(CGFloat)x {
+    CGRect frame = self.frame;
+    frame.origin.x = x;
+    self.frame = frame;
+}
+
+- (CGFloat)top {
+    return self.frame.origin.y;
+}
+
+- (void)setTop:(CGFloat)y {
+    CGRect frame = self.frame;
+    frame.origin.y = y;
+    self.frame = frame;
+}
+
+- (CGFloat)right {
+    return self.frame.origin.x + self.frame.size.width;
+}
+
+- (void)setRight:(CGFloat)right {
+    CGRect frame = self.frame;
+    frame.origin.x = right - frame.size.width;
+    self.frame = frame;
+}
+
+- (CGFloat)bottom {
+    return self.frame.origin.y + self.frame.size.height;
+}
+
+- (void)setBottom:(CGFloat)bottom {
+    CGRect frame = self.frame;
+    frame.origin.y = bottom - frame.size.height;
+    self.frame = frame;
+}
+
+- (CGFloat)width {
+    return self.frame.size.width;
+}
+
+- (void)setWidth:(CGFloat)width {
+    CGRect frame = self.frame;
+    frame.size.width = width;
+    self.frame = frame;
+}
+
+- (CGFloat)height {
+    return self.frame.size.height;
+}
+
+- (void)setHeight:(CGFloat)height {
+    CGRect frame = self.frame;
+    frame.size.height = height;
+    self.frame = frame;
+}
+
+- (CGFloat)centerX {
+    return self.center.x;
+}
+
+- (void)setCenterX:(CGFloat)centerX {
+    self.center = CGPointMake(centerX, self.center.y);
+}
+
+- (CGFloat)centerY {
+    return self.center.y;
+}
+
+- (void)setCenterY:(CGFloat)centerY {
+    self.center = CGPointMake(self.center.x, centerY);
+}
+
+- (CGPoint)origin {
+    return self.frame.origin;
+}
+
+- (void)setOrigin:(CGPoint)origin {
+    CGRect frame = self.frame;
+    frame.origin = origin;
+    self.frame = frame;
+}
+
+- (CGSize)size {
+    return self.frame.size;
+}
+
+- (void)setSize:(CGSize)size {
+    CGRect frame = self.frame;
+    frame.size = size;
+    self.frame = frame;
+}
+
+@end

+ 15 - 0
Demo/YYWebImageDemo/ViewController.h

@@ -0,0 +1,15 @@
+//
+//  ViewController.h
+//  YYWebImageDemo
+//
+//  Created by guoyaoyuan on 15/10/30.
+//  Copyright © 2015年 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UINavigationController
+
+
+@end
+

+ 24 - 0
Demo/YYWebImageDemo/ViewController.m

@@ -0,0 +1,24 @@
+//
+//  ViewController.m
+//  YYWebImageDemo
+//
+//  Created by guoyaoyuan on 15/10/30.
+//  Copyright © 2015年 ibireme. All rights reserved.
+//
+
+#import "ViewController.h"
+#import "YYImageExample.h"
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    YYImageExample *vc = [YYImageExample new];
+    [self pushViewController:vc animated:NO];
+}
+
+@end

+ 41 - 0
Demo/YYWebImageDemo/YYBPGCoder.h

@@ -0,0 +1,41 @@
+//
+//  YYBPGCoder.h
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/13.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import <YYKit/YYKit.h>
+
+/*
+ BPG image format:
+ http://bellard.org/bpg/
+ */
+
+/**
+ Decode BPG data
+ @param bpgData  BPG image data.
+ @param decodeForDisplay  YES: returns a premultiply BRGA format image, NO: returns an ARGB format image.
+ @return A new image, or NULL if an error occurs.
+ */
+CG_EXTERN CGImageRef YYCGImageCreateWithBPGData(CFDataRef bpgData, BOOL decodeForDisplay);
+
+/**
+ Decode a frame from BPG image data, returns NULL if an error occurs.
+ @warning This method should only be used for benchmark.
+ */
+CG_EXTERN CGImageRef YYCGImageCreateFrameWithBPGData(CFDataRef bpgData, NSUInteger frameIndex, BOOL decodeForDisplay);
+
+/**
+ Decode all frames in BPG image data, returns NULL if an error occurs.
+ @warning This method should only be used for benchmark.
+ */
+CG_EXTERN void YYCGImageDecodeAllFrameInBPGData(CFDataRef bpgData, BOOL decodeForDisplay);
+
+/**
+ Whether data is bpg.
+ */
+CG_EXTERN BOOL YYImageIsBPGData(CFDataRef data);
+
+

+ 272 - 0
Demo/YYWebImageDemo/YYBPGCoder.m

@@ -0,0 +1,272 @@
+//
+//  YYBPGCoder.m
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/13.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import "YYBPGCoder.h"
+#import <ImageIO/ImageIO.h>
+#import <Accelerate/Accelerate.h>
+#import <bpg/libbpg.h>
+
+#define YY_FOUR_CC(c1,c2,c3,c4) ((uint32_t)(((c4) << 24) | ((c3) << 16) | ((c2) << 8) | (c1)))
+
+/// Returns byte-aligned size.
+static inline size_t _YYImageByteAlign(size_t size, size_t alignment) {
+    return ((size + (alignment - 1)) / alignment) * alignment;
+}
+
+/**
+ A callback used in CGDataProviderCreateWithData() to release data.
+ 
+ Example:
+ 
+ void *data = malloc(size);
+ CGDataProviderRef provider = CGDataProviderCreateWithData(data, data, size, YYCGDataProviderReleaseDataCallback);
+ */
+static void _YYCGDataProviderReleaseDataCallback(void *info, const void *data, size_t size) {
+    free(info);
+}
+
+CGImageRef YYCGImageCreateWithBPGData(CFDataRef bpgData, BOOL decodeForDisplay) {
+    BPGDecoderContext *decoderContext = NULL;
+    BPGImageInfo imageInfo = {0};
+    size_t width, height, lineSize, stride, size;
+    uint8_t *rgbaLine = NULL, *rgbaBuffer = NULL;
+    CGDataProviderRef dataProvider = NULL;
+    CGImageRef cgImage = NULL;
+    CGBitmapInfo bitmapInfo;
+    
+    if (!bpgData || CFDataGetLength(bpgData) == 0) return NULL;
+    decoderContext = bpg_decoder_open();
+    if (!decoderContext) return NULL;
+    if (bpg_decoder_decode(decoderContext, CFDataGetBytePtr(bpgData), (int)CFDataGetLength(bpgData)) < 0) goto fail;
+    if (bpg_decoder_get_info(decoderContext, &imageInfo) < 0) goto fail;
+    
+    width = imageInfo.width;
+    height = imageInfo.height;
+    lineSize = 4 * width;
+    stride = _YYImageByteAlign(lineSize, 32);
+    size = stride * height;
+    
+    if (width == 0 || height == 0) goto fail;
+    rgbaLine = malloc(lineSize);
+    if (!rgbaLine) goto fail;
+    rgbaBuffer = malloc(size);
+    if (!rgbaBuffer) goto fail;
+    if (bpg_decoder_start(decoderContext, BPG_OUTPUT_FORMAT_RGBA32) < 0) goto fail;
+    
+    for (int y = 0; y < height; y++) {
+        if (bpg_decoder_get_line(decoderContext, rgbaLine) < 0) goto fail;
+        memcpy(rgbaBuffer + (y * stride), rgbaLine, lineSize);
+    }
+    free(rgbaLine);
+    rgbaLine = NULL;
+    bpg_decoder_close(decoderContext);
+    decoderContext = NULL;
+    
+    if (decodeForDisplay) {
+        vImage_Buffer src;
+        src.data = rgbaBuffer;
+        src.width = width;
+        src.height = height;
+        src.rowBytes = stride;
+        vImage_Error error;
+        
+        // premultiply RGBA
+        error = vImagePremultiplyData_RGBA8888(&src, &src, kvImageNoFlags);
+        if (error != kvImageNoError) goto fail;
+        
+        // convert to bgrA
+        uint8_t map[4] = {2,1,0,3};
+        error = vImagePermuteChannels_ARGB8888(&src, &src, map, kvImageNoFlags);
+        if (error != kvImageNoError) goto fail;
+        bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+    } else {
+        bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrderDefault;
+    }
+    
+    dataProvider = CGDataProviderCreateWithData(rgbaBuffer, rgbaBuffer, size, _YYCGDataProviderReleaseDataCallback);
+    if (!dataProvider) goto fail;
+    rgbaBuffer = NULL; // hold by provider
+    cgImage = CGImageCreate(width, height, 8, 32, stride, YYCGColorSpaceGetDeviceRGB(),
+                            bitmapInfo, dataProvider, NULL, NO,
+                            kCGRenderingIntentDefault);
+    
+    CGDataProviderRelease(dataProvider);
+    return cgImage;
+    
+fail:
+    if (decoderContext) bpg_decoder_close(decoderContext);
+    if (rgbaLine) free(rgbaLine);
+    if (rgbaBuffer) free(rgbaBuffer);
+    return NULL;
+}
+
+
+CGImageRef YYCGImageCreateFrameWithBPGData(CFDataRef bpgData, NSUInteger frameIndex, BOOL decodeForDisplay) {
+    BPGDecoderContext *decoderContext = NULL;
+    BPGImageInfo imageInfo = {0};
+    size_t width, height, lineSize, stride, size;
+    uint8_t *rgbaLine = NULL, *rgbaBuffer = NULL;
+    CGDataProviderRef dataProvider = NULL;
+    CGImageRef cgImage = NULL;
+    CGBitmapInfo bitmapInfo;
+    
+    if (!bpgData || CFDataGetLength(bpgData) == 0) return NULL;
+    decoderContext = bpg_decoder_open();
+    if (!decoderContext) return NULL;
+    if (bpg_decoder_decode(decoderContext, CFDataGetBytePtr(bpgData), (int)CFDataGetLength(bpgData)) < 0) goto fail;
+    if (bpg_decoder_get_info(decoderContext, &imageInfo) < 0) goto fail;
+    
+    width = imageInfo.width;
+    height = imageInfo.height;
+    lineSize = 4 * width;
+    stride = _YYImageByteAlign(lineSize, 32);
+    size = stride * height;
+    
+    if (width == 0 || height == 0) goto fail;
+    rgbaLine = malloc(lineSize);
+    if (!rgbaLine) goto fail;
+    rgbaBuffer = malloc(size);
+    if (!rgbaBuffer) goto fail;
+    
+    for (NSUInteger i = 0; i <= frameIndex; i++) {
+        if (bpg_decoder_start(decoderContext, BPG_OUTPUT_FORMAT_RGBA32) < 0) goto fail;
+    }
+    
+    for (int y = 0; y < height; y++) {
+        if (bpg_decoder_get_line(decoderContext, rgbaLine) < 0) goto fail;
+        memcpy(rgbaBuffer + (y * stride), rgbaLine, lineSize);
+    }
+    free(rgbaLine);
+    rgbaLine = NULL;
+    bpg_decoder_close(decoderContext);
+    decoderContext = NULL;
+    
+    if (decodeForDisplay) {
+        vImage_Buffer src;
+        src.data = rgbaBuffer;
+        src.width = width;
+        src.height = height;
+        src.rowBytes = stride;
+        vImage_Error error;
+        
+        // premultiply RGBA
+        error = vImagePremultiplyData_RGBA8888(&src, &src, kvImageNoFlags);
+        if (error != kvImageNoError) goto fail;
+        
+        // convert to BGRA
+        uint8_t map[4] = {2,1,0,3};
+        error = vImagePermuteChannels_ARGB8888(&src, &src, map, kvImageNoFlags);
+        if (error != kvImageNoError) goto fail;
+        bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+    } else {
+        bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrderDefault;
+    }
+    
+    dataProvider = CGDataProviderCreateWithData(rgbaBuffer, rgbaBuffer, size, _YYCGDataProviderReleaseDataCallback);
+    if (!dataProvider) goto fail;
+    rgbaBuffer = NULL; // hold by provider
+    cgImage = CGImageCreate(width, height, 8, 32, stride, YYCGColorSpaceGetDeviceRGB(),
+                            bitmapInfo, dataProvider, NULL, NO,
+                            kCGRenderingIntentDefault);
+    
+    CGDataProviderRelease(dataProvider);
+    return cgImage;
+    
+fail:
+    if (decoderContext) bpg_decoder_close(decoderContext);
+    if (rgbaLine) free(rgbaLine);
+    if (rgbaBuffer) free(rgbaBuffer);
+    return NULL;
+}
+
+
+void YYCGImageDecodeAllFrameInBPGData(CFDataRef bpgData, BOOL decodeForDisplay) {
+    BPGDecoderContext *decoderContext = NULL;
+    BPGImageInfo imageInfo = {0};
+    size_t width, height, lineSize, stride, size;
+    uint8_t *rgbaLine = NULL, *rgbaBuffer = NULL;
+    CGDataProviderRef dataProvider = NULL;
+    CGImageRef cgImage = NULL;
+    CGBitmapInfo bitmapInfo;
+    
+    if (!bpgData || CFDataGetLength(bpgData) == 0) return;
+    decoderContext = bpg_decoder_open();
+    if (!decoderContext) return;
+    if (bpg_decoder_decode(decoderContext, CFDataGetBytePtr(bpgData), (int)CFDataGetLength(bpgData)) < 0) goto end;
+    if (bpg_decoder_get_info(decoderContext, &imageInfo) < 0) goto end;
+    
+    width = imageInfo.width;
+    height = imageInfo.height;
+    lineSize = 4 * width;
+    stride = _YYImageByteAlign(lineSize, 32);
+    size = stride * height;
+    
+    
+    for (;;) {
+        if (bpg_decoder_start(decoderContext, BPG_OUTPUT_FORMAT_RGBA32) < 0) goto end;
+        
+        if (width == 0 || height == 0) goto end;
+        rgbaLine = malloc(lineSize);
+        if (!rgbaLine) goto end;
+        rgbaBuffer = malloc(size);
+        if (!rgbaBuffer) goto end;
+        
+        for (int y = 0; y < height; y++) {
+            if (bpg_decoder_get_line(decoderContext, rgbaLine) < 0) goto end;
+            memcpy(rgbaBuffer + (y * stride), rgbaLine, lineSize);
+        }
+        free(rgbaLine);
+        rgbaLine = NULL;
+        
+        if (decodeForDisplay) {
+            vImage_Buffer src;
+            src.data = rgbaBuffer;
+            src.width = width;
+            src.height = height;
+            src.rowBytes = stride;
+            vImage_Error error;
+            
+            // premultiply RGBA
+            error = vImagePremultiplyData_RGBA8888(&src, &src, kvImageNoFlags);
+            if (error != kvImageNoError) goto end;
+            
+            // convert to BGRA
+            uint8_t map[4] = {2,1,0,3};
+            error = vImagePermuteChannels_ARGB8888(&src, &src, map, kvImageNoFlags);
+            if (error != kvImageNoError) goto end;
+            bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+        } else {
+            bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrderDefault;
+        }
+        
+        dataProvider = CGDataProviderCreateWithData(rgbaBuffer, rgbaBuffer, size, _YYCGDataProviderReleaseDataCallback);
+        if (!dataProvider) goto end;
+        rgbaBuffer = NULL; // hold by provider
+        cgImage = CGImageCreate(width, height, 8, 32, stride, YYCGColorSpaceGetDeviceRGB(),
+                                bitmapInfo, dataProvider, NULL, NO,
+                                kCGRenderingIntentDefault);
+        
+        CGDataProviderRelease(dataProvider);
+        if (cgImage) CFRelease(cgImage);
+    }
+    return;
+    
+end:
+    if (decoderContext) bpg_decoder_close(decoderContext);
+    if (rgbaLine) free(rgbaLine);
+    if (rgbaBuffer) free(rgbaBuffer);
+    return;
+}
+
+
+BOOL YYImageIsBPGData(CFDataRef data) {
+    if (!data || CFDataGetLength(data) < 8) return NO;
+    const uint8_t *bytes = CFDataGetBytePtr(data);
+    uint32_t magic = *((uint32_t *)bytes);
+    return magic == YY_FOUR_CC('B', 'P', 'G', 0xFB);
+}

+ 13 - 0
Demo/YYWebImageDemo/YYImageBenchmark.h

@@ -0,0 +1,13 @@
+//
+//  YYImageProfileExample.h
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/10.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface YYImageBenchmark : UITableViewController
+
+@end

+ 742 - 0
Demo/YYWebImageDemo/YYImageBenchmark.m

@@ -0,0 +1,742 @@
+//
+//  YYImageProfileExample.m
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/10.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import "YYImageBenchmark.h"
+#import <YYKit/YYKit.h>
+#import <ImageIO/ImageIO.h>
+#import <MobileCoreServices/MobileCoreServices.h>
+#import "YYBPGCoder.h"
+
+/*
+ Enable this value and run in simulator, the image will write to desktop.
+ Then you can view this image with preview.
+ */
+#define ENABLE_OUTPUT 0
+#define IMAGE_OUTPUT_DIR @"/Users/ibireme/Desktop/image_out/"
+
+
+
+@implementation YYImageBenchmark {
+    UIActivityIndicatorView *_indicator;
+    UIView *_hud;
+    NSMutableArray *_titles;
+    NSMutableArray *_blocks;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    [self initHUD];
+    _titles = [NSMutableArray new];
+    _blocks = [NSMutableArray new];
+    self.title = @"Benchmark (See Logs in Xcode)";
+    
+    [self addCell:@"ImageIO Image Decode" selector:@selector(runImageDecodeBenchmark)];
+    [self addCell:@"ImageIO Image Encode" selector:@selector(runImageEncodeBenchmark)];
+    [self addCell:@"WebP Encode and Decode (Slow)" selector:@selector(runWebPBenchmark)];
+    [self addCell:@"BPG Decode" selector:@selector(runBPGBenchmark)];
+    [self addCell:@"Animated Image Decode" selector:@selector(runAnimatedImageBenchmark)];
+    
+    [self.tableView reloadData];
+}
+
+- (void)addCell:(NSString *)title selector:(SEL)sel {
+    __weak typeof(self) _self = self;
+    void (^block)(void) = ^() {
+        if (![_self respondsToSelector:sel]) return;
+        
+        [_self startHUD];
+        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+            [_self performSelector:sel];
+#pragma clang diagnostic pop
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [_self stopHUD];
+            });
+        });
+    };
+    [_titles addObject:title];
+    [_blocks addObject:block];
+}
+
+- (void)dealloc {
+    [_hud removeFromSuperview];
+}
+
+- (void)initHUD {
+    _hud = [UIView new];
+    _hud.size = CGSizeMake(130, 80);
+    _hud.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.7];
+    _hud.clipsToBounds = YES;
+    _hud.layer.cornerRadius = 5;
+    
+    _indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+    _indicator.size = CGSizeMake(50, 50);
+    _indicator.centerX = _hud.width / 2;
+    _indicator.centerY = _hud.height / 2 - 9;
+    [_hud addSubview:_indicator];
+    
+    UILabel *label = [UILabel new];
+    label.textAlignment = NSTextAlignmentCenter;
+    label.size = CGSizeMake(_hud.width, 20);
+    label.text = @"See logs in Xcode";
+    label.font = [UIFont systemFontOfSize:12];
+    label.textColor = [UIColor whiteColor];
+    label.centerX = _hud.width / 2;
+    label.bottom = _hud.height - 8;
+    [_hud addSubview:label];
+}
+
+- (void)startHUD {
+    UIWindow *window = [[UIApplication sharedApplication].windows firstObject];
+    _hud.center = CGPointMake(window.width / 2, window.height / 2);
+    [_indicator startAnimating];
+    
+    [window addSubview:_hud];
+    self.navigationController.view.userInteractionEnabled = NO;
+}
+
+- (void)stopHUD {
+    [_indicator stopAnimating];
+    [_hud removeFromSuperview];
+    self.navigationController.view.userInteractionEnabled = YES;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    [tableView deselectRowAtIndexPath:indexPath animated:YES];
+    ((void (^)(void))_blocks[indexPath.row])();
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return _titles.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YY"];
+    if (!cell) {
+        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"YY"];
+    }
+    cell.textLabel.text = _titles[indexPath.row];
+    return cell;
+}
+
+#pragma mark - Benchmark
+
+- (NSArray *)imageNames {
+    return @[ @"dribbble", @"lena" ];
+}
+
+- (NSArray *)imageSizes {
+    return @[  @64, @128, @256, @512 ];
+}
+
+- (NSArray *)imageSources {
+    return @[ @"imageio", @"photoshop", @"imageoptim", @"pngcrush", @"tinypng", @"twitter", @"weibo", @"facebook" ];
+}
+
+- (NSArray *)imageTypes {
+    return @[ (id)kUTTypeJPEG, (id)kUTTypeJPEG2000, (id)kUTTypeTIFF, (id)kUTTypeGIF, (id)kUTTypePNG, (id)kUTTypeBMP ];
+}
+
+- (NSString *)imageTypeGetExt:(id)type {
+    static NSDictionary *map;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        map = @{(id)kUTTypeJPEG : @"jpg",
+                (id)kUTTypeJPEG2000 : @"jp2",
+                (id)kUTTypeTIFF : @"tif",
+                (id)kUTTypeGIF : @"gif",
+                (id)kUTTypePNG : @"png",
+                (id)kUTTypeBMP : @"bmp"};
+    });
+    return type ? map[type] : nil;
+}
+
+- (NSArray *)imageTypeGetQuality:(NSString *)type {
+    BOOL hasQuality = [type isEqualToString:(id)kUTTypeJPEG] || [type isEqualToString:(id)kUTTypeJPEG2000] || [type isEqualToString:@"webp"];
+    return hasQuality ? @[@1.0, @0.95, @0.9, @0.85, @0.8, @0.75, @0.7, @0.6, @0.5, @0.4, @0.3, @0.2, @0.1, @0] : @[@1.0];
+}
+
+- (void)runImageDecodeBenchmark {
+    printf("==========================================\n");
+    printf("ImageIO Decode Benchmark\n");
+    printf("name    size type quality length decode_time\n");
+    
+    for (NSString *imageName in self.imageNames) {
+        for (NSNumber *imageSize in self.imageSizes) {
+            for (NSString *imageSource in self.imageSources) {
+                for (NSString *imageType in @[@"png", @"jpg"]) {
+                    @autoreleasepool {
+                        NSString *fileName = [NSString stringWithFormat:@"%@%@_%@",imageName, imageSize, imageSource];
+                        NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:imageType];
+                        NSData *data = filePath ? [NSData dataWithContentsOfFile:filePath] : nil;
+                        if (!data) continue;
+                        int count = 100;
+                        YYBenchmark(^{
+                            for (int i = 0; i < count; i++) {
+                                CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)data, NULL);
+                                CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache:@(NO)});
+                                CGImageRef decoded = YYCGImageCreateDecodedCopy(image, YES);
+                                CFRelease(decoded);
+                                CFRelease(image);
+                                CFRelease(source);
+                            }
+                        }, ^(double ms) {
+                            printf("%8s %3d %3s %10s %6d %2.3f\n", imageName.UTF8String, imageSize.intValue, imageType.UTF8String, imageSource.UTF8String, (int)data.length, ms / count);
+                        });
+                        
+#if ENABLE_OUTPUT
+                        if ([UIDevice currentDevice].isSimulator) {
+                            NSString *outFilePath = [NSString stringWithFormat:@"%@%@.%@", IMAGE_OUTPUT_DIR, fileName, imageType];
+                            [data writeToFile:outFilePath atomically:YES];
+                        }
+#endif
+                    }
+                }
+            }
+        }
+    }
+    
+    printf("------------------------------------------\n\n");
+}
+
+- (void)runImageEncodeBenchmark {
+    printf("==========================================\n");
+    printf("ImageIO Encode Benchmark\n");
+    printf("name    size type quality length encode decode\n");
+    
+    for (NSString *imageName in self.imageNames) {
+        for (NSNumber *imageSize in self.imageSizes) {
+            NSString *fileName = [NSString stringWithFormat:@"%@%@_imageio",imageName, imageSize];
+            NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"png"];
+            NSData *data = filePath ? [NSData dataWithContentsOfFile:filePath] : nil;
+            CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)data, NULL);
+            CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache:@(NO)});
+            CGImageRef decoded = YYCGImageCreateDecodedCopy(image, YES);
+            
+            for (NSString *uti in [self imageTypes]) {
+                for (NSNumber *quality in [self imageTypeGetQuality:uti]) {
+                    __block int encodeCount = 0;
+                    __block double encodeTime = 0;
+                    __block long length = 0;
+                    __block CFMutableDataRef outData = NULL;
+                    __block int decodeCount = 0;
+                    __block double decodeTime = 0;
+                    
+                    while (encodeTime < 200) { //200ms
+                        YYBenchmark(^{
+                            if (outData) CFRelease(outData);
+                            outData = CFDataCreateMutable(CFAllocatorGetDefault(), 0);
+                            CGImageDestinationRef dest = CGImageDestinationCreateWithData(outData, (CFStringRef)uti, 1, NULL);
+                            NSDictionary *options = @{(id)kCGImageDestinationLossyCompressionQuality : quality };
+                            CGImageDestinationAddImage(dest, decoded, (CFDictionaryRef)options);
+                            CGImageDestinationFinalize(dest);
+                            length = CFDataGetLength(outData);
+                            CFRelease(dest);
+                        }, ^(double ms) {
+                            encodeTime += ms;
+                            encodeCount += 1;
+                        });
+                    }
+                    
+#if ENABLE_OUTPUT
+                    if ([UIDevice currentDevice].isSimulator) {
+                        NSString *outFilePath = [NSString stringWithFormat:@"%@%@%@_%.2f.%@", IMAGE_OUTPUT_DIR, imageName, imageSize, quality.floatValue, [self imageTypeGetExt:uti]];
+                        [((__bridge NSData *)outData) writeToFile:outFilePath atomically:YES];
+                    }
+#endif
+                    
+                    decodeCount = 100;
+                    YYBenchmark(^{
+                        for (int i = 0; i < decodeCount; i++) {
+                            CGImageSourceRef source = CGImageSourceCreateWithData(outData, NULL);
+                            CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache:@(NO)});
+                            CGImageRef decoded = YYCGImageCreateDecodedCopy(image, NO);
+                            CFRelease(decoded);
+                            CFRelease(image);
+                            CFRelease(source);
+                        }
+                    }, ^(double ms) {
+                        decodeTime = ms;
+                    });
+                    CFRelease(outData);
+                    
+                    printf("%8s %3d %3s  %.2f  %7d  %7.3f %7.3f\n",imageName.UTF8String, imageSize.intValue, [self imageTypeGetExt:uti].UTF8String, quality.floatValue, (int)length, encodeTime / encodeCount, decodeTime / decodeCount);
+                    
+                }
+            }
+            
+            CFRelease(decoded);
+            CFRelease(image);
+            CFRelease(source);
+        }
+    }
+    
+    printf("------------------------------------------\n\n");
+}
+
+- (void)runWebPBenchmark {
+    printf("==========================================\n");
+    printf("WebP Benchmark\n");
+    printf("name size  type  quality method length encode   decode\n");
+
+    for (NSString *imageName in self.imageNames) {
+        for (NSNumber *imageSize in self.imageSizes) {
+            NSString *fileName = [NSString stringWithFormat:@"%@%@_imageio", imageName, imageSize];
+            NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"png"];
+            NSData *data = filePath ? [NSData dataWithContentsOfFile:filePath] : nil;
+            CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)data, NULL);
+            CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache : @(NO) });
+            CGImageRef decoded = YYCGImageCreateDecodedCopy(image, YES);
+            
+            for (NSNumber *lossless in @[ @YES, @NO ]) {
+                for (NSNumber *q in [self imageTypeGetQuality:@"webp"]) {
+                    for (NSNumber *m in @[ @0, @1, @2, @3, @4, @5, @6 ]) {
+                        @autoreleasepool {
+                            __block int encodeCount = 0;
+                            __block double encodeTime = 0;
+                            __block long length = 0;
+                            __block CFDataRef webpData = NULL;
+                            int decodeCount = 100;
+                            double decodeTime[8] = {0};  // useThreads,bypassFiltering,noFancyUpsampling 0,0,0; 0,0,1; 0,1,0; 0,1,1; 1,0,0; 1,0,1; 1,1,0; 1,1,1
+                            
+                            while (encodeTime < 200) {  // 200ms
+                                YYBenchmark( ^{
+                                      if (webpData) CFRelease(webpData);
+                                      webpData = YYCGImageCreateEncodedWebPData(decoded, lossless.boolValue, q.floatValue, m.intValue, YYImagePresetDefault);
+                                      length = CFDataGetLength(webpData);
+                                    }, ^(double ms) {
+                                      encodeTime += ms;
+                                      encodeCount += 1;
+                                    });
+                            }
+#if ENABLE_OUTPUT
+                            if ([UIDevice currentDevice].isSimulator) {
+                                NSString *outFilePath = [NSString
+                                    stringWithFormat:@"%@%@%@_%@_q%.2f_m%d.webp", IMAGE_OUTPUT_DIR, imageName, imageSize,
+                                                     lossless.boolValue ? @"lossless" : @"lossy", q.floatValue, m.intValue];
+                                [((__bridge NSData *)webpData)writeToFile:outFilePath atomically:YES];
+                                
+                                CGImageRef image = YYCGImageCreateWithWebPData(webpData, NO, NO, NO, NO);
+                                NSData *pngData = UIImagePNGRepresentation([UIImage imageWithCGImage:image]);
+                                NSString *pngOutFilePath = [NSString
+                                                         stringWithFormat:@"%@%@%@_%@_q%.2f_m%d.webp.png", IMAGE_OUTPUT_DIR, imageName, imageSize,
+                                                         lossless.boolValue ? @"lossless" : @"lossy", q.floatValue, m.intValue];
+                                [pngData writeToFile:pngOutFilePath atomically:YES];
+                                CFRelease(image);
+                            }
+#endif
+
+                            for (NSNumber *useThreads in @[ @NO, @YES ]) {
+                                for (NSNumber *bypassFiltering in @[ @NO, @YES ]) {
+                                    for (NSNumber *noFancyUpsampling in @[ @NO, @YES ]) {
+                                        __block double time = 0;
+                                        YYBenchmark(^{
+                                              for (int i = 0; i < decodeCount; i++) {
+                                                  CGImageRef image = YYCGImageCreateWithWebPData(webpData, YES, useThreads.boolValue, bypassFiltering.boolValue,noFancyUpsampling.boolValue);
+                                                  CFRelease(image);
+                                              }
+                                            }, ^(double ms) {
+                                              time = ms;
+                                            });
+                                        decodeTime[useThreads.intValue << 2 | bypassFiltering.intValue << 1 |
+                                                   noFancyUpsampling.intValue] = time;
+                                    }
+                                }
+                            }
+                            if (webpData) CFRelease(webpData);
+                            
+                            printf("%8s %3d %.8s %.2f  %1d %7d %9.3f  %7.3f %7.3f %7.3f %7.3f %7.3f %7.3f %7.3f %7.3f\n",
+                                   imageName.UTF8String, imageSize.intValue, lossless.boolValue ? "lossless" : "lossy",
+                                   q.floatValue, m.intValue, (int)length, encodeTime / encodeCount, decodeTime[0] / decodeCount,
+                                   decodeTime[1] / decodeCount, decodeTime[2] / decodeCount, decodeTime[3] / decodeCount,
+                                   decodeTime[4] / decodeCount, decodeTime[5] / decodeCount, decodeTime[6] / decodeCount,
+                                   decodeTime[7] / decodeCount);
+                        }
+                    }
+                }
+            }
+
+            CFRelease(decoded);
+            CFRelease(image);
+            CFRelease(source);
+        }
+    }
+
+    printf("------------------------------------------\n\n");
+}
+
+- (void)runBPGBenchmark {
+    printf("==========================================\n");
+    printf("BPG Decode Benchmark\n");
+    printf("name    size  quality length decode_time\n");
+    
+    for (NSString *imageName in self.imageNames) {
+        for (NSNumber *imageSize in self.imageSizes) {
+            for (NSString *quality in @[ @"lossless",@"q0",@"q5",@"q10",@"q15",@"q20",@"q25",@"q30",@"q35",@"q40",@"q45",@"q50"]) {
+                @autoreleasepool {
+                    NSString *fileName = [NSString stringWithFormat:@"%@%@_%@",imageName, imageSize, quality];
+                    NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"bpg"];
+                    NSData *data = filePath ? [NSData dataWithContentsOfFile:filePath] : nil;
+                    if (!data) continue;
+                    int count = 100;
+                    YYBenchmark(^{
+                        for (int i = 0; i < count; i++) {
+                            CGImageRef image = YYCGImageCreateWithBPGData((__bridge CFDataRef)data, YES);
+                            CFRelease(image);
+                        }
+                    }, ^(double ms) {
+                        printf("%8s %3d %8s %6d %2.3f\n", imageName.UTF8String, imageSize.intValue, quality.UTF8String, (int)data.length, ms / count);
+                    });
+                    
+                    
+#if ENABLE_OUTPUT
+                    if ([UIDevice currentDevice].isSimulator) {
+                        NSString *outFilePath = [NSString stringWithFormat:@"%@%@.bpg", IMAGE_OUTPUT_DIR,fileName];
+                        [data writeToFile:outFilePath atomically:YES];
+                        
+                        CGImageRef image = YYCGImageCreateWithBPGData((__bridge CFDataRef)data, YES);
+                        NSData *pngData = UIImagePNGRepresentation([UIImage imageWithCGImage:image]);
+                        CFRelease(image);
+                        NSString *pngOutFilePath = [NSString stringWithFormat:@"%@%@.bpg.png", IMAGE_OUTPUT_DIR,fileName];
+                        [pngData writeToFile:pngOutFilePath atomically:YES];
+                    }
+#endif
+                    
+                }
+            }
+        }
+    }
+    
+    printf("------------------------------------------\n\n");
+}
+
+- (void)runAnimatedImageBenchmark {
+    printf("==========================================\n");
+    printf("Animated Image Decode Benckmark\n");
+    if (!kiOS8Later) {
+        printf("APNG require iOS8 or later\n");
+        return;
+    }
+    
+    NSData *gif = [NSData dataNamed:@"ermilio.gif"];
+    NSData *apng = [NSData dataNamed:@"ermilio.png"];
+    
+    NSData *webp_q85 = [NSData dataNamed:@"ermilio_q85.webp"];
+    NSData *webp_q90 = [NSData dataNamed:@"ermilio_q90.webp"];
+    NSData *webp_lossless = [NSData dataNamed:@"ermilio_lossless.webp"];
+    
+    NSData *bpg_q15 = [NSData dataNamed:@"ermilio_q15.bpg"];
+    NSData *bpg_q20 = [NSData dataNamed:@"ermilio_q20.bpg"];
+    NSData *bpg_lossless = [NSData dataNamed:@"ermilio_lossless.bpg"];
+    
+    NSArray *datas = @[gif, apng, webp_q85, webp_q90, webp_lossless, bpg_q20, bpg_q15, bpg_lossless];
+    NSArray *names = @[@"gif", @"apng", @"webp_85", @"webp_90", @"webp_ll", @"bpg_20", @"bpg_15", @"bpg_ll"];
+    
+    
+#if ENABLE_OUTPUT
+    if ([UIDevice currentDevice].isSimulator) {
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio.gif.png",IMAGE_OUTPUT_DIR];
+            NSData *outData = UIImagePNGRepresentation([UIImage imageWithData:gif]);
+            [outData writeToFile:outPath atomically:YES];
+            [gif writeToFile:[NSString stringWithFormat:@"%@ermilio.gif",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio.apng.png",IMAGE_OUTPUT_DIR];
+            NSData *outData = UIImagePNGRepresentation([UIImage imageWithData:apng]);
+            [outData writeToFile:outPath atomically:YES];
+            [apng writeToFile:[NSString stringWithFormat:@"%@ermilio.png",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio_q85.webp.png",IMAGE_OUTPUT_DIR];
+            NSData *outData = UIImagePNGRepresentation([YYImageDecoder decodeImage:webp_q85 scale:1]);
+            [outData writeToFile:outPath atomically:YES];
+            [webp_q85 writeToFile:[NSString stringWithFormat:@"%@ermilio_q85.webp",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio_q90.webp.png",IMAGE_OUTPUT_DIR];
+            NSData *outData = UIImagePNGRepresentation([YYImageDecoder decodeImage:webp_q90 scale:1]);
+            [outData writeToFile:outPath atomically:YES];
+            [webp_q90 writeToFile:[NSString stringWithFormat:@"%@ermilio_q90.webp",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio_lossless.webp.png",IMAGE_OUTPUT_DIR];
+            NSData *outData = UIImagePNGRepresentation([YYImageDecoder decodeImage:webp_lossless scale:1]);
+            [outData writeToFile:outPath atomically:YES];
+            [webp_lossless writeToFile:[NSString stringWithFormat:@"%@ermilio_lossless.webp",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio_q15.bpg.png",IMAGE_OUTPUT_DIR];
+            CGImageRef imageRef = YYCGImageCreateWithBPGData((__bridge CFDataRef)bpg_q15, NO);
+            NSData *outData = UIImagePNGRepresentation([UIImage imageWithCGImage:imageRef]);
+            [outData writeToFile:outPath atomically:YES];
+            CFRelease(imageRef);
+            [bpg_q15 writeToFile:[NSString stringWithFormat:@"%@ermilio_q15.bpg",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio_q20.bpg.png",IMAGE_OUTPUT_DIR];
+            CGImageRef imageRef = YYCGImageCreateWithBPGData((__bridge CFDataRef)bpg_q20, NO);
+            NSData *outData = UIImagePNGRepresentation([UIImage imageWithCGImage:imageRef]);
+            [outData writeToFile:outPath atomically:YES];
+            CFRelease(imageRef);
+            [bpg_q20 writeToFile:[NSString stringWithFormat:@"%@ermilio_q20.bpg",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+        @autoreleasepool {
+            NSString *outPath = [NSString stringWithFormat:@"%@ermilio_lossless.bpg.png",IMAGE_OUTPUT_DIR];
+            CGImageRef imageRef = YYCGImageCreateWithBPGData((__bridge CFDataRef)bpg_lossless, NO);
+            NSData *outData = UIImagePNGRepresentation([UIImage imageWithCGImage:imageRef]);
+            [outData writeToFile:outPath atomically:YES];
+            CFRelease(imageRef);
+            [bpg_lossless writeToFile:[NSString stringWithFormat:@"%@ermilio_lossless.bpg",IMAGE_OUTPUT_DIR] atomically:YES];
+        }
+    }
+#endif
+    
+    
+    printf("------------------------------------------\n");
+    printf("image   length\n");
+    for (int i = 0; i < names.count; i++) {
+        NSString *name = names[i];
+        NSData *data = datas[i];
+        printf("%7s %6d\n",name.UTF8String, (int)data.length);
+    }
+    printf("\n\n");
+    
+    int count = 20;
+    int frame_num = 28;
+    
+    typedef void (^CoverDecodeBlock)(id src);
+    typedef void (^SingleFrameDecodeBlock)(id src, NSUInteger index);
+    typedef void (^AllFrameDecodeBlock)(id src, BOOL reverseOrder);
+    
+    /// Cover: gif/apng
+    CoverDecodeBlock imageioCoverDecoder = ^(NSData *data){
+        CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)data, NULL);
+        CGImageRef image = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache:@(NO)});
+        CGImageRef decoded = YYCGImageCreateDecodedCopy(image, YES);
+        CFRelease(decoded);
+        CFRelease(image);
+        CFRelease(source);
+    };
+    
+    /// Cover: gif/apng/webp
+    CoverDecodeBlock yyCoverDecoder = ^(NSData *data) {
+        @autoreleasepool {
+            YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:1];
+            [decoder frameAtIndex:0 decodeForDisplay:YES];;
+        }
+    };
+    
+    /// Cover: webp
+    CoverDecodeBlock webpCoverDecoder = ^(NSData *data) {
+        CGImageRef image = YYCGImageCreateWithWebPData((__bridge CFDataRef)data, YES, NO, NO, NO);
+        CFRelease(image);
+    };
+    
+    /// Cover: bpg
+    CoverDecodeBlock bpgCoverDecoder = ^(NSData *data) {
+        CGImageRef image = YYCGImageCreateWithBPGData((__bridge CFDataRef)data, YES);
+        CFRelease(image);
+    };
+    
+    NSArray *coverSrcs = @[@"gif       imageio", gif, imageioCoverDecoder,
+                           @"gif     yydecoder", gif, yyCoverDecoder,
+                           @"apng      imageio", apng, imageioCoverDecoder,
+                           @"apng    yydecoder", apng, yyCoverDecoder,
+                           @"webp_85   yyimage", webp_q85, webpCoverDecoder,
+                           @"webp_85 yydecocer", webp_q85, yyCoverDecoder,
+                           @"webp_90   yyimage", webp_q90, webpCoverDecoder,
+                           @"webp_90 yydecocer", webp_q90, yyCoverDecoder,
+                           @"webp_ll   yyimage", webp_lossless, webpCoverDecoder,
+                           @"webp_ll yydecoder", webp_lossless, yyCoverDecoder,
+                           @"bpg_20    yyimage", bpg_q20, bpgCoverDecoder,
+                           @"bpg_15    yyimage", bpg_q20, bpgCoverDecoder,
+                           @"bpg_ll    yyimage", bpg_lossless, bpgCoverDecoder,
+                           ];
+    
+    
+    printf("------------------------------------------\n");
+    printf("First frame (cover) decode\n");
+    count = 20;
+    for (int i = 0; i < coverSrcs.count / 3; i++) {
+        NSString *name = coverSrcs[i * 3];
+        id src = coverSrcs[i * 3 + 1];
+        CoverDecodeBlock block = coverSrcs[i * 3 + 2];
+        YYBenchmark(^{
+            for (int r = 0; r < count; r++) {
+                block(src);
+            }
+        }, ^(double ms) {
+            printf("%s %8.3f\n",name.UTF8String, ms / count);
+        });
+    }
+    printf("\n\n");
+    
+    
+    
+    
+    
+    
+    
+    
+    /// Single: gif/apng
+    SingleFrameDecodeBlock imagioSingleFrameDecoder = ^(id src, NSUInteger index) {
+        CGImageSourceRef source = (__bridge CGImageSourceRef)src;
+        CGImageRef image = CGImageSourceCreateImageAtIndex(source, index, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache:@(NO)});
+        CGImageRef decoded = YYCGImageCreateDecodedCopy(image, YES);
+        CFRelease(decoded);
+        CFRelease(image);
+    };
+    
+    /// Single: gif/apng/webp
+    SingleFrameDecodeBlock yySingleFrameDecoder = ^(YYImageDecoder *decoder, NSUInteger index) {
+        @autoreleasepool {
+            UIImage *img = [decoder frameAtIndex:index decodeForDisplay:YES].image;
+            [img scale];
+        }
+    };
+    
+    
+    NSArray *singleSrcs = @[@"gif       imageio", @"gif src", imagioSingleFrameDecoder,
+                            @"gif     yydecoder", @"gif", yySingleFrameDecoder,
+                            @"apng      imageio", @"apng src", imagioSingleFrameDecoder,
+                            @"apng    yydecoder", @"apng", yySingleFrameDecoder,
+                            @"webp_85 yydecocer", @"webp85", yySingleFrameDecoder,
+                            @"webp_90 yydecocer", @"webp90", yySingleFrameDecoder,
+                            @"webp_ll yydecoder", @"webpll", yySingleFrameDecoder,
+                            ];
+
+    
+    
+    printf("------------------------------------------\n");
+    printf("Single frame decode\n");
+    count = 5;
+    for (int i = 0; i < singleSrcs.count / 3; i++) {
+        NSString *name = singleSrcs[i * 3];
+        NSString *srcStr = singleSrcs[i * 3 + 1];
+        
+        SingleFrameDecodeBlock block = singleSrcs[i * 3 + 2];
+        
+        printf("%s ",name.UTF8String);
+        for (int f = 0; f < frame_num; f++) {
+            YYBenchmark(^{
+                for (int r = 0; r < count; r++) {
+                    id src = NULL;
+                    if ([srcStr isEqual:@"gif src"]) {
+                        src = CFBridgingRelease(CGImageSourceCreateWithData((__bridge CFDataRef)gif, NULL));
+                    } else if ([srcStr isEqual:@"gif"]) {
+                        src = [YYImageDecoder decoderWithData:gif scale:1];
+                    } else if ([srcStr isEqual:@"apng src"]) {
+                        src = CFBridgingRelease(CGImageSourceCreateWithData((__bridge CFDataRef)apng, NULL));
+                    } else if ([srcStr isEqual:@"apng"]) {
+                        src = [YYImageDecoder decoderWithData:apng scale:1];
+                    } else if ([srcStr isEqual:@"webp85"]) {
+                        src = [YYImageDecoder decoderWithData:webp_q85 scale:1];
+                    } else if ([srcStr isEqual:@"webp90"]) {
+                        src = [YYImageDecoder decoderWithData:webp_q90 scale:1];
+                    } else if ([srcStr isEqual:@"webpll"]) {
+                        src = [YYImageDecoder decoderWithData:webp_lossless scale:1];
+                    }
+                    block(src, f);
+                }
+            }, ^(double ms) {
+                printf("%8.3f ",ms / count);
+            });
+        }
+        printf("\n");
+    }
+    printf("\n\n");
+    
+
+    
+    /// All: gif/apng
+    AllFrameDecodeBlock imageioAllFrameDecoder = ^(NSData *data, BOOL reverseOrder){
+        CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)gif, NULL);
+        if (reverseOrder) {
+            for (int i = frame_num - 1; i >= 0; i--) {
+                CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache:@(NO)});
+                CGImageRef decoded = YYCGImageCreateDecodedCopy(image, YES);
+                CFRelease(decoded);
+                CFRelease(image);
+            }
+        } else {
+            for (int i = 0; i < frame_num; i++) {
+                CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, (CFDictionaryRef)@{(id)kCGImageSourceShouldCache:@(NO)});
+                CGImageRef decoded = YYCGImageCreateDecodedCopy(image, YES);
+                CFRelease(decoded);
+                CFRelease(image);
+            }
+        }
+        CFRelease(source);
+    };
+    
+    /// All: gif/apng/webp
+    AllFrameDecodeBlock yyAllFrameDecoder = ^(NSData *data, BOOL reverseOrder){
+        @autoreleasepool {
+            YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:1];
+            if (reverseOrder) {
+                for (int i = frame_num - 1; i > 0; i--) {
+                    [decoder frameAtIndex:i decodeForDisplay:YES];
+                }
+            } else {
+                for (int i = 1; i < frame_num; i++) {
+                    [decoder frameAtIndex:i decodeForDisplay:YES];
+                }
+            }
+        }
+    };
+    
+    /// All: bpg
+    AllFrameDecodeBlock bpgAllFrameDecoder = ^(NSData *data, BOOL reverseOrder){
+        @autoreleasepool {
+            YYCGImageDecodeAllFrameInBPGData((__bridge CFDataRef)data, YES);
+        }
+    };
+    
+    NSArray *allSrcs = @[@"gif       imageio", gif, imageioAllFrameDecoder,
+                         @"gif     yydecoder", gif, yyAllFrameDecoder,
+                         @"apng      imageio", apng, imageioAllFrameDecoder,
+                         @"apng    yydecoder", apng, yyAllFrameDecoder,
+                         @"webp_85 yydecocer", webp_q85, yyAllFrameDecoder,
+                         @"webp_90 yydecocer", webp_q90, yyAllFrameDecoder,
+                         @"webp_ll yydecoder", webp_lossless, yyAllFrameDecoder,
+                         @"bpg_20    yyimage", bpg_q20, bpgAllFrameDecoder,
+                         @"bpg_15    yyimage", bpg_q20, bpgAllFrameDecoder,
+                         @"bpg_ll    yyimage", bpg_lossless, bpgAllFrameDecoder,
+                         ];
+    
+    
+    
+    printf("------------------------------------------\n");
+    printf("All frame decode\n");
+    printf("type      decoder      asc     desc\n");
+    count = 5;
+    for (int i = 0; i < allSrcs.count / 3; i++) {
+        NSString *name = allSrcs[i * 3];
+        id src = allSrcs[i * 3 + 1];
+        AllFrameDecodeBlock block = allSrcs[i * 3 + 2];
+        
+        printf("%s ",name.UTF8String);
+        for (NSNumber *rev in @[@NO, @YES]) {
+            if ([name hasPrefix:@"bpg"] && rev.boolValue) continue;
+            YYBenchmark(^{
+                for (int r = 0; r < count; r++) {
+                    block(src, rev.boolValue);
+                }
+            }, ^(double ms) {
+                printf("%8.3f ",ms / count);
+            });
+        }
+        printf("\n");
+    }
+    printf("\n\n");
+
+}
+
+@end

+ 13 - 0
Demo/YYWebImageDemo/YYImageDisplayExample.h

@@ -0,0 +1,13 @@
+//
+//  YYImageDisplayExample.h
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/9.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface YYImageDisplayExample : UIViewController
+
+@end

+ 143 - 0
Demo/YYWebImageDemo/YYImageDisplayExample.m

@@ -0,0 +1,143 @@
+//
+//  YYImageDisplayExample.m
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/9.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import "YYImageDisplayExample.h"
+#import "YYImage.h"
+#import "UIView+YYAdd.h"
+#import "YYImageExampleHelper.h"
+#import <sys/sysctl.h>
+
+@interface YYImageDisplayExample()<UIGestureRecognizerDelegate>
+
+@end
+@implementation YYImageDisplayExample {
+    UIScrollView *_scrollView;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.view.backgroundColor = [UIColor colorWithWhite:0.863 alpha:1.000];
+    
+    _scrollView = [UIScrollView new];
+    _scrollView.frame = self.view.bounds;
+    [self.view addSubview:_scrollView];
+    
+    UILabel *label = [UILabel new];
+    label.backgroundColor = [UIColor clearColor];
+    label.size = CGSizeMake(self.view.width, 60);
+    label.top = 20;
+    label.textAlignment = NSTextAlignmentCenter;
+    label.numberOfLines = 0;
+    label.text = @"Tap the image to pause/play\n Slide on the image to forward/rewind";
+    
+    if ([self isSimulator]) {
+        label.text = [@"Please run this app in device\nto get better performance.\n\n" stringByAppendingString:label.text];
+        label.height = 120;
+    }
+    
+    [_scrollView addSubview:label];
+    
+    [self addImageWithName:@"niconiconi" text:@"Animated GIF"];
+    [self addImageWithName:@"wall-e" text:@"Animated WebP"];
+    [self addImageWithName:@"pia" text:@"Animated PNG (APNG)"];
+    [self addFrameImageWithText:@"Frame Animation"];
+    [self addSpriteSheetImageWithText:@"Sprite Sheet Animation"];
+    
+    _scrollView.panGestureRecognizer.cancelsTouchesInView = YES;
+}
+
+- (void)addImageWithName:(NSString *)name text:(NSString *)text {
+    YYImage *image = [YYImage imageNamed:name];
+    [self addImage:image size:CGSizeZero text:text];
+}
+
+- (void)addFrameImageWithText:(NSString *)text {
+    
+    NSString *basePath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"EmoticonWeibo.bundle/com.sina.default"];
+    NSMutableArray *paths = [NSMutableArray new];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_aini@3x.png"]];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_baibai@3x.png"]];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_chanzui@3x.png"]];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_chijing@3x.png"]];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_dahaqi@3x.png"]];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_guzhang@3x.png"]];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_haha@2x.png"]];
+    [paths addObject:[basePath stringByAppendingPathComponent:@"d_haixiu@3x.png"]];
+    
+    UIImage *image = [[YYFrameImage alloc] initWithImagePaths:paths oneFrameDuration:0.1 loopCount:0];
+    [self addImage:image size:CGSizeZero text:text];
+}
+
+- (void)addSpriteSheetImageWithText:(NSString *)text {
+    NSString *path = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"ResourceTwitter.bundle/fav02l-sheet@2x.png"];
+    UIImage *sheet = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:path] scale:2];
+    NSMutableArray *contentRects = [NSMutableArray new];
+    NSMutableArray *durations = [NSMutableArray new];
+    
+    
+    // 8 * 12 sprites in a single sheet image
+    CGSize size = CGSizeMake(sheet.size.width / 8, sheet.size.height / 12);
+    for (int j = 0; j < 12; j++) {
+        for (int i = 0; i < 8; i++) {
+            CGRect rect;
+            rect.size = size;
+            rect.origin.x = sheet.size.width / 8 * i;
+            rect.origin.y = sheet.size.height / 12 * j;
+            [contentRects addObject:[NSValue valueWithCGRect:rect]];
+            [durations addObject:@(1 / 60.0)];
+        }
+    }
+    YYSpriteSheetImage *sprite;
+    sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:sheet
+                                                     contentRects:contentRects
+                                                   frameDurations:durations
+                                                        loopCount:0];
+    [self addImage:sprite size:size text:text];
+}
+
+- (void)addImage:(UIImage *)image size:(CGSize)size text:(NSString *)text {
+    YYAnimatedImageView *imageView = [[YYAnimatedImageView alloc] initWithImage:image];
+    
+    if (size.width > 0 && size.height > 0) imageView.size = size;
+    imageView.centerX = self.view.width / 2;
+    imageView.top = [(UIView *)[_scrollView.subviews lastObject] bottom] + 30;
+    [_scrollView addSubview:imageView];
+    [YYImageExampleHelper addTapControlToAnimatedImageView:imageView];
+    [YYImageExampleHelper addPanControlToAnimatedImageView:imageView];
+    for (UIGestureRecognizer *g in imageView.gestureRecognizers) {
+        g.delegate = self;
+    }
+    
+    UILabel *imageLabel = [UILabel new];
+    imageLabel.backgroundColor = [UIColor clearColor];
+    imageLabel.frame = CGRectMake(0, 0, self.view.width, 20);
+    imageLabel.top = imageView.bottom + 10;
+    imageLabel.textAlignment = NSTextAlignmentCenter;
+    imageLabel.text = text;
+    [_scrollView addSubview:imageLabel];
+    
+    _scrollView.contentSize = CGSizeMake(self.view.width, imageLabel.bottom + 20);
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
+    return YES;
+}
+
+
+
+- (BOOL)isSimulator {
+    size_t size;
+    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+    char *machine = malloc(size);
+    sysctlbyname("hw.machine", machine, &size, NULL, 0);
+    NSString *model = [NSString stringWithUTF8String:machine];
+    free(machine);
+    return [model isEqualToString:@"x86_64"] || [model isEqualToString:@"i386"];
+}
+
+@end

+ 13 - 0
Demo/YYWebImageDemo/YYImageExample.h

@@ -0,0 +1,13 @@
+//
+//  YYImageExample.h
+//  YYKitExample
+//
+//  Created by ibireme on 15/7/18.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface YYImageExample : UITableViewController
+
+@end

+ 65 - 0
Demo/YYWebImageDemo/YYImageExample.m

@@ -0,0 +1,65 @@
+//
+//  YYImageExample.m
+//  YYKitExample
+//
+//  Created by ibireme on 15/7/18.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import "YYImageExample.h"
+#import "YYImage.h"
+#import "UIView+YYAdd.h"
+#import <ImageIO/ImageIO.h>
+#import <WebP/demux.h>
+
+@interface YYImageExample()
+@property (nonatomic, strong) NSMutableArray *titles;
+@property (nonatomic, strong) NSMutableArray *classNames;
+@end
+
+@implementation YYImageExample
+
+- (void)viewDidLoad {
+    self.title = @"YYWebImage Demo";
+    [super viewDidLoad];
+    self.titles = @[].mutableCopy;
+    self.classNames = @[].mutableCopy;
+    [self addCell:@"Animated Image" class:@"YYImageDisplayExample"];
+    [self addCell:@"Progressive Image" class:@"YYImageProgressiveExample"];
+    [self addCell:@"Web Image" class:@"YYWebImageExample"];
+    //[self addCell:@"Benchmark" class:@"YYImageBenchmark"];
+    [self.tableView reloadData];
+}
+
+- (void)addCell:(NSString *)title class:(NSString *)className {
+    [self.titles addObject:title];
+    [self.classNames addObject:className];
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return _titles.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YY"];
+    if (!cell) {
+        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"YY"];
+    }
+    cell.textLabel.text = _titles[indexPath.row];
+    return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    NSString *className = self.classNames[indexPath.row];
+    Class class = NSClassFromString(className);
+    if (class) {
+        UIViewController *ctrl = class.new;
+        ctrl.title = _titles[indexPath.row];
+        [self.navigationController pushViewController:ctrl animated:YES];
+    }
+    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
+}
+
+@end

+ 21 - 0
Demo/YYWebImageDemo/YYImageExampleHelper.h

@@ -0,0 +1,21 @@
+//
+//  YYImageExampleUtils.h
+//  YYKitExample
+//
+//  Created by ibireme on 15/7/20.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "YYWebImage.h"
+
+@interface YYImageExampleHelper : NSObject
+
+/// Tap to play/pause
++ (void)addTapControlToAnimatedImageView:(YYAnimatedImageView *)view;
+
+/// Slide to forward/rewind
++ (void)addPanControlToAnimatedImageView:(YYAnimatedImageView *)view;
+
+@end
+

+ 72 - 0
Demo/YYWebImageDemo/YYImageExampleHelper.m

@@ -0,0 +1,72 @@
+//
+//  YYImageExampleUtils.m
+//  YYKitExample
+//
+//  Created by ibireme on 15/7/20.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import "YYImageExampleHelper.h"
+#import "YYImage.h"
+#import "UIView+YYAdd.h"
+#import "CALayer+YYAdd.h"
+#import "UIGestureRecognizer+YYAdd.h"
+#import <ImageIO/ImageIO.h>
+#import <Accelerate/Accelerate.h>
+//#import <bpg/libbpg.h>
+
+@implementation YYImageExampleHelper
+
++ (void)addTapControlToAnimatedImageView:(YYAnimatedImageView *)view {
+    if (!view) return;
+    view.userInteractionEnabled = YES;
+    __weak typeof(view) _view = view;
+    
+    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithActionBlock:^(id sender) {
+        if ([_view isAnimating]) [_view stopAnimating];
+        else  [_view startAnimating];
+        
+        // add a "bounce" animation
+        UIViewAnimationOptions op = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState;
+        [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
+            _view.layer.transformScale = 0.97;
+        } completion:^(BOOL finished) {
+            [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
+                _view.layer.transformScale = 1.008;
+            } completion:^(BOOL finished) {
+                [UIView animateWithDuration:0.1 delay:0 options:op animations:^{
+                    _view.layer.transformScale = 1;
+                } completion:NULL];
+            }];
+        }];
+    }];
+    [view addGestureRecognizer:tap];
+}
+
++ (void)addPanControlToAnimatedImageView:(YYAnimatedImageView *)view {
+    if (!view) return;
+    view.userInteractionEnabled = YES;
+    __weak typeof(view) _view = view;
+    __block BOOL previousIsPlaying;
+    
+    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithActionBlock:^(id sender) {
+        UIImage<YYAnimatedImage> *image = (id)_view.image;
+        if (![image conformsToProtocol:@protocol(YYAnimatedImage)]) return;
+        UIPanGestureRecognizer *gesture = sender;
+        CGPoint p = [gesture locationInView:gesture.view];
+        CGFloat progress = p.x / gesture.view.width;
+        if (gesture.state == UIGestureRecognizerStateBegan) {
+            previousIsPlaying = [_view isAnimating];
+            [_view stopAnimating];
+            _view.currentAnimatedImageIndex = image.animatedImageFrameCount * progress;
+        } else if (gesture.state == UIGestureRecognizerStateEnded ||
+                   gesture.state == UIGestureRecognizerStateCancelled) {
+            if (previousIsPlaying) [_view startAnimating];
+        } else {
+            _view.currentAnimatedImageIndex = image.animatedImageFrameCount * progress;
+        }
+    }];
+    [view addGestureRecognizer:pan];    
+}
+
+@end

+ 13 - 0
Demo/YYWebImageDemo/YYImageProgressiveExample.h

@@ -0,0 +1,13 @@
+//
+//  YYImageProgressiveExample.h
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/24.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface YYImageProgressiveExample : UIViewController
+
+@end

+ 117 - 0
Demo/YYWebImageDemo/YYImageProgressiveExample.m

@@ -0,0 +1,117 @@
+//
+//  YYImageProgressiveExample.m
+//  YYKitExample
+//
+//  Created by ibireme on 15/8/24.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import "YYImageProgressiveExample.h"
+#import "YYImage.h"
+#import "UIView+YYAdd.h"
+#import "UIControl+YYAdd.h"
+
+@interface NSData(YYAdd)
+@end
+@implementation NSData(YYAdd)
++ (NSData *)dataNamed:(NSString *)name {
+    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""];
+    if (!path) return nil;
+    NSData *data = [NSData dataWithContentsOfFile:path];
+    return data;
+}
+@end
+
+
+@interface YYImageProgressiveExample () {
+    UIImageView *_imageView;
+    UISegmentedControl *_seg0;
+    UISegmentedControl *_seg1;
+    UISlider *_slider0;
+}
+
+@end
+
+@implementation YYImageProgressiveExample
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.view.backgroundColor = [UIColor whiteColor];
+    
+    _imageView = [UIImageView new];
+    _imageView.size = CGSizeMake(300, 300);
+    _imageView.backgroundColor = [UIColor colorWithWhite:0.790 alpha:1.000];
+    _imageView.centerX = self.view.width / 2;
+    
+    _seg0 = [[UISegmentedControl alloc] initWithItems:@[@"baseline",@"progressive/interlaced"]];
+    _seg0.selectedSegmentIndex = 0;
+    _seg0.size = CGSizeMake(_imageView.width, 30);
+    _seg0.centerX = self.view.width / 2;
+    
+    _seg1 = [[UISegmentedControl alloc] initWithItems:@[@"JPEG", @"PNG", @"GIF"]];
+    _seg1.frame = _seg0.frame;
+    _seg1.selectedSegmentIndex = 0;
+    
+    _slider0 = [UISlider new];
+    _slider0.width = _seg0.width;
+    [_slider0 sizeToFit];
+    _slider0.minimumValue = 0;
+    _slider0.maximumValue = 1.05;
+    _slider0.value = 0;
+    _slider0.centerX = self.view.width / 2;
+    
+    _imageView.top = 64 + 10;
+    _seg0.top = _imageView.bottom + 10;
+    _seg1.top = _seg0.bottom + 10;
+    _slider0.top = _seg1.bottom + 10;
+    
+    [self.view addSubview:_imageView];
+    [self.view addSubview:_seg0];
+    [self.view addSubview:_seg1];
+    [self.view addSubview:_slider0];
+    
+    __weak typeof(self) _self = self;
+    [_seg0 addBlockForControlEvents:UIControlEventValueChanged block:^(id sender) {
+        [_self changed];
+    }];
+    [_seg1 addBlockForControlEvents:UIControlEventValueChanged block:^(id sender) {
+        [_self changed];
+    }];
+    [_slider0 addBlockForControlEvents:UIControlEventValueChanged block:^(id sender) {
+        [_self changed];
+    }];
+}
+
+- (void)changed {
+    NSString *name = nil;
+    if (_seg0.selectedSegmentIndex == 0) {
+        if (_seg1.selectedSegmentIndex == 0) {
+            name = @"mew_baseline.jpg";
+        } else if (_seg1.selectedSegmentIndex == 1) {
+            name = @"mew_baseline.png";
+        } else {
+            name = @"mew_baseline.gif";
+        }
+    } else {
+        if (_seg1.selectedSegmentIndex == 0) {
+            name = @"mew_progressive.jpg";
+        } else if (_seg1.selectedSegmentIndex == 1) {
+            name = @"mew_interlaced.png";
+        } else {
+            name = @"mew_interlaced.gif";
+        }
+    }
+    
+    NSData *data = [NSData dataNamed:name];
+    float progress = _slider0.value;
+    if (progress > 1) progress = 1;
+    NSData *subData = [data subdataWithRange:NSMakeRange(0, data.length * progress)];
+    
+    YYImageDecoder *decoder = [[YYImageDecoder alloc] initWithScale:[UIScreen mainScreen].scale];
+    [decoder updateData:subData final:NO];
+    YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES];
+    
+    _imageView.image = frame.image;
+}
+
+@end

+ 13 - 0
Demo/YYWebImageDemo/YYWebImageExample.h

@@ -0,0 +1,13 @@
+//
+//  YYWebImageExample.h
+//  YYKitExample
+//
+//  Created by ibireme on 15/7/19.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface YYWebImageExample : UITableViewController
+
+@end

+ 230 - 0
Demo/YYWebImageDemo/YYWebImageExample.m

@@ -0,0 +1,230 @@
+//
+//  YYWebImageExample.m
+//  YYKitExample
+//
+//  Created by ibireme on 15/7/19.
+//  Copyright (c) 2015 ibireme. All rights reserved.
+//
+
+#import "YYWebImageExample.h"
+#import "YYWebImage.h"
+#import "UIView+YYAdd.h"
+#import "CALayer+YYAdd.h"
+#import "UIGestureRecognizer+YYAdd.h"
+
+#define kCellHeight ceil((kScreenWidth) * 3.0 / 4.0)
+#define kScreenWidth ((UIWindow *)[UIApplication sharedApplication].windows.firstObject).width
+
+@interface YYWebImageExampleCell : UITableViewCell
+@property (nonatomic, strong) YYAnimatedImageView *webImageView;
+@property (nonatomic, strong) UIActivityIndicatorView *indicator;
+@property (nonatomic, strong) CAShapeLayer *progressLayer;
+@property (nonatomic, strong) UILabel *label;
+@end
+
+@implementation YYWebImageExampleCell
+- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
+    
+    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
+    self.backgroundColor = [UIColor clearColor];
+    self.contentView.backgroundColor = [UIColor clearColor];
+    self.size = CGSizeMake(kScreenWidth, kCellHeight);
+    self.contentView.size = self.size;
+    _webImageView = [YYAnimatedImageView new];
+    _webImageView.size = self.size;
+    _webImageView.clipsToBounds = YES;
+    _webImageView.contentMode = UIViewContentModeScaleAspectFill;
+    _webImageView.backgroundColor = [UIColor whiteColor];
+    [self.contentView addSubview:_webImageView];
+    
+    _indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
+    _indicator.center = CGPointMake(self.width / 2, self.height / 2);
+    _indicator.hidden = YES;
+    //[self.contentView addSubview:_indicator]; //use progress bar instead..
+    
+    _label = [UILabel new];
+    _label.size = self.size;
+    _label.textAlignment = NSTextAlignmentCenter;
+    _label.text = @"Load fail, tap to reload.";
+    _label.textColor = [UIColor colorWithWhite:0.7 alpha:1.0];
+    _label.hidden = YES;
+    _label.userInteractionEnabled = YES;
+    [self.contentView addSubview:_label];
+    
+    CGFloat lineHeight = 4;
+    _progressLayer = [CAShapeLayer layer];
+    _progressLayer.size = CGSizeMake(_webImageView.width, lineHeight);
+    UIBezierPath *path = [UIBezierPath bezierPath];
+    [path moveToPoint:CGPointMake(0, _progressLayer.height / 2)];
+    [path addLineToPoint:CGPointMake(_webImageView.width, _progressLayer.height / 2)];
+    _progressLayer.lineWidth = lineHeight;
+    _progressLayer.path = path.CGPath;
+    _progressLayer.strokeColor = [UIColor colorWithRed:0.000 green:0.640 blue:1.000 alpha:0.720].CGColor;
+    _progressLayer.lineCap = kCALineCapButt;
+    _progressLayer.strokeStart = 0;
+    _progressLayer.strokeEnd = 0;
+    [_webImageView.layer addSublayer:_progressLayer];
+    
+    __weak typeof(self) _self = self;
+    UITapGestureRecognizer *g = [[UITapGestureRecognizer alloc] initWithActionBlock:^(id sender) {
+        [_self setImageURL:_self.webImageView.yy_imageURL];
+    }];
+    [_label addGestureRecognizer:g];
+    
+    return self;
+}
+
+- (void)setImageURL:(NSURL *)url {
+    _label.hidden = YES;
+    _indicator.hidden = NO;
+    [_indicator startAnimating];
+    __weak typeof(self) _self = self;
+    
+    [CATransaction begin];
+    [CATransaction setDisableActions: YES];
+    self.progressLayer.hidden = YES;
+    self.progressLayer.strokeEnd = 0;
+    [CATransaction commit];
+
+    [_webImageView yy_setImageWithURL:url
+                          placeholder:nil
+                          options:YYWebImageOptionProgressiveBlur | YYWebImageOptionShowNetworkActivity | YYWebImageOptionSetImageWithFadeAnimation
+                          progress:^(NSInteger receivedSize, NSInteger expectedSize) {
+                              if (expectedSize > 0 && receivedSize > 0) {
+                                  CGFloat progress = (CGFloat)receivedSize / expectedSize;
+                                  progress = progress < 0 ? 0 : progress > 1 ? 1 : progress;
+                                  if (_self.progressLayer.hidden) _self.progressLayer.hidden = NO;
+                                  _self.progressLayer.strokeEnd = progress;
+                              }
+                          }
+                          transform:nil
+                          completion:^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) {
+                              if (stage == YYWebImageStageFinished) {
+                                  _self.progressLayer.hidden = YES;
+                                  [_self.indicator stopAnimating];
+                                  _self.indicator.hidden = YES;
+                                  if (!image) _self.label.hidden = NO;
+                              }
+                         }];
+}
+
+- (void)prepareForReuse {
+    //nothing
+}
+
+@end
+
+
+@implementation YYWebImageExample {
+    NSArray *_imageLinks;
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+    self.view.backgroundColor = [UIColor whiteColor];
+    
+    UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Reload" style:UIBarButtonItemStylePlain target:self action:@selector(reload)];
+    self.navigationItem.rightBarButtonItem = button;
+    self.view.backgroundColor = [UIColor colorWithWhite:0.217 alpha:1.000];
+    
+    NSArray *links = @[
+        /*
+         You can add your image url here.
+         */
+        
+        // progressive jpeg
+        @"https://s-media-cache-ak0.pinimg.com/1200x/2e/0c/c5/2e0cc5d86e7b7cd42af225c29f21c37f.jpg",
+        
+        // animated gif: http://cinemagraphs.com/
+        @"http://i.imgur.com/uoBwCLj.gif",
+        @"http://i.imgur.com/8KHKhxI.gif",
+        @"http://i.imgur.com/WXJaqof.gif",
+        
+        // animated gif: https://dribbble.com/markpear
+        @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1780193/dots18.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1809343/dots17.1.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1845612/dots22.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1820014/big-hero-6.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1819006/dots11.0.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1799885/dots21.gif",
+        
+        // animaged gif: https://dribbble.com/jonadinges
+        @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/2025999/batman-beyond-the-rain.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/1855350/r_nin.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/1963497/way-back-home.gif",
+        @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/1913272/depressed-slurp-cycle.gif",
+        
+        // jpg: https://dribbble.com/snootyfox
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/2047158/beerhenge.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/2016158/avalanche.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1839353/pilsner.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1833469/porter.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1521183/farmers.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1391053/tents.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1399501/imperial_beer.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1488711/fishin.jpg",
+        @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1466318/getaway.jpg",
+        
+        // animated webp and apng: http://littlesvr.ca/apng/gif_apng_webp.html
+        @"http://littlesvr.ca/apng/images/BladeRunner.png",
+        @"http://littlesvr.ca/apng/images/Contact.webp",
+    ];
+    
+    _imageLinks = links;
+    [self.tableView reloadData];
+    [self scrollViewDidScroll:self.tableView];
+}
+
+- (void)viewDidAppear:(BOOL)animated {
+    [super viewDidAppear:animated];
+    self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
+    self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
+    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    self.navigationController.navigationBar.barStyle = UIBarStyleDefault;
+    self.navigationController.navigationBar.tintColor = nil;
+    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
+}
+
+- (void)reload {
+    [[YYImageCache sharedCache].memoryCache removeAllObjects];
+    [[YYImageCache sharedCache].diskCache removeAllObjectsWithBlock:nil];
+    [self.tableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.1];
+}
+
+- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
+    return NO;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return _imageLinks.count * 4;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return kCellHeight;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    YYWebImageExampleCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
+    if (!cell) cell = [[YYWebImageExampleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
+    [cell setImageURL:[NSURL URLWithString:_imageLinks[indexPath.row % _imageLinks.count]]];
+    return cell;
+}
+
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
+    CGFloat viewHeight = scrollView.height + scrollView.contentInset.top;
+    for (YYWebImageExampleCell *cell in [self.tableView visibleCells]) {
+        CGFloat y = cell.centerY - scrollView.contentOffset.y;
+        CGFloat p = y - viewHeight / 2;
+        CGFloat scale = cos(p / viewHeight * 0.8) * 0.95;
+        [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState animations:^{
+            cell.webImageView.transform = CGAffineTransformMakeScale(scale, scale);
+        } completion:NULL];
+    }
+}
+
+@end

BIN
Demo/YYWebImageDemo/cube@2x.png


BIN
Demo/YYWebImageDemo/google@2x.webp


+ 16 - 0
Demo/YYWebImageDemo/main.m

@@ -0,0 +1,16 @@
+//
+//  main.m
+//  YYWebImageDemo
+//
+//  Created by guoyaoyuan on 15/10/30.
+//  Copyright © 2015年 ibireme. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+    }
+}

BIN
Demo/YYWebImageDemo/mew_baseline.gif


BIN
Demo/YYWebImageDemo/mew_baseline.jpg


BIN
Demo/YYWebImageDemo/mew_baseline.png


BIN
Demo/YYWebImageDemo/mew_interlaced.gif


BIN
Demo/YYWebImageDemo/mew_interlaced.png


BIN
Demo/YYWebImageDemo/mew_progressive.jpg


BIN
Demo/YYWebImageDemo/niconiconi@2x.gif


BIN
Demo/YYWebImageDemo/nyancat@2x.webp


BIN
Demo/YYWebImageDemo/pia@2x.png


BIN
Demo/YYWebImageDemo/wall-e@2x.webp


+ 20 - 22
Framework/YYWebImage-Static.xcodeproj/project.pbxproj

@@ -8,42 +8,42 @@
 
 /* Begin PBXBuildFile section */
 		D9753A1B1BD3BBE600C6F4B8 /* YYCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D97539F41BD3BBE600C6F4B8 /* YYCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A1C1BD3BBE600C6F4B8 /* YYCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539F51BD3BBE600C6F4B8 /* YYCache.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A1C1BD3BBE600C6F4B8 /* YYCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539F51BD3BBE600C6F4B8 /* YYCache.m */; };
 		D9753A1D1BD3BBE600C6F4B8 /* YYDiskCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D97539F61BD3BBE600C6F4B8 /* YYDiskCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A1E1BD3BBE600C6F4B8 /* YYDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539F71BD3BBE600C6F4B8 /* YYDiskCache.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A1E1BD3BBE600C6F4B8 /* YYDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539F71BD3BBE600C6F4B8 /* YYDiskCache.m */; };
 		D9753A1F1BD3BBE600C6F4B8 /* YYKVStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = D97539F81BD3BBE600C6F4B8 /* YYKVStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A201BD3BBE600C6F4B8 /* YYKVStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539F91BD3BBE600C6F4B8 /* YYKVStorage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A201BD3BBE600C6F4B8 /* YYKVStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539F91BD3BBE600C6F4B8 /* YYKVStorage.m */; };
 		D9753A211BD3BBE600C6F4B8 /* YYMemoryCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D97539FA1BD3BBE600C6F4B8 /* YYMemoryCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A221BD3BBE600C6F4B8 /* YYMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539FB1BD3BBE600C6F4B8 /* YYMemoryCache.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A221BD3BBE600C6F4B8 /* YYMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539FB1BD3BBE600C6F4B8 /* YYMemoryCache.m */; };
 		D9753A231BD3BBE600C6F4B8 /* _YYWebImageSetter.h in Headers */ = {isa = PBXBuildFile; fileRef = D97539FD1BD3BBE600C6F4B8 /* _YYWebImageSetter.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		D9753A241BD3BBE600C6F4B8 /* _YYWebImageSetter.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539FE1BD3BBE600C6F4B8 /* _YYWebImageSetter.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A241BD3BBE600C6F4B8 /* _YYWebImageSetter.m in Sources */ = {isa = PBXBuildFile; fileRef = D97539FE1BD3BBE600C6F4B8 /* _YYWebImageSetter.m */; };
 		D9753A251BD3BBE600C6F4B8 /* CALayer+YYWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D97539FF1BD3BBE600C6F4B8 /* CALayer+YYWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A261BD3BBE600C6F4B8 /* CALayer+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A001BD3BBE600C6F4B8 /* CALayer+YYWebImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A261BD3BBE600C6F4B8 /* CALayer+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A001BD3BBE600C6F4B8 /* CALayer+YYWebImage.m */; };
 		D9753A271BD3BBE600C6F4B8 /* MKAnnotationView+YYWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A011BD3BBE600C6F4B8 /* MKAnnotationView+YYWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A281BD3BBE600C6F4B8 /* MKAnnotationView+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A021BD3BBE600C6F4B8 /* MKAnnotationView+YYWebImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A281BD3BBE600C6F4B8 /* MKAnnotationView+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A021BD3BBE600C6F4B8 /* MKAnnotationView+YYWebImage.m */; };
 		D9753A291BD3BBE600C6F4B8 /* UIButton+YYWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A031BD3BBE600C6F4B8 /* UIButton+YYWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A2A1BD3BBE600C6F4B8 /* UIButton+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A041BD3BBE600C6F4B8 /* UIButton+YYWebImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A2A1BD3BBE600C6F4B8 /* UIButton+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A041BD3BBE600C6F4B8 /* UIButton+YYWebImage.m */; };
 		D9753A2B1BD3BBE600C6F4B8 /* UIImage+YYWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A051BD3BBE600C6F4B8 /* UIImage+YYWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A2C1BD3BBE600C6F4B8 /* UIImage+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A061BD3BBE600C6F4B8 /* UIImage+YYWebImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A2C1BD3BBE600C6F4B8 /* UIImage+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A061BD3BBE600C6F4B8 /* UIImage+YYWebImage.m */; };
 		D9753A2D1BD3BBE600C6F4B8 /* UIImageView+YYWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A071BD3BBE600C6F4B8 /* UIImageView+YYWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A2E1BD3BBE600C6F4B8 /* UIImageView+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A081BD3BBE600C6F4B8 /* UIImageView+YYWebImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A2E1BD3BBE600C6F4B8 /* UIImageView+YYWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A081BD3BBE600C6F4B8 /* UIImageView+YYWebImage.m */; };
 		D9753A2F1BD3BBE600C6F4B8 /* YYAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A0A1BD3BBE600C6F4B8 /* YYAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A301BD3BBE600C6F4B8 /* YYAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A0B1BD3BBE600C6F4B8 /* YYAnimatedImageView.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A301BD3BBE600C6F4B8 /* YYAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A0B1BD3BBE600C6F4B8 /* YYAnimatedImageView.m */; };
 		D9753A311BD3BBE600C6F4B8 /* YYFrameImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A0C1BD3BBE600C6F4B8 /* YYFrameImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A321BD3BBE600C6F4B8 /* YYFrameImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A0D1BD3BBE600C6F4B8 /* YYFrameImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A321BD3BBE600C6F4B8 /* YYFrameImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A0D1BD3BBE600C6F4B8 /* YYFrameImage.m */; };
 		D9753A331BD3BBE600C6F4B8 /* YYImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A0E1BD3BBE600C6F4B8 /* YYImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A341BD3BBE600C6F4B8 /* YYImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A0F1BD3BBE600C6F4B8 /* YYImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A341BD3BBE600C6F4B8 /* YYImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A0F1BD3BBE600C6F4B8 /* YYImage.m */; };
 		D9753A351BD3BBE600C6F4B8 /* YYImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A101BD3BBE600C6F4B8 /* YYImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A361BD3BBE600C6F4B8 /* YYImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A111BD3BBE600C6F4B8 /* YYImageCoder.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A361BD3BBE600C6F4B8 /* YYImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A111BD3BBE600C6F4B8 /* YYImageCoder.m */; };
 		D9753A371BD3BBE600C6F4B8 /* YYSpriteSheetImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A121BD3BBE600C6F4B8 /* YYSpriteSheetImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A381BD3BBE600C6F4B8 /* YYSpriteSheetImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A131BD3BBE600C6F4B8 /* YYSpriteSheetImage.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A381BD3BBE600C6F4B8 /* YYSpriteSheetImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A131BD3BBE600C6F4B8 /* YYSpriteSheetImage.m */; };
 		D9753A391BD3BBE600C6F4B8 /* YYImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A141BD3BBE600C6F4B8 /* YYImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A3A1BD3BBE600C6F4B8 /* YYImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A151BD3BBE600C6F4B8 /* YYImageCache.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A3A1BD3BBE600C6F4B8 /* YYImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A151BD3BBE600C6F4B8 /* YYImageCache.m */; };
 		D9753A3B1BD3BBE600C6F4B8 /* YYWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A161BD3BBE600C6F4B8 /* YYWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		D9753A3C1BD3BBE600C6F4B8 /* YYWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A171BD3BBE600C6F4B8 /* YYWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A3D1BD3BBE600C6F4B8 /* YYWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A181BD3BBE600C6F4B8 /* YYWebImageManager.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A3D1BD3BBE600C6F4B8 /* YYWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A181BD3BBE600C6F4B8 /* YYWebImageManager.m */; };
 		D9753A3E1BD3BBE600C6F4B8 /* YYWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = D9753A191BD3BBE600C6F4B8 /* YYWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		D9753A3F1BD3BBE600C6F4B8 /* YYWebImageOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A1A1BD3BBE600C6F4B8 /* YYWebImageOperation.m */; settings = {ASSET_TAGS = (); }; };
+		D9753A3F1BD3BBE600C6F4B8 /* YYWebImageOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = D9753A1A1BD3BBE600C6F4B8 /* YYWebImageOperation.m */; };
 		D9753A411BD3BE6400C6F4B8 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A401BD3BE6400C6F4B8 /* libsqlite3.tbd */; };
 		D9753A431BD3BE6800C6F4B8 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A421BD3BE6800C6F4B8 /* libz.tbd */; };
 		D9753A451BD3BE6C00C6F4B8 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A441BD3BE6C00C6F4B8 /* MobileCoreServices.framework */; };
@@ -53,7 +53,7 @@
 		D9753A4D1BD3BE8000C6F4B8 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A4C1BD3BE8000C6F4B8 /* ImageIO.framework */; };
 		D9753A4F1BD3BE8600C6F4B8 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A4E1BD3BE8600C6F4B8 /* CoreFoundation.framework */; };
 		D9753A511BD3BE8A00C6F4B8 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A501BD3BE8A00C6F4B8 /* UIKit.framework */; };
-		D9753A531BD3BE9D00C6F4B8 /* WebP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A521BD3BE9D00C6F4B8 /* WebP.framework */; settings = {ASSET_TAGS = (); }; };
+		D9753A531BD3BE9D00C6F4B8 /* WebP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9753A521BD3BE9D00C6F4B8 /* WebP.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -290,7 +290,7 @@
 		D97539D41BD3BB6F00C6F4B8 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0700;
+				LastUpgradeCheck = 0710;
 				ORGANIZATIONNAME = ibireme;
 				TargetAttributes = {
 					D97539DD1BD3BB6F00C6F4B8 = {
@@ -447,7 +447,6 @@
 		D97539ED1BD3BB6F00C6F4B8 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD)";
 				CONTENTS_FOLDER_PATH = "$(WRAPPER_NAME)/Versions/$(FRAMEWORK_VERSION)";
 				DEAD_CODE_STRIPPING = NO;
 				DYLIB_COMPATIBILITY_VERSION = 1;
@@ -472,7 +471,6 @@
 		D97539EE1BD3BB6F00C6F4B8 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD)";
 				CONTENTS_FOLDER_PATH = "$(WRAPPER_NAME)/Versions/$(FRAMEWORK_VERSION)";
 				DEAD_CODE_STRIPPING = NO;
 				DYLIB_COMPATIBILITY_VERSION = 1;

+ 8 - 2
YYWebImage/Cache/YYCache.h

@@ -1,6 +1,6 @@
 //
 //  YYCache.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/2/13.
 //  Copyright (c) 2015 ibireme.
@@ -11,7 +11,13 @@
 
 #import <Foundation/Foundation.h>
 
-#if __has_include(<YYWebImage/YYWebImage.h>)
+#if __has_include(<YYCache/YYCache.h>)
+FOUNDATION_EXPORT double YYCacheVersionNumber;
+FOUNDATION_EXPORT const unsigned char YYCacheVersionString[];
+#import <YYCache/YYMemoryCache.h>
+#import <YYCache/YYDiskCache.h>
+#import <YYCache/YYKVStorage.h>
+#elif __has_include(<YYWebImage/YYCache.h>)
 #import <YYWebImage/YYMemoryCache.h>
 #import <YYWebImage/YYDiskCache.h>
 #import <YYWebImage/YYKVStorage.h>

+ 1 - 1
YYWebImage/Cache/YYCache.m

@@ -1,6 +1,6 @@
 //
 //  YYCache.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/2/13.
 //  Copyright (c) 2015 ibireme.

+ 7 - 7
YYWebImage/Cache/YYDiskCache.h

@@ -1,6 +1,6 @@
 //
 //  YYDiskCache.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/2/11.
 //  Copyright (c) 2015 ibireme.
@@ -88,8 +88,8 @@
  The maximum number of objects the cache should hold.
  
  @discussion The default value is NSUIntegerMax, which means no limit.
- This is not a strict limit—if the cache goes over the limit, some objects in the
- cache could be evicted later in backgound queue.
+ This is not a strict limit  if the cache goes over the limit, some objects in the
+ cache could be evicted later in background queue.
  */
 @property (assign) NSUInteger countLimit;
 
@@ -97,8 +97,8 @@
  The maximum total cost that the cache can hold before it starts evicting objects.
  
  @discussion The default value is NSUIntegerMax, which means no limit.
- This is not a strict limit—if the cache goes over the limit, some objects in the
- cache could be evicted later in backgound queue.
+ This is not a strict limit  if the cache goes over the limit, some objects in the
+ cache could be evicted later in background queue.
  */
 @property (assign) NSUInteger costLimit;
 
@@ -106,8 +106,8 @@
  The maximum expiry time of objects in cache.
  
  @discussion The default value is DBL_MAX, which means no limit.
- This is not a strict limit—if an object goes over the limit, the objects could
- be evicted later in backgound queue.
+ This is not a strict limit  if an object goes over the limit, the objects could
+ be evicted later in background queue.
  */
 @property (assign) NSTimeInterval ageLimit;
 

+ 2 - 2
YYWebImage/Cache/YYDiskCache.m

@@ -1,6 +1,6 @@
 //
 //  YYDiskCache.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/2/11.
 //  Copyright (c) 2015 ibireme.
@@ -150,7 +150,7 @@ static NSString *_YYNSStringMD5(NSString *string) {
     _kv = kv;
     _path = path;
     _lock = dispatch_semaphore_create(1);
-    _queue = dispatch_queue_create("com.ibireme.yykit.cache.disk", DISPATCH_QUEUE_CONCURRENT);
+    _queue = dispatch_queue_create("com.ibireme.cache.disk", DISPATCH_QUEUE_CONCURRENT);
     _inlineThreshold = threshold;
     _countLimit = NSUIntegerMax;
     _costLimit = NSUIntegerMax;

+ 1 - 1
YYWebImage/Cache/YYKVStorage.h

@@ -1,6 +1,6 @@
 //
 //  YYKVStorage.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/4/22.
 //  Copyright (c) 2015 ibireme.

+ 2 - 2
YYWebImage/Cache/YYKVStorage.m

@@ -1,6 +1,6 @@
 //
 //  YYKVStorage.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/4/22.
 //  Copyright (c) 2015 ibireme.
@@ -651,7 +651,7 @@ static NSString *const kTrashDirectoryName = @"trash";
     _type = type;
     _dataPath = [path stringByAppendingPathComponent:kDataDirectoryName];
     _trashPath = [path stringByAppendingPathComponent:kTrashDirectoryName];
-    _trashQueue = dispatch_queue_create("com.ibireme.yykit.cache.disk.trash", DISPATCH_QUEUE_SERIAL);
+    _trashQueue = dispatch_queue_create("com.ibireme.cache.disk.trash", DISPATCH_QUEUE_SERIAL);
     _dbPath = [path stringByAppendingPathComponent:kDBFileName];
     _dbStateLock = OS_SPINLOCK_INIT;
     _errorLogsEnabled = YES;

+ 10 - 3
YYWebImage/Cache/YYMemoryCache.h

@@ -1,6 +1,6 @@
 //
 //  YYMemoryCache.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/2/7.
 //  Copyright (c) 2015 ibireme.
@@ -108,14 +108,21 @@
 @property (copy) void(^didEnterBackgroundBlock)(YYMemoryCache *cache);
 
 /**
- If `YES`, the key-value object will be released on main thread, otherwise on
- background thread. Default is NO. 
+ If `YES`, the key-value pair will be released on main thread, otherwise on
+ background thread. Default is NO.
  
  @discussion You may set this value to `YES` if the key-value object contains
  the instance which should be released in main thread (such as UIView/CALayer).
  */
 @property (assign) BOOL releaseOnMainThread;
 
+/**
+ If `YES`, the key-value pair will be released asynchronously to avoid blocking 
+ the access methods, otherwise it will be released in the access method  
+ (such as removeObjectForKey:). Default is YES.
+ */
+@property (assign) BOOL releaseAsynchronously;
+
 
 #pragma mark - Access Methods
 ///=============================================================================

+ 53 - 15
YYWebImage/Cache/YYMemoryCache.m

@@ -1,6 +1,6 @@
 //
 //  YYMemoryCache.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYCache <https://github.com/ibireme/YYCache>
 //
 //  Created by ibireme on 15/2/7.
 //  Copyright (c) 2015 ibireme.
@@ -14,6 +14,7 @@
 #import <CoreFoundation/CoreFoundation.h>
 #import <QuartzCore/QuartzCore.h>
 #import <libkern/OSAtomic.h>
+#import <pthread.h>
 
 #if __has_include("YYDispatchQueuePool.h")
 #import "YYDispatchQueuePool.h"
@@ -64,6 +65,7 @@ static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
     _YYLinkedMapNode *_head; // MRU, do not change it directly
     _YYLinkedMapNode *_tail; // LRU, do not change it directly
     BOOL _releaseOnMainThread;
+    BOOL _releaseAsynchronously;
 }
 
 /// Insert a node at head and update the total cost.
@@ -88,9 +90,11 @@ static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
 
 @implementation _YYLinkedMap
 
-- (instancetype) init{
+- (instancetype)init {
     self = [super init];
     _dic = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    _releaseOnMainThread = NO;
+    _releaseAsynchronously = YES;
     return self;
 }
 
@@ -160,10 +164,19 @@ static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
     if (CFDictionaryGetCount(_dic) > 0) {
         CFMutableDictionaryRef holder = _dic;
         _dic = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-        dispatch_queue_t queue = _releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
-        dispatch_async(queue, ^{
-            CFRelease(holder); // hold and release in specified queue
-        });
+        
+        if (_releaseAsynchronously) {
+            dispatch_queue_t queue = _releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
+            dispatch_async(queue, ^{
+                CFRelease(holder); // hold and release in specified queue
+            });
+        } else if (_releaseOnMainThread && !pthread_main_np()) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                CFRelease(holder); // hold and release in specified queue
+            });
+        } else {
+            CFRelease(holder);
+        }
     }
 }
 
@@ -322,7 +335,7 @@ static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
     self = super.init;
     _lock = OS_SPINLOCK_INIT;
     _lru = [_YYLinkedMap new];
-    _queue = dispatch_queue_create("com.ibireme.yykit.cache.memory", DISPATCH_QUEUE_SERIAL);
+    _queue = dispatch_queue_create("com.ibireme.cache.memory", DISPATCH_QUEUE_SERIAL);
     
     _countLimit = NSUIntegerMax;
     _costLimit = NSUIntegerMax;
@@ -371,6 +384,19 @@ static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
     OSSpinLockUnlock(&_lock);
 }
 
+- (BOOL)releaseAsynchronously {
+    OSSpinLockLock(&_lock);
+    BOOL releaseAsynchronously = _lru->_releaseAsynchronously;
+    OSSpinLockUnlock(&_lock);
+    return releaseAsynchronously;
+}
+
+- (void)setReleaseAsynchronously:(BOOL)releaseAsynchronously {
+    OSSpinLockLock(&_lock);
+    _lru->_releaseAsynchronously = releaseAsynchronously;
+    OSSpinLockUnlock(&_lock);
+}
+
 - (BOOL)containsObjectForKey:(id)key {
     if (!key) return NO;
     OSSpinLockLock(&_lock);
@@ -426,10 +452,16 @@ static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
     }
     if (_lru->_totalCount > _countLimit) {
         _YYLinkedMapNode *node = [_lru removeTailNode];
-        dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
-        dispatch_async(queue, ^{
-            [node class]; //hold and release in queue
-        });
+        if (_lru->_releaseAsynchronously) {
+            dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
+            dispatch_async(queue, ^{
+                [node class]; //hold and release in queue
+            });
+        } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [node class]; //hold and release in queue
+            });
+        }
     }
     OSSpinLockUnlock(&_lock);
 }
@@ -441,10 +473,16 @@ static inline dispatch_queue_t YYMemoryCacheGetReleaseQueue() {
     if (node) {
         [_lru removeNode:node];
         _YYLinkedMapNode *node = [_lru removeTailNode];
-        dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
-        dispatch_async(queue, ^{
-            [node class]; //release in queue
-        });
+        if (_lru->_releaseAsynchronously) {
+            dispatch_queue_t queue = _lru->_releaseOnMainThread ? dispatch_get_main_queue() : YYMemoryCacheGetReleaseQueue();
+            dispatch_async(queue, ^{
+                [node class]; //hold and release in queue
+            });
+        } else if (_lru->_releaseOnMainThread && !pthread_main_np()) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [node class]; //hold and release in queue
+            });
+        }
     }
     OSSpinLockUnlock(&_lock);
 }

+ 2 - 2
YYWebImage/Categories/_YYWebImageSetter.m

@@ -58,7 +58,7 @@ const NSTimeInterval _YYWebImageProgressiveFadeTime = 0.4;
     NSOperation *operation = [manager requestImageWithURL:imageURL options:options progress:progress transform:transform completion:completion];
     if (!operation && completion) {
         NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"YYWebImageOperation create failed." };
-        completion(nil, imageURL, YYWebImageFromNone, YYWebImageStageFinished, [NSError errorWithDomain:@"com.ibireme.yykit.webimage" code:-1 userInfo:userInfo]);
+        completion(nil, imageURL, YYWebImageFromNone, YYWebImageStageFinished, [NSError errorWithDomain:@"com.ibireme.webimage" code:-1 userInfo:userInfo]);
     }
     
     OSSpinLockLock(&_lock);
@@ -93,7 +93,7 @@ const NSTimeInterval _YYWebImageProgressiveFadeTime = 0.4;
     static dispatch_queue_t queue;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
-        queue = dispatch_queue_create("com.ibireme.yykit.webimage.setter", DISPATCH_QUEUE_SERIAL);
+        queue = dispatch_queue_create("com.ibireme.webimage.setter", DISPATCH_QUEUE_SERIAL);
         dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
     });
     return queue;

+ 1 - 1
YYWebImage/Image/YYAnimatedImageView.h

@@ -1,6 +1,6 @@
 //
 //  YYAnimatedImageView.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/19.
 //  Copyright (c) 2015 ibireme.

+ 1 - 1
YYWebImage/Image/YYAnimatedImageView.m

@@ -1,6 +1,6 @@
 //
 //  YYAnimatedImageView.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/19.
 //  Copyright (c) 2015 ibireme.

+ 4 - 2
YYWebImage/Image/YYFrameImage.h

@@ -1,6 +1,6 @@
 //
 //  YYFrameImage.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/12/9.
 //  Copyright (c) 2015 ibireme.
@@ -11,7 +11,9 @@
 
 #import <UIKit/UIKit.h>
 
-#if __has_include(<YYWebImage/YYWebImage.h>)
+#if __has_include(<YYImage/YYImage.h>)
+#import <YYImage/YYAnimatedImageView.h>
+#elif __has_include(<YYWebImage/YYImage.h>)
 #import <YYWebImage/YYAnimatedImageView.h>
 #else
 #import "YYAnimatedImageView.h"

+ 1 - 1
YYWebImage/Image/YYFrameImage.m

@@ -1,6 +1,6 @@
 //
 //  YYFrameImage.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/12/9.
 //  Copyright (c) 2015 ibireme.

+ 11 - 2
YYWebImage/Image/YYImage.h

@@ -1,6 +1,6 @@
 //
 //  YYImage.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/20.
 //  Copyright (c) 2015 ibireme.
@@ -11,7 +11,14 @@
 
 #import <UIKit/UIKit.h>
 
-#if __has_include(<YYWebImage/YYWebImage.h>)
+#if __has_include(<YYImage/YYImage.h>)
+FOUNDATION_EXPORT double YYImageVersionNumber;
+FOUNDATION_EXPORT const unsigned char YYImageVersionString[];
+#import <YYImage/YYFrameImage.h>
+#import <YYImage/YYSpriteSheetImage.h>
+#import <YYImage/YYImageCoder.h>
+#import <YYImage/YYAnimatedImageView.h>
+#elif __has_include(<YYWebImage/YYImage.h>)
 #import <YYWebImage/YYFrameImage.h>
 #import <YYWebImage/YYSpriteSheetImage.h>
 #import <YYWebImage/YYImageCoder.h>
@@ -24,6 +31,8 @@
 #endif
 
 
+
+
 /**
  A YYImage object is a high-level way to display animated image data.
  

+ 1 - 1
YYWebImage/Image/YYImage.m

@@ -1,6 +1,6 @@
 //
 //  YYImage.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 14/10/20.
 //  Copyright (c) 2015 ibireme.

+ 1 - 1
YYWebImage/Image/YYImageCoder.h

@@ -1,6 +1,6 @@
 //
 //  YYImageCoder.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/5/13.
 //  Copyright (c) 2015 ibireme.

+ 1 - 1
YYWebImage/Image/YYImageCoder.m

@@ -1,6 +1,6 @@
 //
 //  YYImageCoder.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/5/13.
 //  Copyright (c) 2015 ibireme.

+ 4 - 2
YYWebImage/Image/YYSpriteSheetImage.h

@@ -1,6 +1,6 @@
 //
 //  YYSpriteImage.h
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/4/21.
 //  Copyright (c) 2015 ibireme.
@@ -11,7 +11,9 @@
 
 #import <UIKit/UIKit.h>
 
-#if __has_include(<YYWebImage/YYWebImage.h>)
+#if __has_include(<YYImage/YYImage.h>)
+#import <YYImage/YYAnimatedImageView.h>
+#elif __has_include(<YYWebImage/YYImage.h>)
 #import <YYWebImage/YYAnimatedImageView.h>
 #else
 #import "YYAnimatedImageView.h"

+ 1 - 1
YYWebImage/Image/YYSpriteSheetImage.m

@@ -1,6 +1,6 @@
 //
 //  YYSpriteImage.m
-//  YYKit <https://github.com/ibireme/YYKit>
+//  YYImage <https://github.com/ibireme/YYImage>
 //
 //  Created by ibireme on 15/4/21.
 //  Copyright (c) 2015 ibireme.

+ 4 - 4
YYWebImage/YYWebImage.h

@@ -35,23 +35,23 @@ FOUNDATION_EXPORT const unsigned char YYWebImageVersionString[];
 
 #if __has_include(<YYImage/YYImage.h>)
 #import <YYImage/YYImage.h>
-#elif __has_include(YYWebImage/YYImage.h)
+#elif __has_include(<YYWebImage/YYImage.h>)
 #import <YYWebImage/YYImage.h>
 #import <YYWebImage/YYFrameImage.h>
 #import <YYWebImage/YYSpriteSheetImage.h>
-#import <YYWebImage/YYImageCocder.h>
+#import <YYWebImage/YYImageCoder.h>
 #import <YYWebImage/YYAnimatedImageView.h>
 #else
 #import "YYImage.h"
 #import "YYFrameImage.h"
 #import "YYSpriteSheetImage.h"
-#import "YYImageCocder.h"
+#import "YYImageCoder.h"
 #import "YYAnimatedImageView.h"
 #endif
 
 #if __has_include(<YYCache/YYCache.h>)
 #import <YYCache/YYCache.h>
-#elif __has_include(YYWebImage/YYCache.h)
+#elif __has_include(<YYWebImage/YYCache.h>)
 #import <YYWebImage/YYCache.h>
 #import <YYWebImage/YYMemoryCache.h>
 #import <YYWebImage/YYDiskCache.h>

+ 4 - 4
YYWebImage/YYWebImageOperation.m

@@ -149,7 +149,7 @@ static NSData *JPEGSOSMarker() {
 /// Network thread entry point.
 + (void)_networkThreadMain:(id)object {
     @autoreleasepool {
-        [[NSThread currentThread] setName:@"com.ibireme.yykit.webimage.request"];
+        [[NSThread currentThread] setName:@"com.ibireme.webimage.request"];
         NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
         [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
         [runLoop run];
@@ -186,11 +186,11 @@ static NSData *JPEGSOSMarker() {
         if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
             for (NSUInteger i = 0; i < queueCount; i++) {
                 dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
-                queues[i] = dispatch_queue_create("com.ibireme.yykit.decode", attr);
+                queues[i] = dispatch_queue_create("com.ibireme.image.decode", attr);
             }
         } else {
             for (NSUInteger i = 0; i < queueCount; i++) {
-                queues[i] = dispatch_queue_create("com.ibireme.yykit.decode", DISPATCH_QUEUE_SERIAL);
+                queues[i] = dispatch_queue_create("com.ibireme.image.decode", DISPATCH_QUEUE_SERIAL);
                 dispatch_set_target_queue(queues[i], dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
             }
         }
@@ -381,7 +381,7 @@ static NSData *JPEGSOSMarker() {
             _data = nil;
             NSError *error = nil;
             if (!image) {
-                error = [NSError errorWithDomain:@"com.ibireme.yykit.image" code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Web image decode fail." }];
+                error = [NSError errorWithDomain:@"com.ibireme.image" code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Web image decode fail." }];
             }
             if (_completion) _completion(image, _request.URL, YYWebImageFromRemote, YYWebImageStageFinished, error);
             [self _finish];