├── Demo
├── Tests
│ ├── Resources
│ │ ├── Image.jpg
│ │ ├── Image2.jpg
│ │ └── lhfer5lguvi76a9uedez.webp
│ ├── Source
│ │ ├── TDFTestingKit.h
│ │ ├── TDFMockResource.h
│ │ ├── TDFMockImageProcessor.h
│ │ ├── TDFMockFetchOperation.h
│ │ ├── TDFImageRequestOptions.m
│ │ ├── TDFTesting.h
│ │ ├── TDFImageRequest.m
│ │ ├── TDFCommonTests.h
│ │ ├── TDFMockImageCache.h
│ │ ├── TDFMockImageFetcher.h
│ │ ├── TDFMockImageProcessor.m
│ │ ├── TDFImageFormats.m
│ │ ├── TDFMockFetchOperation.m
│ │ ├── TDFMockFetcher.h
│ │ ├── TDFMockImageCache.m
│ │ ├── TDFMockResource.m
│ │ ├── TDFTesting.m
│ │ ├── TDFImageCache.m
│ │ ├── TDFMockImageFetcher.m
│ │ └── TDFMockFetcher.m
│ └── Info.plist
├── DFImageManager
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── icon.png
│ │ │ ├── icon-1.png
│ │ │ ├── icon-2.png
│ │ │ ├── icon-3.png
│ │ │ ├── icon-4.png
│ │ │ ├── icon-5.png
│ │ │ ├── icon-6.png
│ │ │ ├── icon@2x.png
│ │ │ ├── icon@3x.png
│ │ │ ├── icon@2x-1.png
│ │ │ ├── icon@2x-2.png
│ │ │ ├── icon@3x-1.png
│ │ │ └── Contents.json
│ ├── Resources
│ │ ├── 10669363.jpg
│ │ ├── 10849093.jpg
│ │ ├── 10861057.jpg
│ │ ├── 10872981.jpg
│ │ ├── 10915709.jpg
│ │ └── 10926234.jpg
│ ├── Source
│ │ ├── SDFMenuViewController.h
│ │ ├── SDFPhotos.h
│ │ ├── SDFAppDelegate.m
│ │ ├── SDFGIFDemoViewController.h
│ │ ├── SDFPhotosKitDemoViewController.h
│ │ ├── SDFAppDelegate.h
│ │ ├── SDFBuiltinNetworkingDemoViewController.h
│ │ ├── SDFProgressiveJPEGDemoViewController.h
│ │ ├── UIViewController+SDFImageManager.h
│ │ ├── SDFFilesystemDemoViewController.h
│ │ ├── SDFStickyHeaderCollectionViewFlowLayout.h
│ │ ├── SDFBaseCollectionViewController.h
│ │ ├── SDFNetworkingDemoCollectionViewController.h
│ │ ├── SDFImageCollectionViewCell.h
│ │ ├── SDFMomentHeaderCollectionReusableView.h
│ │ ├── UIViewController+SDFImageManager.m
│ │ ├── SDFBaseCollectionViewController.m
│ │ ├── SDFMomentHeaderCollectionReusableView.m
│ │ ├── SDFFilesystemDemoViewController.m
│ │ ├── SDFStickyHeaderCollectionViewFlowLayout.m
│ │ ├── SDFImageCollectionViewCell.m
│ │ ├── SDFBuiltinNetworkingDemoViewController.m
│ │ ├── Launch Screen.xib
│ │ ├── SDFProgressiveJPEGDemoViewController.m
│ │ ├── SDFMomentHeaderCollectionReusableView.xib
│ │ └── SDFGIFDemoViewController.m
│ ├── main.m
│ ├── Info.plist
│ └── Base.lproj
│ │ └── Launch Screen.xib
├── DFImageManager.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── DFImageManager-Example.xcscheme
├── DFImageManager.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Podfile
├── Pod
├── Source
│ ├── WebP
│ │ ├── DFImageManagerKit+WebP.h
│ │ ├── DFWebPImageDecoder.h
│ │ └── DFWebPImageDecoder.m
│ ├── AFNetworking
│ │ ├── DFImageManagerKit+AFNetworking.h
│ │ └── DFAFImageFetcher.h
│ ├── PhotosKit
│ │ ├── DFImageManagerKit+PhotosKit.h
│ │ ├── DFPhotosKitImageFetcher.h
│ │ ├── NSURL+DFPhotosKit.h
│ │ └── NSURL+DFPhotosKit.m
│ ├── GIF
│ │ ├── DFImageManagerKit+GIF.h
│ │ ├── DFAnimatedImageDecoder.h
│ │ ├── DFAnimatedImage.m
│ │ ├── DFAnimatedImageProcessor.h
│ │ ├── DFAnimatedImageView.h
│ │ ├── DFAnimatedImage.h
│ │ ├── DFAnimatedImageDecoder.m
│ │ ├── DFAnimatedImageProcessor.m
│ │ └── DFAnimatedImageView.m
│ ├── UI
│ │ ├── DFImageManagerKit+UI.h
│ │ ├── DFImageRequest+UIKitAdditions.h
│ │ ├── DFImageRequest+UIKitAdditions.m
│ │ ├── UIImageView+DFImageManager.h
│ │ ├── DFImageView.h
│ │ ├── UIImageView+DFImageManager.m
│ │ ├── DFCollectionViewPreheatingController.h
│ │ └── DFImageView.m
│ └── Core
│ │ ├── Support
│ │ ├── DFImageManagerDefines.m
│ │ ├── DFImageResponse.m
│ │ ├── DFImageTask.m
│ │ ├── DFImageResponse.h
│ │ ├── DFImageRequest.m
│ │ ├── DFImageManagerDefines.h
│ │ ├── DFImageRequestOptions.m
│ │ ├── DFImageRequest.h
│ │ ├── DFImageTask.h
│ │ └── DFImageRequestOptions.h
│ │ ├── Caching
│ │ ├── NSCache+DFImageManager.h
│ │ ├── DFCachedImageResponse.m
│ │ ├── DFImageCache.h
│ │ ├── DFCachedImageResponse.h
│ │ ├── NSCache+DFImageManager.m
│ │ └── DFImageCache.m
│ │ ├── Protocols
│ │ ├── DFImageDecoding.h
│ │ ├── DFImageFetchingOperation.h
│ │ ├── DFImageCaching.h
│ │ ├── DFImageProcessing.h
│ │ ├── DFImageFetching.h
│ │ └── DFImageManaging.h
│ │ ├── Processing
│ │ ├── DFImageDecoder.h
│ │ ├── DFImageProcessor.h
│ │ ├── UIImage+DFImageUtilities.h
│ │ ├── DFImageDecoder.m
│ │ ├── DFImageProcessor.m
│ │ └── UIImage+DFImageUtilities.m
│ │ ├── Fetching
│ │ ├── DFURLResponseValidating.h
│ │ ├── DFURLHTTPResponseValidator.h
│ │ ├── DFURLHTTPResponseValidator.m
│ │ └── DFURLImageFetcher.h
│ │ ├── Private
│ │ ├── DFProgressiveImageDecoder.h
│ │ ├── DFImageManagerLoader.h
│ │ └── DFProgressiveImageDecoder.m
│ │ ├── DFImageManagerKit.h
│ │ └── Managing
│ │ ├── DFCompositeImageManager.h
│ │ ├── DFImageManager+Convenience.m
│ │ ├── DFImageManagerConfiguration.m
│ │ ├── DFImageManagerConfiguration.h
│ │ ├── DFImageManager.h
│ │ ├── DFImageManager+SharedManager.m
│ │ └── DFCompositeImageManager.m
├── Supporting Files
│ ├── DFImageManager.modulemap
│ ├── DFImageManager-umbrella.h
│ └── Info.plist
└── DFImageManager.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ └── xcschemes
│ └── DFImageManager.xcscheme
├── .cocoadocs.yml
├── .gitignore
├── LICENSE
└── DFImageManager.podspec
/Demo/Tests/Resources/Image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/Tests/Resources/Image.jpg
--------------------------------------------------------------------------------
/Demo/Tests/Resources/Image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/Tests/Resources/Image2.jpg
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Demo/DFImageManager/Resources/10669363.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Resources/10669363.jpg
--------------------------------------------------------------------------------
/Demo/DFImageManager/Resources/10849093.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Resources/10849093.jpg
--------------------------------------------------------------------------------
/Demo/DFImageManager/Resources/10861057.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Resources/10861057.jpg
--------------------------------------------------------------------------------
/Demo/DFImageManager/Resources/10872981.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Resources/10872981.jpg
--------------------------------------------------------------------------------
/Demo/DFImageManager/Resources/10915709.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Resources/10915709.jpg
--------------------------------------------------------------------------------
/Demo/DFImageManager/Resources/10926234.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Resources/10926234.jpg
--------------------------------------------------------------------------------
/Demo/Tests/Resources/lhfer5lguvi76a9uedez.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/Tests/Resources/lhfer5lguvi76a9uedez.webp
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon.png
--------------------------------------------------------------------------------
/Pod/Source/WebP/DFImageManagerKit+WebP.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFWebPImageDecoder.h"
6 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-1.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-2.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-3.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-4.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-5.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon-6.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@2x.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@3x.png
--------------------------------------------------------------------------------
/Pod/Supporting Files/DFImageManager.modulemap:
--------------------------------------------------------------------------------
1 | framework module DFImageManager {
2 | umbrella header "DFImageManager-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@2x-1.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@2x-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@2x-2.png
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@3x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kean/DFImageManager/HEAD/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/icon@3x-1.png
--------------------------------------------------------------------------------
/Pod/Source/AFNetworking/DFImageManagerKit+AFNetworking.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFAFImageFetcher.h"
6 |
--------------------------------------------------------------------------------
/.cocoadocs.yml:
--------------------------------------------------------------------------------
1 | highlight-color: "#3758E1"
2 | highlight-dark-color: "#2740A9"
3 | darker-color: "#C6C6C6"
4 | darker-dark-color: "#A1A1A1"
5 | background-color: "#ECEDF0"
6 | alt-link-color: "#B7233F"
7 | warning-color: "#B80E3D"
--------------------------------------------------------------------------------
/Pod/Source/PhotosKit/DFImageManagerKit+PhotosKit.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFPhotosKitImageFetcher.h"
6 | #import "NSURL+DFPhotosKit.h"
7 |
--------------------------------------------------------------------------------
/Demo/DFImageManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Pod/DFImageManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFImageManagerKit+GIF.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFAnimatedImage.h"
6 | #import "DFAnimatedImageDecoder.h"
7 | #import "DFAnimatedImageProcessor.h"
8 | #import "DFAnimatedImageView.h"
9 |
--------------------------------------------------------------------------------
/Pod/Source/WebP/DFWebPImageDecoder.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import "DFImageDecoding.h"
7 |
8 | @interface DFWebPImageDecoder : NSObject
9 | @end
10 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImageDecoder.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import "DFImageDecoding.h"
7 |
8 | @interface DFAnimatedImageDecoder : NSObject
9 |
10 | @end
11 |
--------------------------------------------------------------------------------
/Pod/Source/UI/DFImageManagerKit+UI.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageRequest+UIKitAdditions.h"
6 | #import "DFCollectionViewPreheatingController.h"
7 | #import "DFImageView.h"
8 | #import "UIImageView+DFImageManager.h"
9 |
--------------------------------------------------------------------------------
/Demo/DFImageManager.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Demo/DFImageManager.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageManagerDefines.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 |
7 | CGSize const DFImageMaximumSize = { FLT_MAX, FLT_MAX };
8 |
9 | NSString *const DFImageManagerErrorDomain = @"DFImageManagerErrorDomain";
10 |
--------------------------------------------------------------------------------
/Pod/DFImageManager.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFMenuViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 12/22/14.
6 | // Copyright (c) 2014 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SDFMenuViewController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFPhotos.h:
--------------------------------------------------------------------------------
1 | //
2 | // SFDPhotos.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 10/09/15.
6 | // Copyright © 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SDFPhotos : NSObject
12 |
13 | + (NSArray /* NSURL */ *)URLsForSmallPhotos;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 12/22/14.
6 | // Copyright (c) 2014 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFAppDelegate.h"
10 |
11 | @interface SDFAppDelegate ()
12 |
13 | @end
14 |
15 | @implementation SDFAppDelegate
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFGIFDemoViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFGIFSampleViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 3/5/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SDFGIFDemoViewController : UICollectionViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Pod/Source/UI/DFImageRequest+UIKitAdditions.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageRequest.h"
6 |
7 | @interface DFImageRequest (UIKitAdditions)
8 |
9 | /*! Returns image target size (in pixels) for a given view.
10 | */
11 | + (CGSize)targetSizeForView:(nonnull UIView *)view;
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFPhotosKitDemoViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFPhotosKitSampleViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 12/23/14.
6 | // Copyright (c) 2014 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SDFPhotosKitDemoViewController : UICollectionViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 12/22/14.
6 | // Copyright (c) 2014 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SDFAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFBuiltinNetworkingDemoViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFAFNetworkingDemoViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 3/8/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFBaseCollectionViewController.h"
10 |
11 | @interface SDFBuiltinNetworkingDemoViewController : SDFBaseCollectionViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFProgressiveJPEGDemoViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFProgressiveJPEGDemoViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 14/08/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFBaseCollectionViewController.h"
10 |
11 | @interface SDFProgressiveJPEGDemoViewController : SDFBaseCollectionViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/UIViewController+SDFImageManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+SDFImageManager.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/5/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIViewController (SDFImageManager)
12 |
13 | - (UIActivityIndicatorView *)df_showActivityIndicatorView;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFFilesystemDemoViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFFilesystemDemoViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/7/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFBaseCollectionViewController.h"
10 | #import
11 |
12 | @interface SDFFilesystemDemoViewController : SDFBaseCollectionViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 10/09/15.
6 | // Copyright © 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SDFAppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([SDFAppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFStickyHeaderCollectionViewFlowLayout.h:
--------------------------------------------------------------------------------
1 | //
2 | // DFStickyHeaderCollectionViewFlowLayout.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/8/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | static NSInteger const kStickyHeaderZIndex = 1024;
12 |
13 | @interface SDFStickyHeaderCollectionViewFlowLayout : UICollectionViewFlowLayout
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Pod/Supporting Files/DFImageManager-umbrella.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 |
7 | //! Project version number for DFImageManager.
8 | FOUNDATION_EXPORT double DFImageManagerVersionNumber;
9 |
10 | //! Project version string for DFImageManager.
11 | FOUNDATION_EXPORT const unsigned char DFImageManagerVersionString[];
12 |
13 | #import "DFImageManagerKit.h"
14 | #import "DFImageManagerKit+UI.h"
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFBaseCollectionViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFBaseCollectionViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/7/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SDFBaseCollectionViewController : UICollectionViewController
12 |
13 | @property (nonatomic) NSInteger numberOfItemsPerRow;
14 |
15 | - (instancetype)init;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFTestingKit.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFTestingKit.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 2/28/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFTesting.h"
10 | #import "TDFMockResource.h"
11 | #import "TDFMockImageFetcher.h"
12 | #import "TDFMockFetcher.h"
13 | #import "TDFMockFetchOperation.h"
14 | #import "TDFMockImageProcessor.h"
15 | #import "TDFMockImageCache.h"
16 | #import "TDFCommonTests.h"
17 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageResponse.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageResponse.h"
6 |
7 | @implementation DFImageResponse
8 |
9 | - (nonnull instancetype)initWithInfo:(nullable NSDictionary *)info isFastResponse:(BOOL)isFastResponse {
10 | if (self = [super init]) {
11 | _info = info;
12 | _isFastResponse = isFastResponse;
13 | }
14 | return self;
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Pod/Source/UI/DFImageRequest+UIKitAdditions.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageRequest+UIKitAdditions.h"
6 |
7 | @implementation DFImageRequest (UIKitAdditions)
8 |
9 | + (CGSize)targetSizeForView:(nonnull UIView *)view {
10 | CGSize size = view.bounds.size;
11 | CGFloat scale = [UIScreen mainScreen].scale;
12 | return CGSizeMake(size.width * scale, size.height * scale);
13 | }
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Caching/NSCache+DFImageManager.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 |
7 | @interface NSCache (DFImageManager)
8 |
9 | /*! Returns shared image cache with a recommended total cost limit.
10 | */
11 | + (nonnull NSCache *)df_sharedImageCache;
12 |
13 | /*! Returns recommended total cost limit in bytes.
14 | */
15 | + (NSUInteger)df_recommendedTotalCostLimit;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Protocols/DFImageDecoding.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | /*! Defines methods for image decoding.
9 | */
10 | @protocol DFImageDecoding
11 |
12 | /*! Creates and returns an image object that uses the specified image data.
13 | */
14 | - (nullable UIImage *)imageWithData:(nonnull NSData *)data partial:(BOOL)partial;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Protocols/DFImageFetchingOperation.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 | #import
7 |
8 | @protocol DFImageFetchingOperation
9 |
10 | /*! Cancels image fetching operation.
11 | */
12 | - (void)cancelImageFetching;
13 |
14 | /*! Changes image fetching operation priority.
15 | */
16 | - (void)setImageFetchingPriority:(DFImageRequestPriority)priority;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockResource.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFResource.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 2/28/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TDFMockResource : NSObject
12 |
13 | @property (nonatomic, readonly) NSString *ID;
14 |
15 | - (instancetype)initWithID:(NSString *)ID NS_DESIGNATED_INITIALIZER;
16 |
17 | - (instancetype)init NS_UNAVAILABLE;
18 |
19 | + (instancetype)resourceWithID:(NSString *)ID;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFNetworkingDemoCollectionViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFCompositeSampleCollectionViewController.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 12/22/14.
6 | // Copyright (c) 2014 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFBaseCollectionViewController.h"
10 | #import
11 |
12 | @interface SDFNetworkingDemoCollectionViewController : SDFBaseCollectionViewController
13 |
14 | @property (nonatomic) BOOL allowsPreheating;
15 | @property (nonatomic) BOOL displaysPreheatingDetails;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFImageCollectionViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SDFImageCollectionViewCell.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 20/07/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class DFAnimatedImageView;
12 | @class DFImageRequest;
13 |
14 | @interface SDFImageCollectionViewCell : UICollectionViewCell
15 |
16 | @property (nonatomic, readonly) DFAnimatedImageView *imageView;
17 |
18 | - (void)setImageWithURL:(NSURL *)imageURL;
19 | - (void)setImageWithRequest:(DFImageRequest *)request;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockImageProcessor.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageProcessor.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 2/28/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "DFImageManagerKit.h"
10 | #import
11 |
12 | @interface UIImage (TDFMockImageProcessor)
13 |
14 | - (BOOL)tdf_isImageProcessed;
15 |
16 | @end
17 |
18 | /*! The mock implementation of DFImageProcessing protocol.
19 | */
20 | @interface TDFMockImageProcessor : NSObject
21 |
22 | @property (nonatomic) NSTimeInterval processingTime;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageTask.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageTask.h"
6 |
7 | @implementation DFImageTask
8 |
9 | - (DFImageTask *)resume {
10 | [NSException raise:NSInternalInconsistencyException format:@"Abstract method called %@", NSStringFromSelector(_cmd)];
11 | return self;
12 | }
13 |
14 | - (void)cancel {
15 | [NSException raise:NSInternalInconsistencyException format:@"Abstract method called %@", NSStringFromSelector(_cmd)];
16 | }
17 |
18 | - (id)copyWithZone:(NSZone *)zone {
19 | return self;
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImage.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFAnimatedImage.h"
6 |
7 | @implementation DFAnimatedImage
8 |
9 | - (instancetype)initWithAnimatedImage:(FLAnimatedImage *)animatedImage posterImage:(CGImageRef)posterImage posterImageScale:(CGFloat)posterImageScale posterImageOrientation:(UIImageOrientation)posterImageOrientation {
10 | if (self = [super initWithCGImage:posterImage scale:posterImageScale orientation:posterImageOrientation]) {
11 | _animatedImage = animatedImage;
12 | }
13 | return self;
14 | }
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockFetchOperation.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFMockFetchOperation.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/1/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class DFImageRequest;
13 |
14 | static NSString *const TDFMockFetchOperationWillCancelNotification = @"TDFMockFetchOperationWillCancelNotification";
15 |
16 | @interface TDFMockFetchOperation : NSBlockOperation
17 |
18 | @property (nonatomic) DFImageRequest *request;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Caching/DFCachedImageResponse.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFCachedImageResponse.h"
6 | #import "DFImageManagerDefines.h"
7 |
8 | @implementation DFCachedImageResponse
9 |
10 | DF_INIT_UNAVAILABLE_IMPL
11 |
12 | - (nullable instancetype)initWithImage:(nonnull UIImage *)image info:(nullable NSDictionary *)info expirationDate:(NSTimeInterval)expirationDate {
13 | if (self = [super init]) {
14 | _image = image;
15 | _info = info;
16 | _expirationDate = expirationDate;
17 | }
18 | return self;
19 | }
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 | .DS_Store
20 |
21 | # CocoaPods
22 | #
23 | # We recommend against adding the Pods directory to your .gitignore. However
24 | # you should judge for yourself, the pros and cons are mentioned at:
25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
26 | #
27 | # Pods/
28 |
29 | Pods/
30 | Podfile.lock
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImageProcessor.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import "DFImageProcessing.h"
7 |
8 | /*! Prevents processing of animated images.
9 | */
10 | @interface DFAnimatedImageProcessor : NSObject
11 |
12 | /*! Initialized animated image processor with an actual processor.
13 | */
14 | - (nonnull instancetype)initWithProcessor:(nonnull id)processor;
15 |
16 | /*! Unavailable initializer, please use designated initializer.
17 | */
18 | - (nullable instancetype)init NS_UNAVAILABLE;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFImageRequestOptions.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageRequestOptions.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/6/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFTestingKit.h"
10 | #import "DFImageManagerKit.h"
11 | #import
12 | #import
13 |
14 | @interface TDFImageRequestOptions : XCTestCase
15 |
16 | @end
17 |
18 | @implementation TDFImageRequestOptions
19 |
20 | - (void)testThatDefaultOptionsAreCreated {
21 | DFImageRequestOptions *options = [DFImageRequestOptions new];
22 | TDFAssertDefaultOptionsAreValid(options);
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Processing/DFImageDecoder.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import "DFImageDecoding.h"
7 |
8 | /*! Image decoder that supports multiple image formats not supported by UIImage.
9 | */
10 | @interface DFImageDecoder : NSObject
11 |
12 | @end
13 |
14 |
15 | /*! Composes image decoders.
16 | */
17 | @interface DFCompositeImageDecoder : NSObject
18 |
19 | /*! Initializes DFCompositeImageDecoder with an array of decoders.
20 | */
21 | - (nonnull instancetype)initWithDecoders:(nonnull NSArray > *)decoders;
22 |
23 | @end
--------------------------------------------------------------------------------
/Demo/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, "8.0"
2 |
3 | project "DFImageManager.xcodeproj"
4 |
5 | source "https://github.com/CocoaPods/Specs.git"
6 |
7 | target 'DFImageManager-Example' do
8 | pod "DFImageManager", :path => "../"
9 | pod "DFImageManager/AFNetworking", :path => "../"
10 | pod "DFImageManager/GIF", :path => "../"
11 | pod "DFImageManager/WebP", :path => "../"
12 | pod "DFImageManager/PhotosKit", :path => "../"
13 |
14 | pod "AFNetworking/UIKit", "~> 3.0"
15 | end
16 |
17 | target 'DFImageManager-Tests' do
18 | pod "DFImageManager", :path => "../"
19 | pod "DFImageManager/AFNetworking", :path => "../"
20 | pod "DFImageManager/GIF", :path => "../"
21 | pod "DFImageManager/WebP", :path => "../"
22 |
23 | pod "OHHTTPStubs"
24 | end
25 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFTesting.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFTesting.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 12/26/14.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | static inline BOOL
13 | TDFSystemVersionGreaterThanOrEqualTo(NSString *version) {
14 | return [[[UIDevice currentDevice] systemVersion] compare:version options:NSNumericSearch] != NSOrderedAscending;
15 | }
16 |
17 | @interface TDFTesting : NSObject
18 |
19 | + (NSURL *)testImageURL;
20 | + (UIImage *)testImage;
21 | + (NSData *)testImageData;
22 |
23 | + (UIImage *)testImage2;
24 | + (NSData *)testImageData2;
25 |
26 | + (void)stubRequestWithURL:(NSURL *)imageURL;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFMomentHeaderCollectionReusableView.h:
--------------------------------------------------------------------------------
1 | //
2 | // DFMomentHeaderCollectionReusableView.h
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/8/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SDFMomentHeaderCollectionReusableView : UICollectionReusableView
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *labelTopLeft;
14 | @property (weak, nonatomic) IBOutlet UILabel *labelBottomLeft;
15 | @property (weak, nonatomic) IBOutlet UILabel *labelBottomRight;
16 |
17 | @property (nonatomic) NSLayoutConstraint *labelTopLeftConstraintCenterVertically;
18 | @property (nonatomic) IBOutlet NSLayoutConstraint *labelTopLeftConstraintTopSpacing;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/Pod/Source/PhotosKit/DFPhotosKitImageFetcher.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageFetching.h"
6 |
7 | /*! The PHImageRequestOptionsVersion value for requesting an image asset with or without adjustments, used by the version property. Default value is PHImageRequestOptionsVersionCurrent.
8 | @note Should be put into DFImageRequestOptions userInfo dictionary.
9 | */
10 | extern NSString *__nonnull const DFPhotosKitVersionKey;
11 |
12 | /*! Image fetcher for Photos Kit framework. Supported resources: PHAsset, NSURL with scheme com.github.kean.photos-kit.
13 | @note Use methods of NSURL+DFPhotosKit category to construct URLs for PHAssets.
14 | */
15 | @interface DFPhotosKitImageFetcher : NSObject
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFImageRequest.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageRequest.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/6/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFTestingKit.h"
10 | #import "DFImageManagerKit.h"
11 | #import
12 | #import
13 |
14 | @interface TDFImageRequest : XCTestCase
15 |
16 | @end
17 |
18 | @implementation TDFImageRequest
19 |
20 | - (void)testThatDefaultsAreSet {
21 | DFImageRequest *request = [DFImageRequest requestWithResource:@"Resourse"];
22 | XCTAssertTrue(CGSizeEqualToSize(request.targetSize, DFImageMaximumSize));
23 | XCTAssertTrue(request.contentMode == DFImageContentModeAspectFill);
24 | TDFAssertDefaultOptionsAreValid(request.options);
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Protocols/DFImageCaching.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | @class DFCachedImageResponse;
9 |
10 | /*! Cache for storing image responses into memory.
11 | */
12 | @protocol DFImageCaching
13 |
14 | /*! Returns cached image response associated with a given key.
15 | */
16 | - (nullable DFCachedImageResponse *)cachedImageResponseForKey:(nullable id)key;
17 |
18 | /*! Stores cached image response for the given key.
19 | */
20 | - (void)storeImageResponse:(nullable DFCachedImageResponse *)cachedResponse forKey:(nullable id)key;
21 |
22 | /*! Removes all cached image responses.
23 | */
24 | - (void)removeAllObjects;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFCommonTests.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFCommonTests.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/6/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | /*! Validates that instance of DFImageRequestOptions class has all default options set propertly.
10 | */
11 | #define TDFAssertDefaultOptionsAreValid(options) \
12 | ({ \
13 | DFImageRequestOptions *opt = (options); \
14 | XCTAssertNotNil(opt); \
15 | XCTAssertEqual(opt.priority, DFImageRequestPriorityNormal); \
16 | XCTAssertEqual(opt.allowsNetworkAccess, YES); \
17 | XCTAssertEqual(opt.allowsClipping, NO); \
18 | XCTAssertEqual(opt.memoryCachePolicy, DFImageRequestCachePolicyDefault); \
19 | XCTAssertEqual(opt.expirationAge, 600.); \
20 | XCTAssertNil(opt.userInfo); \
21 | })
22 |
--------------------------------------------------------------------------------
/Demo/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Fetching/DFURLResponseValidating.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 |
7 | NS_ASSUME_NONNULL_BEGIN
8 |
9 | /*! Validation error domain.
10 | */
11 | static NSString *const DFURLValidationErrorDomain = @"DFURLValidationErrorDomain";
12 |
13 | /*! A URL response (NSURLResponse).
14 | */
15 | static NSString *const DFURLErrorInfoURLResponseKey = @"DFURLErrorInfoURLResponseKey";
16 |
17 | /*! The DFURLResponseValidating protocol is adopted by an object that validates image response.
18 | */
19 | @protocol DFURLResponseValidating
20 |
21 | /*! Validates response and data associated with it.
22 | */
23 | - (BOOL)isValidResponse:(nullable NSURLResponse *)response data:(nullable NSData *)data error:(NSError **)error;
24 |
25 | @end
26 |
27 | NS_ASSUME_NONNULL_END
28 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockImageCache.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageCache.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/1/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "DFImageManagerKit.h"
10 | #import
11 |
12 |
13 | static NSString *TDFMockImageCacheWillReturnCachedImageNotification = @"TDFMockImageCacheWillReturnCachedImageNotification";
14 | static NSString *TDFMockImageCacheImageKey = @"TDFMockImageCacheImageKey";
15 |
16 | /*! The DFImageCaching implementation that can be easily enabled and disabled, doesn't evict objects and provides other features required for testing.
17 | */
18 | @interface TDFMockImageCache : NSObject
19 |
20 | /*! Default value is NO.
21 | */
22 | @property (nonatomic) BOOL enabled;
23 | @property (nonatomic, readonly) NSMutableDictionary *responses;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Caching/DFImageCache.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageCaching.h"
6 | #import
7 |
8 | /*! Memory cache implementation built on top of NSCache. Adds cached entries expiration, automatic cleanup on memory warnings and more.
9 | */
10 | @interface DFImageCache : NSObject
11 |
12 | /*! Returns the cache that the DFImageCache was initialized with.
13 | */
14 | @property (nonnull, nonatomic, readonly) NSCache *cache;
15 |
16 | /*! Initializes image cache with an instance of NSCache class.
17 | */
18 | - (nonnull instancetype)initWithCache:(nonnull NSCache *)cache NS_DESIGNATED_INITIALIZER;
19 |
20 | /*! Returns cost for a given cached image response.
21 | */
22 | - (NSUInteger)costForImageResponse:(nonnull DFCachedImageResponse *)cachedResponse;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageResponse.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | /*! The DFImageResponse class represents an image response for a specified resource. DFImageResponse encapsulates the metadata associated with a load.
9 | */
10 | @interface DFImageResponse : NSObject
11 |
12 | /*! Returns YES if response was returned using fast path, for instance from the memory cache.
13 | */
14 | @property (nonatomic, readonly) BOOL isFastResponse;
15 |
16 | /*! Returns the metadata associated with the load.
17 | */
18 | @property (nullable, nonatomic, readonly) NSDictionary *info;
19 |
20 | /*! Initializes response with a given parameters.
21 | */
22 | - (nonnull instancetype)initWithInfo:(nullable NSDictionary *)info isFastResponse:(BOOL)isFastResponse;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Processing/DFImageProcessor.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageProcessing.h"
6 | #import
7 | #import
8 |
9 | /*! NSNumber with float value that specifies a normalized image corner radius, where 0.5 is a corner radius that is half of the minimum image side. Should be put into DFImageRequestOptions userInfo dictionary.
10 | */
11 | extern NSString *__nonnull DFImageProcessingCornerRadiusKey;
12 |
13 | /*! The DFImageProcessor implements image decompression, scaling, cropping and more.
14 | */
15 | @interface DFImageProcessor : NSObject
16 |
17 | /*! If YES decoder would force image decompression, otherwise UIImage might delay decompression until the image is displayed. Default value is YES.
18 | */
19 | @property (nonatomic) BOOL shouldDecompressImages;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/Pod/Supporting Files/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 2.0.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Private/DFProgressiveImageDecoder.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 |
7 | @protocol DFImageDecoding;
8 |
9 | /*! Decodes received data at given thresholds. It would produce less decoded images if it can't keep up with the rate at which it receives data.
10 | @note Thread safe.
11 | */
12 | @interface DFProgressiveImageDecoder : NSObject
13 |
14 | - (nonnull instancetype)initWithQueue:(nonnull NSOperationQueue *)queue decoder:(nonnull id)decoder;
15 |
16 | @property (nonatomic) float threshold;
17 | @property (nonatomic) int64_t totalByteCount;
18 |
19 | - (void)appendData:(nullable NSData *)data;
20 |
21 | /*! Resumes decoding, safe to call multiple times.
22 | */
23 | - (void)resume;
24 | - (void)invalidate;
25 |
26 | @property (nullable, atomic, copy) void (^handler)(UIImage *__nonnull image);
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/Pod/Source/PhotosKit/NSURL+DFPhotosKit.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 |
7 | @class PHAsset;
8 |
9 | /*! The URL scheme used for accessing PHAsset objects.
10 | */
11 | static NSString *__nonnull const DFPhotosKitURLScheme = @"com.github.kean.photos-kit";
12 |
13 | /*! The NSURL category that adds methods for manipulating URLs with "com.github.kean.photos-kit" scheme.
14 | */
15 | @interface NSURL (DFPhotosKit)
16 |
17 | /*! Returns NSURL with a given local identifier for asset.
18 | */
19 | + (nullable NSURL *)df_assetURLWithAssetLocalIdentifier:(nullable NSString *)localIdentifier;
20 |
21 | /*! Returns NSURL with a local identifier for a given asset.
22 | */
23 | + (nullable NSURL *)df_assetURLWithAsset:(nullable PHAsset *)asset;
24 |
25 | /*! Returns local identifier from a given URL.
26 | */
27 | - (nullable NSString *)df_assetLocalIdentifier;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/Pod/Source/Core/DFImageManagerKit.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 |
7 | #import "DFImageManaging.h"
8 | #import "DFImageFetching.h"
9 | #import "DFImageFetchingOperation.h"
10 | #import "DFImageCaching.h"
11 | #import "DFImageProcessing.h"
12 | #import "DFImageDecoding.h"
13 |
14 | #import "DFImageManager.h"
15 | #import "DFImageManagerConfiguration.h"
16 | #import "DFCompositeImageManager.h"
17 |
18 | #import "DFImageTask.h"
19 | #import "DFImageRequest.h"
20 | #import "DFImageRequestOptions.h"
21 | #import "DFImageResponse.h"
22 |
23 | #import "DFImageCache.h"
24 | #import "DFCachedImageResponse.h"
25 | #import "NSCache+DFImageManager.h"
26 |
27 | #import "DFImageDecoder.h"
28 | #import "DFImageProcessor.h"
29 | #import "UIImage+DFImageUtilities.h"
30 |
31 | #import "DFURLHTTPResponseValidator.h"
32 | #import "DFURLImageFetcher.h"
33 | #import "DFURLResponseValidating.h"
34 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImageView.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageView.h"
6 | #import
7 |
8 | /*! The DFAnimatedImageView uses FLAnimatedImageView to enable animated GIF playback.
9 | @note The playback is enabled by default and can be disabled using allowsGIFPlayback property.
10 | */
11 | @interface DFAnimatedImageView : DFImageView
12 |
13 | /*! Inner animated image view used for GIF playback.
14 | */
15 | @property (nonnull, nonatomic, readonly) FLAnimatedImageView *animatedImageView;
16 |
17 | /*! If the value is YES the receiver will start a GIF playback as soon as the image is displayed. Default value is YES.
18 | */
19 | @property (nonatomic) BOOL allowsGIFPlayback;
20 |
21 | /*! Displays a given image. Automatically starts GIF playback when given a DFAnimatedImage object and when the GIF playback is enabled.
22 | */
23 | - (void)displayImage:(nullable UIImage *)image;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockImageFetcher.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageFetcher.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 2/28/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "DFImageManagerKit.h"
10 | #import
11 |
12 | extern NSString *TDFMockImageFetcherDidStartOperationNotification;
13 | extern NSString *TDFMockImageFetcherRequestKey;
14 | extern NSString *TDFMockImageFetcherOperationKey;
15 |
16 | /*! The mock implementation of DFImageFetching protocol.
17 | @note Supports resources of TDFResource class.
18 | @note Uses TDFMockFetchOperation class for fetch operations.
19 | */
20 | @interface TDFMockImageFetcher : NSObject
21 |
22 | @property (nonatomic) NSOperationQueue *queue;
23 |
24 | @property (nonatomic) NSData *data;
25 | @property (nonatomic) NSError *error;
26 | @property (nonatomic) NSDictionary *info;
27 |
28 | // For assertions
29 | @property (nonatomic, readonly) NSInteger createdOperationCount;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockImageProcessor.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageProcessor.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 2/28/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFMockImageProcessor.h"
10 | #import
11 |
12 | static char *_imageProcessedKey;
13 |
14 | @implementation UIImage (TDFMockImageProcessor)
15 |
16 | - (BOOL)tdf_isImageProcessed {
17 | return [objc_getAssociatedObject(self, &_imageProcessedKey) boolValue];
18 | }
19 |
20 | @end
21 |
22 |
23 |
24 | @implementation TDFMockImageProcessor
25 |
26 | - (BOOL)isProcessingForRequestEquivalent:(DFImageRequest *)request1 toRequest:(DFImageRequest *)request2 {
27 | return CGSizeEqualToSize(request1.targetSize, request2.targetSize);
28 | }
29 |
30 | - (UIImage *)processedImage:(UIImage *)image forRequest:(DFImageRequest *)request partial:(BOOL)partial {
31 | objc_setAssociatedObject(image, &_imageProcessedKey, @YES, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
32 | return image;
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Fetching/DFURLHTTPResponseValidator.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFURLResponseValidating.h"
6 |
7 | /*! The DFURLHTTPResponseValidator performs response validation based on HTTP status code and content type.
8 | */
9 | @interface DFURLHTTPResponseValidator : NSObject
10 |
11 | /*! The acceptable HTTP status codes for responses. For more info see the HTTP specification http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
12 | @note All status codes are acceptable in case acceptableStatusCodes is nil.
13 | */
14 | @property (nullable, nonatomic, copy) NSIndexSet *acceptableStatusCodes;
15 |
16 | /*! The acceptable MIME types for responses. Default value is nil so that all content types are supported. Image initialization never crashes when provided with an invalid data.
17 | @note All content types are acceptable in case acceptableContentTypes is nil.
18 | */
19 | @property (nullable, nonatomic, copy) NSSet *acceptableContentTypes;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImage.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | /*! The DFAnimatedImage subclasses UIImage and represents a poster image for the underlying animated image. It can be used anywhere where a regular `UIImage` can be used.
9 | */
10 | @interface DFAnimatedImage : UIImage
11 |
12 | /* The animated image that the receiver was initialized with. An `FLAnimatedImage`'s job is to deliver frames in a highly performant way and works in conjunction with `FLAnimatedImageView`.
13 | */
14 | @property (nonnull, nonatomic, readonly) FLAnimatedImage *animatedImage;
15 |
16 | /*! Initializes the DFAnimatedImage with an instance of FLAnimatedImage class and poster image.
17 | */
18 | - (nonnull instancetype)initWithAnimatedImage:(nonnull FLAnimatedImage *)animatedImage posterImage:(nonnull CGImageRef)posterImage posterImageScale:(CGFloat)posterImageScale posterImageOrientation:(UIImageOrientation)posterImageOrientation NS_DESIGNATED_INITIALIZER;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Caching/DFCachedImageResponse.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | /*! Wrapper for image responses stored in the framework's memory caching system.
9 | */
10 | @interface DFCachedImageResponse : NSObject
11 |
12 | /*! Returns response image.
13 | */
14 | @property (nonnull, nonatomic, readonly) UIImage *image;
15 |
16 | /*! Returns response info.
17 | */
18 | @property (nullable, nonatomic, readonly) NSDictionary *info;
19 |
20 | /*! Returns the expiration date of the receiver.
21 | */
22 | @property (nonatomic, readonly) NSTimeInterval expirationDate;
23 |
24 | /*! Initializes the DFCachedImageResponse with the given image, info and expiration date.
25 | */
26 | - (nullable instancetype)initWithImage:(nonnull UIImage *)image info:( nullable NSDictionary *)info expirationDate:(NSTimeInterval)expirationDate NS_DESIGNATED_INITIALIZER;
27 |
28 | /*! Unavailable initializer, please use designated initializer.
29 | */
30 | - (nullable instancetype)init NS_UNAVAILABLE;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFImageFormats.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFWebP.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 19/07/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "DFImageManagerKit.h"
10 | #import "DFImageManagerKit+WebP.h"
11 | #import
12 | #import
13 |
14 | @interface TDFImageFormats : XCTestCase
15 |
16 | @end
17 |
18 | @implementation TDFImageFormats
19 |
20 | - (void)testThatWebPIsDecoded {
21 | NSData *data = [self _webpImageData];
22 | XCTAssertEqual(data.length, 118042);
23 | id decoder = [DFWebPImageDecoder new];
24 | UIImage *image = [decoder imageWithData:data partial:NO];
25 | XCTAssertNotNil(image);
26 | XCTAssertEqual(image.size.width, 768);
27 | XCTAssertEqual(image.size.height, 768);
28 | }
29 |
30 | #pragma mark -
31 |
32 | - (NSData *)_webpImageData {
33 | NSBundle *bundle = [NSBundle bundleForClass:[self class]];
34 | NSString *path = [bundle pathForResource:@"lhfer5lguvi76a9uedez" ofType:@"webp"];
35 | return [NSData dataWithContentsOfFile:path];
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockFetchOperation.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFMockFetchOperation.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/1/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFMockFetchOperation.h"
10 |
11 | static inline NSOperationQueuePriority _DFQueuePriorityForRequestPriority(DFImageRequestPriority priority) {
12 | switch (priority) {
13 | case DFImageRequestPriorityHigh: return NSOperationQueuePriorityHigh;
14 | case DFImageRequestPriorityNormal: return NSOperationQueuePriorityNormal;
15 | case DFImageRequestPriorityLow: return NSOperationQueuePriorityLow;
16 | }
17 | }
18 |
19 | @implementation TDFMockFetchOperation
20 |
21 | - (void)cancel {
22 | [[NSNotificationCenter defaultCenter] postNotificationName:TDFMockFetchOperationWillCancelNotification object:self];
23 | [super cancel];
24 | }
25 |
26 | - (void)cancelImageFetching {
27 | [self cancel];
28 | }
29 |
30 | - (void)setImageFetchingPriority:(DFImageRequestPriority)priority {
31 | self.queuePriority = _DFQueuePriorityForRequestPriority(priority);
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockFetcher.h:
--------------------------------------------------------------------------------
1 | //
2 | // TDFMockResourceImageFetcher.h
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 11/07/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "DFImageManagerKit.h"
10 | #import
11 |
12 | extern NSString *TDFMockFetcherDidStartOperationNotification;
13 |
14 | @interface TDFMockResponse : NSObject
15 |
16 | @property (nonatomic) NSTimeInterval elapsedTime;
17 | @property (nonatomic) NSData *data;
18 | @property (nonatomic) NSError *error;
19 | @property (nonatomic) NSDictionary *info;
20 |
21 | + (instancetype)mockWithData:(NSData *)data;
22 | + (instancetype)mockWithData:(NSData *)data elapsedTime:(NSTimeInterval)elapsedTime;
23 | + (instancetype)mockWithError:(NSError *)error elapsedTime:(NSTimeInterval)elapsedTime;
24 |
25 | @end
26 |
27 | /*! Mock used for composite image task tests.
28 | */
29 | @interface TDFMockFetcher : NSObject
30 |
31 | @property (nonatomic, readonly) NSOperationQueue *queue;
32 |
33 | - (void)setResponse:(TDFMockResponse *)response forResource:(NSString *)resource;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Alexander Grebenyuk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Processing/UIImage+DFImageUtilities.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 | #import
7 |
8 | /*! Image utilities.
9 | */
10 | @interface UIImage (DFImageUtilities)
11 |
12 | /*! Returns scale that is required to fill/fit image in a target size, maintaining aspect ratio.
13 | */
14 | + (CGFloat)df_scaleForImage:(nullable UIImage *)image targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode;
15 |
16 | /*! Returns scaled decompressed image with a given image. Image decompression and scaling is made in a single step.
17 | */
18 | + (nullable UIImage *)df_decompressedImage:(nullable UIImage *)image scale:(CGFloat)scale;
19 |
20 | /*! Returns image cropped to a given normalized crop rect.
21 | */
22 | + (nullable UIImage *)df_croppedImage:(nullable UIImage *)image normalizedCropRect:(CGRect)cropRect;
23 |
24 | /*! Returns image by drawing rounded corners.
25 | @param cornerRadius corner radius in points.
26 | */
27 | + (nullable UIImage *)df_imageWithImage:(nullable UIImage *)image cornerRadius:(CGFloat)cornerRadius;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Caching/NSCache+DFImageManager.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "NSCache+DFImageManager.h"
6 | #import
7 |
8 | @implementation NSCache (DFImageManager)
9 |
10 | + (nonnull NSCache *)df_sharedImageCache {
11 | static NSCache *cache;
12 | static dispatch_once_t onceToken;
13 | dispatch_once(&onceToken, ^{
14 | cache = [NSCache new];
15 | cache.totalCostLimit = [self df_recommendedTotalCostLimit];
16 | });
17 | return cache;
18 | }
19 |
20 | + (NSUInteger)df_recommendedTotalCostLimit {
21 | static NSUInteger recommendedSize;
22 | static dispatch_once_t onceToken;
23 | dispatch_once(&onceToken, ^{
24 | #if TARGET_OS_WATCH
25 | recommendedSize = 1024 * 1024 * 20; /* 20 Mb */
26 | #else
27 | NSProcessInfo *info = [NSProcessInfo processInfo];
28 | CGFloat ratio = info.physicalMemory <= (1024 * 1024 * 512 /* 512 Mb */) ? 0.1f : 0.2f;
29 | recommendedSize = (NSUInteger)MAX(1024 * 1024 * 50 /* 50 Mb */, info.physicalMemory * ratio);
30 | #endif
31 | });
32 | return recommendedSize;
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Pod/Source/PhotosKit/NSURL+DFPhotosKit.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "NSURL+DFPhotosKit.h"
6 | #import
7 |
8 | @implementation NSURL (DFPhotosKit)
9 |
10 | + (NSURL *)df_assetURLWithAssetLocalIdentifier:(NSString *)localIdentifier {
11 | NSURLComponents *components = [NSURLComponents new];
12 | components.scheme = DFPhotosKitURLScheme;
13 | components.host = @"photos";
14 | components.path = [NSString stringWithFormat:@"/asset"];
15 | components.queryItems = @[[NSURLQueryItem queryItemWithName:@"local_identifier" value:localIdentifier]];
16 | return components.URL;
17 | }
18 |
19 | + (NSURL *)df_assetURLWithAsset:(PHAsset *)asset {
20 | return [self df_assetURLWithAssetLocalIdentifier:asset.localIdentifier];
21 | }
22 |
23 | - (NSString *)df_assetLocalIdentifier {
24 | NSURLComponents *components = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO];
25 | NSURLQueryItem *queryItem = [components.queryItems filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name=%@", @"local_identifier"]].firstObject;
26 | return queryItem.value;
27 | }
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/UIViewController+SDFImageManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+SDFImageManager.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/5/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+SDFImageManager.h"
10 |
11 | @implementation UIViewController (SDFImageManager)
12 |
13 | - (UIActivityIndicatorView *)df_showActivityIndicatorView {
14 | UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
15 | indicator.translatesAutoresizingMaskIntoConstraints = NO;
16 | [indicator startAnimating];
17 | [self.view addSubview:indicator];
18 | [self.view addConstraint:[NSLayoutConstraint constraintWithItem:indicator attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f]];
19 | [self.view addConstraint:[NSLayoutConstraint constraintWithItem:indicator attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.f constant:0.f]];
20 | return indicator;
21 | }
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageRequest.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageRequest.h"
6 | #import "DFImageRequestOptions.h"
7 |
8 | @implementation DFImageRequest
9 |
10 | DF_INIT_UNAVAILABLE_IMPL
11 |
12 | - (nonnull instancetype)initWithResource:(nonnull id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options {
13 | if (self = [super init]) {
14 | _resource = resource;
15 | _targetSize = targetSize;
16 | _contentMode = contentMode;
17 | _options = options ?: [DFImageRequestOptions new];
18 | }
19 | return self;
20 | }
21 |
22 | + (nonnull instancetype)requestWithResource:(nonnull id)resource {
23 | return [[[self class] alloc] initWithResource:resource targetSize:DFImageMaximumSize contentMode:DFImageContentModeAspectFill options:nil];
24 | }
25 |
26 | + (nonnull instancetype)requestWithResource:(nonnull id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options {
27 | return [[[self class] alloc] initWithResource:resource targetSize:targetSize contentMode:contentMode options:options];
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Processing/DFImageDecoder.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageDecoder.h"
6 |
7 | #if TARGET_OS_WATCH
8 | #import
9 | #endif
10 |
11 | @implementation DFImageDecoder
12 |
13 | - (nullable UIImage *)imageWithData:(nonnull NSData *)data partial:(BOOL)partial {
14 | #if TARGET_OS_IOS && !TARGET_OS_WATCH
15 | return [UIImage imageWithData:data scale:[UIScreen mainScreen].scale];
16 | #else
17 | return [UIImage imageWithData:data scale:[WKInterfaceDevice currentDevice].screenScale];
18 | #endif
19 | }
20 |
21 | @end
22 |
23 |
24 | @implementation DFCompositeImageDecoder {
25 | NSArray > *_decoders;
26 | }
27 |
28 | - (instancetype)initWithDecoders:(NSArray> *)decoders {
29 | if (self = [super init]) {
30 | _decoders = [NSArray arrayWithArray:decoders];
31 | }
32 | return self;
33 | }
34 |
35 | - (UIImage *)imageWithData:(NSData *)data partial:(BOOL)partial {
36 | for (id decoder in _decoders) {
37 | UIImage *image = [decoder imageWithData:data partial:partial];
38 | if (image) {
39 | return image;
40 | }
41 | }
42 | return nil;
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockImageCache.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageCache.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/1/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFMockImageCache.h"
10 |
11 | @implementation TDFMockImageCache
12 |
13 | - (instancetype)init {
14 | if (self = [super init]) {
15 | _enabled = NO;
16 | }
17 | return self;
18 | }
19 |
20 | - (void)setEnabled:(BOOL)enabled {
21 | if (_enabled != enabled) {
22 | _enabled = enabled;
23 | _responses = enabled ? [NSMutableDictionary new] : nil;
24 | }
25 | }
26 |
27 | - (DFCachedImageResponse *)cachedImageResponseForKey:(id)key {
28 | DFCachedImageResponse *response = [_responses objectForKey:key];
29 | if (response) {
30 | [[NSNotificationCenter defaultCenter] postNotificationName:TDFMockImageCacheWillReturnCachedImageNotification object:self userInfo:@{ TDFMockImageCacheImageKey : response.image }];
31 | }
32 | return response;
33 | }
34 |
35 | - (void)storeImageResponse:(DFCachedImageResponse *)cachedResponse forKey:(id)key {
36 | [_responses setObject:cachedResponse forKey:key];
37 | }
38 |
39 | - (void)removeAllObjects {
40 | [_responses removeAllObjects];
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImageDecoder.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFAnimatedImageDecoder.h"
6 | #import "DFAnimatedImage.h"
7 |
8 | @implementation DFAnimatedImageDecoder
9 |
10 | - (UIImage *)imageWithData:(NSData *)data partial:(BOOL)partial {
11 | if (![self _isGIFData:data]) {
12 | return nil;
13 | }
14 | FLAnimatedImage *animatedImage = [FLAnimatedImage animatedImageWithGIFData:data];
15 | if (!animatedImage) {
16 | return nil;
17 | }
18 | UIImage *posterImage = animatedImage.posterImage;
19 | CGImageRef posterImageRef = posterImage.CGImage;
20 | if (!posterImageRef) {
21 | return nil;
22 | }
23 | return [[DFAnimatedImage alloc] initWithAnimatedImage:animatedImage posterImage:posterImageRef posterImageScale:posterImage.scale posterImageOrientation:posterImage.imageOrientation];
24 | }
25 |
26 | /*! See https://en.wikipedia.org/wiki/List_of_file_signatures
27 | */
28 | - (BOOL)_isGIFData:(NSData *)data {
29 | const NSInteger sigLength = 3;
30 | if (data.length < sigLength) {
31 | return NO;
32 | }
33 | uint8_t sig[sigLength];
34 | [data getBytes:&sig length:sigLength];
35 | return sig[0] == 0x47 && sig[1] == 0x49 && sig[2] == 0x46;
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockResource.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFResource.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 2/28/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFMockResource.h"
10 |
11 | @implementation TDFMockResource
12 |
13 | - (instancetype)initWithID:(NSString *)ID {
14 | if (self = [super init]) {
15 | _ID = ID;
16 | }
17 | return self;
18 | }
19 |
20 | - (instancetype)init {
21 | [NSException raise:NSInternalInconsistencyException format:@"Please use designated initialzier"];
22 | return nil;
23 | }
24 |
25 | + (instancetype)resourceWithID:(NSString *)ID {
26 | return [[[self class] alloc] initWithID:ID];
27 | }
28 |
29 | - (NSUInteger)hash {
30 | return _ID.hash;
31 | }
32 |
33 | - (BOOL)isEqual:(id)other {
34 | if (other == self) {
35 | return YES;
36 | }
37 | if (!other || ![other isKindOfClass:[self class]]) {
38 | return NO;
39 | }
40 | return [self.ID isEqualToString:((TDFMockResource *)other).ID];
41 | }
42 |
43 | - (id)copyWithZone:(NSZone *)zone {
44 | return [[TDFMockResource alloc] initWithID:self.ID];
45 | }
46 |
47 | - (NSString *)description {
48 | return [NSString stringWithFormat:@"<%@ %p> { ID = %@ }", [self class], self, self.ID];
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Managing/DFCompositeImageManager.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManaging.h"
6 | #import
7 |
8 | /*! The DFCompositeImageManager is a dynamic dispatcher that constructs a tree of responsibility from multiple image managers and dynamically dispatch requests between them.
9 | @note Each image manager defines which image requests it can handle. The DFCompositeImageManager dispatches image requests starting with the first image manager in a chain. If the image manager can't handle the request it is passes to the next image manager in the chain and so on.
10 | @note The DFCompositeImageManager also conforms to DFImageManaging protocol so that individual managers and compositions can be treated uniformly.
11 | */
12 | @interface DFCompositeImageManager : NSObject
13 |
14 | /*! Initializes composite image manager with an array of image managers.
15 | */
16 | - (nonnull instancetype)initWithImageManagers:(nonnull NSArray> *)imageManagers;
17 |
18 | /*! Adds image manager to the end of the chain.
19 | */
20 | - (void)addImageManager:(nonnull id)imageManager;
21 |
22 | /*! Removes image manager from the chain.
23 | */
24 | - (void)removeImageManager:(nonnull id)imageManager;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/Pod/Source/UI/UIImageView+DFImageManager.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 | #import
7 |
8 | @class DFImageTask;
9 | @class DFImageRequest;
10 | @class DFImageRequestOptions;
11 |
12 | /*! Adds some basic image fetching capabilities to the UIImageView. For more features see DFImageView.
13 | */
14 | @interface UIImageView (DFImageManager)
15 |
16 | /*! Performs any clean up necessary to prepare the view for use again. Removes currently displayed image and cancels all requests registered with a receiver.
17 | */
18 | - (void)df_prepareForReuse;
19 |
20 | /*! Requests an image representation with a target size computed based on the image view size, default content mode (aspect fill) and default options. Uses shared image manager for fetching.
21 | */
22 | - (nullable DFImageTask *)df_setImageWithResource:(nullable id)resource;
23 |
24 | /*! Requests an image representation for the specified resource.
25 | */
26 | - (nullable DFImageTask *)df_setImageWithResource:(nullable id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options;
27 |
28 | /*! Requests an image representation for the specified requests.
29 | */
30 | - (nullable DFImageTask *)df_setImageWithRequest:(nullable DFImageRequest *)request;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Protocols/DFImageProcessing.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | @class DFImageRequest;
9 |
10 | /*! Processes images. Might include image scaling, cropping and more.
11 | */
12 | @protocol DFImageProcessing
13 |
14 | /*! Compares two requests for equivalence with regard to processing the image. Requests should be considered equivalent if image processor will produce the same result for both requests when given the same input image.
15 | @warning Implementation should not inspect a resource object of the request.
16 | */
17 | - (BOOL)isProcessingForRequestEquivalent:(nonnull DFImageRequest *)request1 toRequest:(nonnull DFImageRequest *)request2;
18 |
19 | /*! Returns processed image for a given request.
20 | @param partial If YES then image is a progressively decoded partial image data.
21 | */
22 | - (nullable UIImage *)processedImage:(nonnull UIImage *)image forRequest:(nonnull DFImageRequest *)request partial:(BOOL)partial;
23 |
24 | @optional
25 | /*! Returns NO when no processing is required for image with a given request.
26 | @param partial If YES then image is a progressively decoded partial image data.
27 | */
28 | - (BOOL)shouldProcessImage:(nonnull UIImage *)image forRequest:(nonnull DFImageRequest *)request partial:(BOOL)partial;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImageProcessor.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFAnimatedImage.h"
6 | #import "DFAnimatedImageProcessor.h"
7 | #import "DFImageManagerDefines.h"
8 |
9 | @implementation DFAnimatedImageProcessor {
10 | id _processor;
11 | }
12 |
13 | DF_INIT_UNAVAILABLE_IMPL
14 |
15 | - (instancetype)initWithProcessor:(id)processor {
16 | if (self = [super init]) {
17 | _processor = processor;
18 | }
19 | return self;
20 | }
21 |
22 | - (BOOL)isProcessingForRequestEquivalent:(DFImageRequest *)request1 toRequest:(DFImageRequest *)request2 {
23 | return [_processor isProcessingForRequestEquivalent:request1 toRequest:request2];
24 | }
25 |
26 | - (BOOL)shouldProcessImage:(UIImage *)image forRequest:(DFImageRequest *)request partial:(BOOL)partial {
27 | if ([image isKindOfClass:[DFAnimatedImage class]]) {
28 | return NO;
29 | }
30 | if ([_processor respondsToSelector:@selector(shouldProcessImage:forRequest:partial:)]) {
31 | return [_processor shouldProcessImage:image forRequest:request partial:partial];
32 | }
33 | return YES;
34 | }
35 |
36 | - (UIImage *)processedImage:(UIImage *)image forRequest:(DFImageRequest *)request partial:(BOOL)partial {
37 | return [_processor processedImage:image forRequest:request partial:partial];
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Managing/DFImageManager+Convenience.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManager.h"
6 |
7 | @implementation DFImageManager (Convenience)
8 |
9 | + (DFImageTask *)imageTaskForResource:(id)resource completion:(DFImageTaskCompletion)completion {
10 | return [[self sharedManager] imageTaskForResource:resource completion:completion];
11 | }
12 |
13 | + (DFImageTask *)imageTaskForRequest:(DFImageRequest *)request completion:(DFImageTaskCompletion)completion {
14 | return [[self sharedManager] imageTaskForRequest:request completion:completion];
15 | }
16 |
17 | + (void)getImageTasksWithCompletion:(void (^)(NSArray * _Nonnull, NSArray * _Nonnull))completion {
18 | [[self sharedManager] getImageTasksWithCompletion:completion];
19 | }
20 |
21 | + (void)invalidateAndCancel {
22 | [[self sharedManager] invalidateAndCancel];
23 | }
24 |
25 | + (void)startPreheatingImagesForRequests:(NSArray *)requests {
26 | [[self sharedManager] startPreheatingImagesForRequests:requests];
27 | }
28 |
29 | + (void)stopPreheatingImagesForRequests:(NSArray *)requests {
30 | [[self sharedManager] stopPreheatingImagesForRequests:requests];
31 | }
32 |
33 | + (void)stopPreheatingImagesForAllRequests {
34 | [[self sharedManager] stopPreheatingImagesForAllRequests];
35 | }
36 |
37 | + (void)removeAllCachedImages {
38 | [[self sharedManager] removeAllCachedImages];
39 | }
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFBaseCollectionViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDFBaseCollectionViewController.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/7/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFBaseCollectionViewController.h"
10 |
11 | @implementation SDFBaseCollectionViewController
12 |
13 | - (instancetype)init {
14 | return [self initWithCollectionViewLayout:[UICollectionViewFlowLayout new]];
15 | }
16 |
17 | - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout {
18 | if (self = [super initWithCollectionViewLayout:layout]) {
19 | _numberOfItemsPerRow = 4;
20 | }
21 | return self;
22 | }
23 |
24 | - (void)viewDidLoad {
25 | [super viewDidLoad];
26 |
27 | self.collectionView.alwaysBounceVertical = YES;
28 | self.view.backgroundColor = [UIColor whiteColor];
29 | self.collectionView.backgroundColor = [UIColor whiteColor];
30 | }
31 |
32 | - (void)viewWillAppear:(BOOL)animated {
33 | [super viewWillAppear:animated];
34 |
35 | [self _updateItemSize];
36 | }
37 |
38 | - (void)viewDidLayoutSubviews {
39 | [super viewDidLayoutSubviews];
40 |
41 | [self _updateItemSize];
42 | }
43 |
44 | - (void)_updateItemSize {
45 | UICollectionViewFlowLayout *layout = (id)self.collectionViewLayout;
46 | layout.minimumLineSpacing = 2.f;
47 | layout.minimumInteritemSpacing = 2.f;
48 | CGFloat side = (self.collectionView.bounds.size.width - (self.numberOfItemsPerRow - 1) * 2.0) / self.numberOfItemsPerRow;
49 | layout.itemSize = CGSizeMake(side, side);
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFTesting.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFTesting.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 12/26/14.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFTesting.h"
10 | #import
11 |
12 | @implementation TDFTesting
13 |
14 | + (UIImage *)testImage {
15 | return [[UIImage alloc] initWithData:[self testImageData] scale:[UIScreen mainScreen].scale];
16 | }
17 |
18 | + (NSURL *)testImageURL {
19 | return [self _testImageURLForName:@"Image"];
20 | }
21 |
22 | + (NSURL *)_testImageURLForName:(NSString *)name {
23 | NSBundle *bundle = [NSBundle bundleForClass:[self class]];
24 | NSString *path = [bundle pathForResource:name ofType:@"jpg"];
25 | return [NSURL fileURLWithPath:path];
26 | }
27 |
28 | + (NSData *)testImageData {
29 | return [NSData dataWithContentsOfURL:[self testImageURL]];
30 | }
31 |
32 | + (UIImage *)testImage2 {
33 | return [[UIImage alloc] initWithData:[self testImageData2] scale:[UIScreen mainScreen].scale];
34 | }
35 |
36 | + (NSData *)testImageData2 {
37 | return [NSData dataWithContentsOfURL:[self _testImageURLForName:@"Image2"]];
38 | }
39 |
40 | + (void)stubRequestWithURL:(NSURL *)imageURL {
41 | UIImage *testImage = [TDFTesting testImage];
42 | NSData *data = UIImageJPEGRepresentation(testImage, 1.0);
43 | [OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
44 | return [request.URL isEqual:imageURL];
45 | } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
46 | return [[OHHTTPStubsResponse alloc] initWithData:data statusCode:200 headers:nil];
47 | }];
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Fetching/DFURLHTTPResponseValidator.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFURLHTTPResponseValidator.h"
6 |
7 | @implementation DFURLHTTPResponseValidator
8 |
9 | - (nonnull instancetype)init {
10 | if (self = [super init]) {
11 | _acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
12 | }
13 | return self;
14 | }
15 |
16 | - (BOOL)isValidResponse:(nullable NSHTTPURLResponse *)response data:(nullable NSData *)data error:(NSError * __nullable __autoreleasing * __nullable)error {
17 | if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
18 | return NO;
19 | }
20 | if (self.acceptableStatusCodes != nil && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode]) {
21 | if (error != nil) {
22 | *error = [NSError errorWithDomain:DFURLValidationErrorDomain code:NSURLErrorBadServerResponse userInfo:[self _errorInfoWithResponse:response]];
23 | }
24 | return NO;
25 | }
26 | if (self.acceptableContentTypes != nil && ![self.acceptableContentTypes containsObject:response.MIMEType]) {
27 | if (error != nil) {
28 | *error = [NSError errorWithDomain:DFURLValidationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:[self _errorInfoWithResponse:response]];
29 | }
30 | return NO;
31 | }
32 | return YES;
33 | }
34 |
35 | - (nonnull NSDictionary *)_errorInfoWithResponse:(nonnull NSURLResponse *)response {
36 | NSMutableDictionary *userInfo = [NSMutableDictionary new];
37 | userInfo[DFURLErrorInfoURLResponseKey] = response;
38 | if (response.URL != nil) {
39 | userInfo[NSURLErrorFailingURLErrorKey] = response.URL;
40 | }
41 | return [userInfo copy];
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFImageCache.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageCache.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 3/19/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFTestingKit.h"
10 | #import "DFImageManagerKit.h"
11 | #import
12 |
13 | @interface TDFImageCache : XCTestCase
14 |
15 | @end
16 |
17 | @implementation TDFImageCache {
18 | DFImageCache *_cache;
19 | }
20 |
21 | - (void)setUp {
22 | [super setUp];
23 | _cache = [DFImageCache new];
24 | }
25 |
26 | - (void)testThatDefaultCacheIsInitializedWithSharedCache {
27 | DFImageCache *cache = [DFImageCache new];
28 | XCTAssertEqual(cache.cache, [NSCache df_sharedImageCache]);
29 | XCTAssertEqual(cache.cache.totalCostLimit, [NSCache df_recommendedTotalCostLimit]);
30 | }
31 |
32 | - (void)testThatImageIsCached {
33 | UIImage *image = [UIImage new];
34 | DFCachedImageResponse *cachedResponse = [[DFCachedImageResponse alloc] initWithImage:image info:nil expirationDate:CFAbsoluteTimeGetCurrent() + 1.0];
35 | [_cache storeImageResponse:cachedResponse forKey:@"key"];
36 | XCTAssertNotNil([_cache cachedImageResponseForKey:@"key"]);
37 | XCTAssertEqual([_cache cachedImageResponseForKey:@"key"].image, image);
38 | }
39 |
40 | - (void)testThatExpiredImageIsntReturned {
41 | UIImage *image = [UIImage new];
42 | DFCachedImageResponse *cachedImage = [[DFCachedImageResponse alloc] initWithImage:image info:nil expirationDate:CFAbsoluteTimeGetCurrent() + 0.01];
43 | [_cache storeImageResponse:cachedImage forKey:@"key"];
44 | XCTAssertNotNil([_cache cachedImageResponseForKey:@"key"]);
45 | XCTAssertEqual([_cache cachedImageResponseForKey:@"key"].image, image);
46 | [NSThread sleepForTimeInterval:0.02];
47 | XCTAssertNil([_cache cachedImageResponseForKey:@"key"]);
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Private/DFImageManagerLoader.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 | #import
7 |
8 | @class DFImageTask;
9 | @class DFImageManagerConfiguration;
10 | @class DFImageManagerLoader;
11 |
12 | @protocol DFImageManagerLoaderDelegate
13 |
14 | - (void)imageLoader:(nonnull DFImageManagerLoader *)imageLoader imageTask:(nonnull DFImageTask *)imageTask didUpdateProgressWithCompletedUnitCount:(int64_t)completedUnitCount totalUnitCount:(int64_t)totalUnitCount;
15 |
16 | - (void)imageLoader:(nonnull DFImageManagerLoader *)imageLoader imageTask:(nonnull DFImageTask *)imageTask didCompleteWithImage:(nullable UIImage *)image info:(nullable NSDictionary *)info error:(nullable NSError *)error;
17 |
18 | - (void)imageLoader:(nonnull DFImageManagerLoader *)imageLoader imageTask:(nonnull DFImageTask *)imageTask didReceiveProgressiveImage:(nonnull UIImage *)image;
19 |
20 | @end
21 |
22 | /*! Private image loader:
23 | - transparent loading+processing+caching with a single completion block
24 | - transparent multiplexing
25 | - offloads work to the background queue
26 | */
27 | @interface DFImageManagerLoader : NSObject
28 |
29 | @property (nullable, nonatomic, weak) id delegate;
30 |
31 | - (nonnull instancetype)initWithConfiguration:(nonnull DFImageManagerConfiguration *)configuration;
32 |
33 | - (void)startLoadingForImageTask:(nonnull DFImageTask *)imageTask;
34 |
35 | - (void)cancelLoadingForImageTask:(nonnull DFImageTask *)imageTask;
36 |
37 | - (void)updateLoadingPriorityForImageTask:(nonnull DFImageTask *)imageTask;
38 |
39 | - (nullable DFCachedImageResponse *)cachedResponseForRequest:(nonnull DFImageRequest *)request;
40 |
41 | - (nonnull id)preheatingKeyForRequest:(nonnull DFImageRequest *)request;
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | NSPhotoLibraryUsageDescription
31 | to show you PhotoKit demo
32 | UILaunchStoryboardName
33 | Launch Screen
34 | UIMainStoryboardFile
35 | Main
36 | UIRequiredDeviceCapabilities
37 |
38 | armv7
39 |
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UISupportedInterfaceOrientations~ipad
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationPortraitUpsideDown
50 | UIInterfaceOrientationLandscapeLeft
51 | UIInterfaceOrientationLandscapeRight
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Managing/DFImageManagerConfiguration.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageDecoder.h"
6 | #import "DFImageManagerConfiguration.h"
7 | #import "DFImageManagerDefines.h"
8 |
9 | @implementation DFImageManagerConfiguration
10 |
11 | - (instancetype)init {
12 | if (self = [super init]) {
13 | _decoder = [DFImageDecoder new];
14 | _processingQueue = [NSOperationQueue new];
15 | _processingQueue.maxConcurrentOperationCount = 2;
16 | _maximumConcurrentPreheatingRequests = 2;
17 | _progressiveImageDecodingThreshold = 0.15f;
18 | }
19 | return self;
20 | }
21 |
22 | + (instancetype)configurationWithFetcher:(id)fetcher processor:(id)processor cache:(id)cache {
23 | DFImageManagerConfiguration *conf = [[self class] new];
24 | conf.fetcher = fetcher;
25 | conf.processor = processor;
26 | conf.cache = cache;
27 | return conf;
28 | }
29 |
30 | - (id)copyWithZone:(NSZone *)zone {
31 | DFImageManagerConfiguration *copy = [DFImageManagerConfiguration new];
32 | copy.fetcher = self.fetcher;
33 | copy.decoder = self.decoder;
34 | copy.cache = self.cache;
35 | copy.processor = self.processor;
36 | copy.processingQueue = self.processingQueue;
37 | copy.maximumConcurrentPreheatingRequests = self.maximumConcurrentPreheatingRequests;
38 | copy.progressiveImageDecodingThreshold = self.progressiveImageDecodingThreshold;
39 | return copy;
40 | }
41 |
42 | @end
43 |
44 |
45 | @implementation DFImageManagerConfiguration (DFGlobalConfiguration)
46 |
47 | static BOOL _allowsProgressiveImage = NO;
48 |
49 | + (void)setAllowsProgressiveImage:(BOOL)allowsProgressiveImage {
50 | _allowsProgressiveImage = allowsProgressiveImage;
51 | }
52 |
53 | + (BOOL)allowsProgressiveImage {
54 | return _allowsProgressiveImage;
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "icon.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "icon-5.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "icon@2x-1.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "icon@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "60x60",
29 | "idiom" : "iphone",
30 | "filename" : "icon-1.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "icon@3x-1.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "29x29",
41 | "idiom" : "ipad",
42 | "filename" : "icon-3.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "icon-2.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "40x40",
53 | "idiom" : "ipad",
54 | "filename" : "icon-4.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "icon@2x.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "76x76",
65 | "idiom" : "ipad",
66 | "filename" : "icon-6.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "icon@2x-2.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "idiom" : "ipad",
77 | "size" : "83.5x83.5",
78 | "scale" : "2x"
79 | }
80 | ],
81 | "info" : {
82 | "version" : 1,
83 | "author" : "xcode"
84 | }
85 | }
--------------------------------------------------------------------------------
/Pod/Source/Core/Caching/DFImageCache.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFCachedImageResponse.h"
6 | #import "DFImageCache.h"
7 | #import "DFImageManagerDefines.h"
8 | #import "NSCache+DFImageManager.h"
9 |
10 | @implementation DFImageCache
11 |
12 | - (void)dealloc {
13 | [[NSNotificationCenter defaultCenter] removeObserver:self];
14 | }
15 |
16 | - (nonnull instancetype)initWithCache:(nonnull NSCache *)cache {
17 | if (self = [super init]) {
18 | _cache = cache;
19 | #if TARGET_OS_IOS && !TARGET_OS_WATCH
20 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
21 | #endif
22 | }
23 | return self;
24 | }
25 |
26 | - (instancetype)init {
27 | return [self initWithCache:[NSCache df_sharedImageCache]];
28 | }
29 |
30 | #pragma mark
31 |
32 | - (nullable DFCachedImageResponse *)cachedImageResponseForKey:(nullable id)key {
33 | DFCachedImageResponse *response = [_cache objectForKey:key];
34 | if (response) {
35 | if (response.expirationDate > CFAbsoluteTimeGetCurrent()) {
36 | return response;
37 | } else {
38 | [_cache removeObjectForKey:key];
39 | }
40 | }
41 | return nil;
42 | }
43 |
44 | - (void)storeImageResponse:(nullable DFCachedImageResponse *)response forKey:(nullable id)key {
45 | if (response && key) {
46 | [_cache setObject:response forKey:key cost:[self costForImageResponse:response]];
47 | }
48 | }
49 |
50 | - (void)removeAllObjects {
51 | [_cache removeAllObjects];
52 | }
53 |
54 | - (NSUInteger)costForImageResponse:(nonnull DFCachedImageResponse *)cachedResponse {
55 | CGImageRef image = cachedResponse.image.CGImage;
56 | return (CGImageGetWidth(image) * CGImageGetHeight(image) * CGImageGetBitsPerPixel(image)) / 8;
57 | }
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/Pod/Source/GIF/DFAnimatedImageView.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFAnimatedImage.h"
6 | #import "DFAnimatedImageView.h"
7 | #import "DFImageResponse.h"
8 | #import "DFImageTask.h"
9 |
10 | @implementation DFAnimatedImageView
11 |
12 | - (instancetype)initWithFrame:(CGRect)frame {
13 | if (self = [super initWithFrame:frame]) {
14 | [self _createUI];
15 | }
16 | return self;
17 | }
18 |
19 | - (instancetype)initWithCoder:(NSCoder *)decoder {
20 | if (self = [super initWithCoder:decoder]) {
21 | [self _createUI];
22 | }
23 | return self;
24 | }
25 |
26 | - (void)_createUI {
27 | _allowsGIFPlayback = YES;
28 | _animatedImageView = [[FLAnimatedImageView alloc] initWithFrame:self.bounds];
29 | _animatedImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
30 | [self addSubview:_animatedImageView];
31 | }
32 |
33 | - (void)displayImage:(nullable UIImage *)image {
34 | if (!image) {
35 | self.image = nil;
36 | self.animatedImageView.animatedImage = nil;
37 | return;
38 | }
39 | if (self.allowsGIFPlayback && [image isKindOfClass:[DFAnimatedImage class]]) {
40 | self.animatedImageView.animatedImage = ((DFAnimatedImage *)image).animatedImage;
41 | } else {
42 | self.image = image;
43 | }
44 | }
45 |
46 | - (void)prepareForReuse {
47 | [super prepareForReuse];
48 | self.animatedImageView.animatedImage = nil;
49 | }
50 |
51 | - (void)didCompleteImageTask:(DFImageTask *)task withImage:(UIImage *)image {
52 | if (self.allowsAnimations && !task.response.isFastResponse && !self.image) {
53 | [self displayImage:image];
54 | [self.layer addAnimation:({
55 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
56 | animation.keyPath = @"opacity";
57 | animation.fromValue = @0.f;
58 | animation.toValue = @1.f;
59 | animation.duration = 0.25f;
60 | animation;
61 | }) forKey:@"opacity"];
62 | } else {
63 | [self displayImage:image];
64 | }
65 | }
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageManagerDefines.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | /* Size to pass when requesting the largest image for resource available (contentMode will be ignored).
9 | */
10 | extern CGSize const DFImageMaximumSize;
11 |
12 | /*! Options for fitting an image’s aspect ratio to a target size.
13 | */
14 | typedef NS_ENUM(NSInteger, DFImageContentMode) {
15 | /*! Fill the target size. Some portion of the content may be clipped if the clipping is allowed (see DFImageRequestOptions for more info).
16 | */
17 | DFImageContentModeAspectFill,
18 |
19 | /*! Fit the target size by maintaining the aspect ratio.
20 | */
21 | DFImageContentModeAspectFit
22 | };
23 |
24 | /*! The DFImageRequestCachePolicy defines the request cache policy used for memory caching. For more info on memory caching in DFImageManager docs.
25 | */
26 | typedef NS_ENUM(NSInteger, DFImageRequestCachePolicy) {
27 | /*! The default policy allows memory cache lookup.
28 | */
29 | DFImageRequestCachePolicyDefault,
30 |
31 | /* Specifies that the image should loaded from the originating source. No existing cache data should be used to satisfy the request.
32 | */
33 | DFImageRequestCachePolicyReloadIgnoringCache
34 | };
35 |
36 | /*! Image request priority.
37 | */
38 | typedef NS_ENUM(NSInteger, DFImageRequestPriority) {
39 | DFImageRequestPriorityLow,
40 | DFImageRequestPriorityNormal,
41 | DFImageRequestPriorityHigh
42 | };
43 |
44 | /*! The error domain for DFImageManager.
45 | */
46 | extern NSString *__nonnull const DFImageManagerErrorDomain;
47 |
48 | /*! Returned when an image request is cancelled.
49 | */
50 | static const NSInteger DFImageManagerErrorCancelled = -1;
51 |
52 | /*! Returned when an image request fails without a specific reason.
53 | */
54 | static const NSInteger DFImageManagerErrorUnknown = -2;
55 |
56 | #define DF_INIT_UNAVAILABLE_IMPL \
57 | - (nullable instancetype)init { \
58 | [NSException raise:NSInternalInconsistencyException format:@"Please use designated initialzier"]; \
59 | return nil; \
60 | } \
61 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageRequestOptions.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageRequestOptions.h"
6 |
7 | @implementation DFImageRequestOptions
8 |
9 | - (nonnull instancetype)init {
10 | return [self initWithBuilder:[DFMutableImageRequestOptions new]];
11 | }
12 |
13 | - (nonnull instancetype)initWithBuilder:(nonnull DFMutableImageRequestOptions *)builder {
14 | if (self = [super init]) {
15 | _priority = builder.priority;
16 | _allowsNetworkAccess = builder.allowsNetworkAccess;
17 | _allowsClipping = builder.allowsClipping;
18 | _allowsProgressiveImage = builder.allowsProgressiveImage;
19 | _memoryCachePolicy = builder.memoryCachePolicy;
20 | _expirationAge = builder.expirationAge;
21 | _userInfo = builder.userInfo;
22 | }
23 | return self;
24 | }
25 |
26 | @end
27 |
28 |
29 | @implementation DFMutableImageRequestOptions
30 |
31 | static DFMutableImageRequestOptions *_defaultOptions;
32 |
33 | + (void)initialize {
34 | _defaultOptions = [DFMutableImageRequestOptions new];
35 | _defaultOptions.priority = DFImageRequestPriorityNormal;
36 | _defaultOptions.allowsNetworkAccess = YES;
37 | _defaultOptions.memoryCachePolicy = DFImageRequestCachePolicyDefault;
38 | _defaultOptions.expirationAge = 60.0 * 10.0; // 600.0 seconds
39 | }
40 |
41 | + (instancetype)defaultOptions {
42 | return _defaultOptions;
43 | }
44 |
45 | - (nonnull instancetype)init {
46 | if (self = [super init]) {
47 | DFImageRequestOptions *defaults = [[self class] defaultOptions];
48 | if (defaults) {
49 | _priority = defaults.priority;
50 | _allowsNetworkAccess = defaults.allowsNetworkAccess;
51 | _allowsClipping = defaults.allowsClipping;
52 | _allowsProgressiveImage = defaults.allowsProgressiveImage;
53 | _memoryCachePolicy = defaults.memoryCachePolicy;
54 | _expirationAge = defaults.expirationAge;
55 | _userInfo = [defaults.userInfo copy];
56 | }
57 | }
58 | return self;
59 | }
60 |
61 | - (DFImageRequestOptions * __nonnull)options {
62 | return [[DFImageRequestOptions alloc] initWithBuilder:self];
63 | }
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Fetching/DFURLImageFetcher.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageFetching.h"
6 | #import
7 |
8 | @class DFURLImageFetcher;
9 | @protocol DFURLResponseValidating;
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | /*! The NSNumber with NSURLRequestCachePolicy value that specifies a request cache policy.
14 | @note Should be put into DFImageRequestOptions userInfo dictionary.
15 | */
16 | extern NSString *const DFURLRequestCachePolicyKey;
17 |
18 |
19 | /*! Delegate that allows to customize DFURLImageFetcher.
20 | */
21 | @protocol DFURLImageFetcherDelegate
22 |
23 | @optional
24 |
25 | /*! Allows delegate to modify the given URL request.
26 | @param URLRequest The default URL request.
27 | @return The delegate may return unmodified NSURLResponse or create new NSURLResponse instance.
28 | */
29 | - (NSURLRequest *)URLImageFetcher:(DFURLImageFetcher *)fetcher URLRequestForImageRequest:(DFImageRequest *)imageRequest URLRequest:(NSURLRequest *)URLRequest;
30 |
31 | /*! Creates response validator for a given request.
32 | */
33 | - (nullable id)URLImageFetcher:(DFURLImageFetcher *)fetcher responseValidatorForURLRequest:(NSURLRequest *)URLRequest;
34 |
35 | @end
36 |
37 |
38 | /*! The DFURLImageFetcher provides basic networking using NSURLSession.
39 | */
40 | @interface DFURLImageFetcher : NSObject
41 |
42 | /*! The NSURLSession instance used by the image fetcher.
43 | */
44 | @property (nonatomic, readonly) NSURLSession *session;
45 |
46 | /*! A set containing all the supported URL schemes. The default set contains "http", "https", "ftp", "file" and "data" schemes.
47 | */
48 | @property (nonatomic, copy) NSSet *supportedSchemes;
49 |
50 | /*! The delegate of the receiver.
51 | */
52 | @property (nullable, nonatomic, weak) id delegate;
53 |
54 | /*! Initializes DFURLImageFetcher with a given session configuration.
55 | */
56 | - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration;
57 |
58 | /*! Initializer DFURLImageFetcher with default session configuration.
59 | */
60 | - (nullable instancetype)init;
61 |
62 | @end
63 |
64 | NS_ASSUME_NONNULL_END
65 |
--------------------------------------------------------------------------------
/Pod/Source/UI/DFImageView.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManaging.h"
6 | #import
7 |
8 | @class DFImageRequest;
9 | @class DFImageRequestOptions;
10 |
11 | /*! The DFImageView extends UIImageView class with image fetching functionality. It also adds other features like managing request priorities and more.
12 | */
13 | @interface DFImageView : UIImageView
14 |
15 | /*! Image manager used by the image view. Set to the shared manager during initialization.
16 | */
17 | @property (nonnull, nonatomic) id imageManager;
18 |
19 | /*! Automatically changes current request priority when image view gets added/removed from the window. Default value is NO.
20 | */
21 | @property (nonatomic) BOOL managesRequestPriorities;
22 |
23 | /*! If the value is YES image view will animate image changes when necessary. Default value is YES.
24 | */
25 | @property (nonatomic) BOOL allowsAnimations;
26 |
27 | /*! Duration it will take to animate image in if image view allows animations.
28 | */
29 | @property (nonatomic) CGFloat fadeDuration;
30 |
31 | /*! Performs any clean up necessary to prepare the view for use again. Removes currently displayed image and cancels all requests registered with a receiver.
32 | */
33 | - (void)prepareForReuse;
34 |
35 | /*! Returns current image task.
36 | */
37 | @property (nullable, nonatomic, readonly) DFImageTask *imageTask;
38 |
39 | /*! Requests an image representation with a target size, image content mode and request options of the receiver. For more info see setImageWithRequests: method.
40 | */
41 | - (void)setImageWithResource:(nullable id)resource;
42 |
43 | /*! Requests an image representation for the specified resource. For more info see setImageWithRequests: method.
44 | */
45 | - (void)setImageWithResource:(nullable id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options;
46 |
47 | /*! Requests an image representation for the specified request. For more info see setImageWithRequests: method.
48 | */
49 | - (void)setImageWithRequest:(nullable DFImageRequest *)request;
50 |
51 | /*! Subclassing hook that gets called when the completion block is called for the current image fetch task.
52 | */
53 | - (void)didCompleteImageTask:(nonnull DFImageTask *)task withImage:(nullable UIImage *)image;
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/Pod/Source/UI/UIImageView+DFImageManager.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManager.h"
6 | #import "DFImageRequest+UIKitAdditions.h"
7 | #import "DFImageRequest.h"
8 | #import "DFImageTask.h"
9 | #import "UIImageView+DFImageManager.h"
10 | #import
11 |
12 | static char *_imageTaskKey;
13 |
14 | @implementation UIImageView (DFImageManager)
15 |
16 | - (DFImageTask *)_df_imageTask {
17 | return objc_getAssociatedObject(self, &_imageTaskKey);
18 | }
19 |
20 | - (void)_df_setImageTask:(DFImageTask *)task {
21 | objc_setAssociatedObject(self, &_imageTaskKey, task, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
22 | }
23 |
24 | - (void)df_prepareForReuse {
25 | self.image = nil;
26 | [self _df_cancelFetching];
27 | }
28 |
29 | - (nullable DFImageTask *)df_setImageWithResource:(nullable id)resource {
30 | return [self df_setImageWithResource:resource targetSize:[DFImageRequest targetSizeForView:self] contentMode:DFImageContentModeAspectFill options:nil];
31 | }
32 |
33 | - (nullable DFImageTask *)df_setImageWithResource:(nullable id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options {
34 | return [self df_setImageWithRequest:(resource ? [DFImageRequest requestWithResource:resource targetSize:targetSize contentMode:contentMode options:options] : nil)];
35 | }
36 |
37 | - (nullable DFImageTask *)df_setImageWithRequest:(nullable DFImageRequest *)request {
38 | [self _df_cancelFetching];
39 | if (!request) {
40 | return nil;
41 | }
42 | typeof(self) __weak weakSelf = self;
43 | DFImageTask *task = [[DFImageManager sharedManager] imageTaskForRequest:request completion:^(UIImage *__nullable image, NSError *__nullable error, DFImageResponse *__nullable response, DFImageTask *__nonnull imageTask){
44 | if (image) {
45 | weakSelf.image = image;
46 | }
47 | }];
48 | task.progressiveImageHandler = ^(UIImage *__nonnull image){
49 | weakSelf.image = image;
50 | };
51 | [task resume];
52 | [self _df_setImageTask:task];
53 | return task;
54 | }
55 |
56 | - (void)_df_cancelFetching {
57 | DFImageTask *imageTask = [self _df_imageTask];
58 | imageTask.completionHandler = nil;
59 | imageTask.progressiveImageHandler = nil;
60 | [imageTask cancel];
61 | [self _df_setImageTask:nil];
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageRequest.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 | #import
7 |
8 | @class DFImageRequestOptions;
9 |
10 | /*! The DFImageRequest class represents an image request for a specified resource.
11 | */
12 | @interface DFImageRequest : NSObject
13 |
14 | /*! The resource whose image data is to be loaded.
15 | */
16 | @property (nonnull, nonatomic, readonly) id resource;
17 |
18 | /*! The size in pixels of image to be returned.
19 | */
20 | @property (nonatomic, readonly) CGSize targetSize;
21 |
22 | /*! An option for how to fit the image to the aspect ratio of the requested size. For details, see DFImageContentMode.
23 | */
24 | @property (nonatomic, readonly) DFImageContentMode contentMode;
25 |
26 | /*! Options specifying how image manager should handle the request and process the received image. More options that are provided in a base class may be available, so make sure to check the documentation on that.
27 | */
28 | @property (nonnull, nonatomic, readonly) DFImageRequestOptions *options;
29 |
30 | /*! Initializes request with a given parameters.
31 | @param resource The resource whose image data is to be loaded.
32 | @param targetSize The size in pixels of image to be returned.
33 | @param contentMode An option for how to fit the image to the aspect ratio of the requested size. For details, see DFImageContentMode.
34 | @param options Options specifying how image manager should handle the request and process the received image. Default options are created when parameter is nil.
35 | */
36 | - (nonnull instancetype)initWithResource:(nonnull id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options NS_DESIGNATED_INITIALIZER;
37 |
38 | /*! Returns a DFImageRequest initialized with a given resource. Uses DFImageMaximumSize and DFImageContentModeAspectFill as other parameters.
39 | */
40 | + (nonnull instancetype)requestWithResource:(nonnull id)resource;
41 |
42 | /*! Returns a DFImageRequest initialized with a given parameters.
43 | */
44 | + (nonnull instancetype)requestWithResource:(nonnull id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options;
45 |
46 | /*! Unavailable initializer, please use designated initializer.
47 | */
48 | - (nullable instancetype)init NS_UNAVAILABLE;
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Managing/DFImageManagerConfiguration.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 |
7 | @protocol DFImageCaching;
8 | @protocol DFImageFetching;
9 | @protocol DFImageDecoding;
10 | @protocol DFImageProcessing;
11 |
12 | /*! An DFImageManagerConfiguration object defines the behaviour and policies to use when retrieving images using DFImageManager object.
13 | */
14 | @interface DFImageManagerConfiguration : NSObject
15 |
16 | /*! The image fetcher the receiver was initialized with.
17 | */
18 | @property (nullable, nonatomic) id fetcher;
19 |
20 | /*! The image decoder.
21 | */
22 | @property (nullable, nonatomic) id decoder;
23 |
24 | /*! The image processor.
25 | */
26 | @property (nullable, nonatomic) id processor;
27 |
28 | /*! Operation queue used for executing image processing operations (see DFImageProcessing protocol).
29 | */
30 | @property (nullable, nonatomic) NSOperationQueue *processingQueue;
31 |
32 | /*! Memory cache that stores processed images.
33 | @note It's a good idea to implement DFImageProcessing and DFImageCaching in that same object.
34 | */
35 | @property (nullable, nonatomic) id cache;
36 |
37 | /*! Maximum number of preheating requests that are allowed to execute concurrently.
38 | */
39 | @property (nonatomic) NSUInteger maximumConcurrentPreheatingRequests;
40 |
41 | /*! The load progress threshold at which received data is decoded. Default value is 0.15, which means that the received data will be decoded each time next 15% of total bytes is received.
42 | */
43 | @property (nonatomic) float progressiveImageDecodingThreshold;
44 |
45 | /*! Initializes DFImageManagerConfiguration instance with default parameters.
46 | */
47 | - (nullable instancetype)init;
48 |
49 | /*! Returns configuration created with a given fetcher, processor and cache.
50 | */
51 | + (nonnull instancetype)configurationWithFetcher:(nonnull id)fetcher processor:(nullable id)processor cache:(nullable id)cache;
52 |
53 | @end
54 |
55 |
56 | @interface DFImageManagerConfiguration (DFGlobalConfiguration)
57 |
58 | /*! If YES allows progressive image decoding. Default value is NO.
59 | */
60 | + (void)setAllowsProgressiveImage:(BOOL)allowsProgressiveImage;
61 |
62 | /*! If YES allows progressive image decoding. Default value is NO.
63 | */
64 | + (BOOL)allowsProgressiveImage;
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/Pod/Source/WebP/DFWebPImageDecoder.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFWebPImageDecoder.h"
6 | #import
7 |
8 | @implementation DFWebPImageDecoder
9 |
10 | static void FreeImageData(void *info, const void *data, size_t size) {
11 | free((void *)data);
12 | }
13 |
14 | - (UIImage *)imageWithData:(NSData *)data partial:(BOOL)partial {
15 | if (partial) {
16 | return nil;
17 | }
18 | if (![self _isWebPData:data]) {
19 | return nil;
20 | }
21 | WebPDecoderConfig config;
22 | if (!WebPInitDecoderConfig(&config)) {
23 | return nil;
24 | }
25 | if (WebPGetFeatures(data.bytes, data.length, &config.input) != VP8_STATUS_OK) {
26 | return nil;
27 | }
28 | config.output.colorspace = config.input.has_alpha ? MODE_rgbA : MODE_RGB;
29 | if (WebPDecode(data.bytes, data.length, &config) != VP8_STATUS_OK) {
30 | return nil;
31 | }
32 | size_t width = (size_t)(config.options.use_scaling ? config.options.scaled_width : config.input.width);
33 | size_t height = (size_t)(config.options.use_scaling ? config.options.scaled_height : config.input.height);
34 |
35 | CGDataProviderRef providerRef = CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData);
36 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
37 | CGBitmapInfo bitmapInfo = config.input.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0;
38 | size_t components = config.input.has_alpha ? 4 : 3;
39 | CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, providerRef, NULL, NO, kCGRenderingIntentDefault);
40 | if (colorSpaceRef) {
41 | CGColorSpaceRelease(colorSpaceRef);
42 | }
43 | if (providerRef) {
44 | CGDataProviderRelease(providerRef);
45 | }
46 | UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
47 | if (imageRef) {
48 | CGImageRelease(imageRef);
49 | }
50 | return image;
51 | }
52 |
53 | - (BOOL)_isWebPData:(NSData *)data {
54 | const NSInteger sigLength = 12;
55 | if (data.length < sigLength) {
56 | return NO;
57 | }
58 | uint8_t sig[sigLength];
59 | [data getBytes:&sig length:sigLength];
60 | // RIFF----WEBP
61 | return (sig[0] == 0x52 && sig[1] == 0x49 && sig[2] == 0x46 && sig[3] == 0x46 && sig[8] == 0x57 && sig[9] == 0x45 && sig[10] == 0x42 && sig[11] == 0x50);
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/Pod/Source/AFNetworking/DFAFImageFetcher.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageFetching.h"
6 | #import
7 | #import
8 |
9 | /*! The NSNumber with NSURLRequestCachePolicy value that specifies a request cache policy.
10 | @note Should be put into DFImageRequestOptions userInfo dictionary.
11 | */
12 | extern NSString *__nonnull const DFAFRequestCachePolicyKey;
13 |
14 | @class DFAFImageFetcher;
15 |
16 | /*! The DFAFImageFetcherDelegate protocol describes the methods that DFAFImageFetcher objects call on their delegates to customize its behaviour.
17 | */
18 | @protocol DFAFImageFetcherDelegate
19 |
20 | @optional
21 |
22 | /*! Sent to allow delegate to modify the given URL request.
23 | @param fetcher The image fetcher sending the message.
24 | @param imageRequest The image request.
25 | @param URLRequest The proposed URL request to used for image load.
26 | @return The delegate may return modified, unmodified NSURLResponse or create NSURLResponse from scratch.
27 | */
28 | - (nonnull NSURLRequest *)imageFetcher:(nonnull DFAFImageFetcher *)fetcher URLRequestForImageRequest:(nonnull DFImageRequest *)imageRequest URLRequest:(nonnull NSURLRequest *)URLRequest;
29 |
30 | @end
31 |
32 | /*! The DFAFURLImageFetcher implements DFImageFetching protocol using AFNetworking library.
33 | @note AFNetworking doesn't track progress of NSURLSessionDataTask objects, tracking progress it currently not implemented.
34 | */
35 | @interface DFAFImageFetcher : NSObject
36 |
37 | /*! The session manager that the receiver was initialized with.
38 | */
39 | @property (nonnull, nonatomic, readonly) AFURLSessionManager *sessionManager;
40 |
41 | /*! The delegate of the receiver.
42 | */
43 | @property (nullable, nonatomic, weak) id delegate;
44 |
45 | /*! A set containing all the supported URL schemes. The default set contains "http", "https", "ftp", "file" and "data" schemes.
46 | @note The property can be changed in case there are any custom protocols supported by NSURLSession.
47 | */
48 | @property (nonnull, nonatomic, copy) NSSet *supportedSchemes;
49 |
50 | /*! Initializes the DFURLImageFetcher with a given session manager.
51 | */
52 | - (nonnull instancetype)initWithSessionManager:(nonnull AFURLSessionManager *)sessionManager NS_DESIGNATED_INITIALIZER;
53 |
54 | /*! Unavailable initializer, please use designated initializer.
55 | */
56 | - (nullable instancetype)init NS_UNAVAILABLE;
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockImageFetcher.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFImageFetcher.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 2/28/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFMockFetchOperation.h"
10 | #import "TDFMockImageFetcher.h"
11 | #import "TDFMockResource.h"
12 | #import "TDFTesting.h"
13 |
14 |
15 | NSString *TDFMockImageFetcherDidStartOperationNotification = @"TDFMockImageFetcherDidStartOperationNotification";
16 | NSString *TDFMockImageFetcherRequestKey = @"TDFMockImageFetcherRequestKey";
17 | NSString *TDFMockImageFetcherOperationKey = @"TDFMockImageFetcherOperationKey";
18 |
19 |
20 | @implementation TDFMockImageFetcher
21 |
22 | - (instancetype)init {
23 | if (self = [super init]) {
24 | _queue = [NSOperationQueue new];
25 | _data = [TDFTesting testImageData];
26 | }
27 | return self;
28 | }
29 |
30 | - (BOOL)canHandleRequest:(DFImageRequest *)request {
31 | return [request.resource isKindOfClass:[TDFMockResource class]];
32 | }
33 |
34 | - (BOOL)isRequestFetchEquivalent:(DFImageRequest *)request1 toRequest:(DFImageRequest *)request2 {
35 | return [request1.resource isEqual:request2.resource];
36 | }
37 |
38 | - (BOOL)isRequestCacheEquivalent:(DFImageRequest *)request1 toRequest:(DFImageRequest *)request2 {
39 | return [request1.resource isEqual:request2.resource];
40 | }
41 |
42 | - (id)startOperationWithRequest:(DFImageRequest *)request progressHandler:(DFImageFetchingProgressHandler)progressHandler completion:(DFImageFetchingCompletionHandler)completion {
43 | _createdOperationCount++;
44 | TDFMockFetchOperation *operation = [TDFMockFetchOperation blockOperationWithBlock:^{
45 | dispatch_async(dispatch_get_main_queue(), ^{
46 | if (progressHandler) {
47 | progressHandler(nil, 50, 100);
48 | }
49 | });
50 | dispatch_async(dispatch_get_main_queue(), ^{
51 | if (progressHandler) {
52 | progressHandler(nil, 100, 100);
53 | }
54 | });
55 | dispatch_async(dispatch_get_main_queue(), ^{
56 | if (completion) {
57 | completion(self.data, self.info, self.error);
58 | }
59 | });
60 | }];
61 | [_queue addOperation:operation];
62 | [[NSNotificationCenter defaultCenter] postNotificationName:TDFMockImageFetcherDidStartOperationNotification object:self userInfo:@{ TDFMockImageFetcherRequestKey : request, TDFMockImageFetcherOperationKey : operation }];
63 | return operation;
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageTask.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 | #import
7 |
8 | @class DFImageRequest;
9 | @class DFImageResponse;
10 |
11 | /*! Constants for determining the current state of a task.
12 | */
13 | typedef NS_ENUM(NSUInteger, DFImageTaskState) {
14 | DFImageTaskStateSuspended = 0,
15 | DFImageTaskStateRunning,
16 | DFImageTaskStateCancelled,
17 | DFImageTaskStateCompleted
18 | };
19 |
20 | /*! Abstract class representing image task.
21 | */
22 | @interface DFImageTask : NSObject
23 |
24 | /*! The image request that the task was created with.
25 | */
26 | @property (nonnull, atomic, readonly) DFImageRequest *request;
27 |
28 | /*! The current state of the task within the image manager.
29 | */
30 | @property (nonatomic, readonly) DFImageTaskState state;
31 |
32 | /*! An error object that indicates why the task failed.
33 | */
34 | @property (nullable, atomic, readonly) NSError *error;
35 |
36 | /*! Returns image response with metadata associated with a load.
37 | */
38 | @property (nullable, atomic, readonly) DFImageResponse *response;
39 |
40 | /*! A progress object monitoring the task progress. Progress is created lazily.
41 | @note Progress object can be used to cancel image task.
42 | */
43 | @property (nullable, atomic, readonly) NSProgress *progress;
44 |
45 | /*! A progress block monitoring the task progress. Always called on the main thread.
46 | */
47 | @property (nullable, atomic, copy) void (^progressHandler)(int64_t completedUnitCount, int64_t totalUnitCount);
48 |
49 | /*! Priority of the task. Can be changed during the execution of the task.
50 | */
51 | @property (nonatomic) DFImageRequestPriority priority;
52 |
53 | /*! Completion block to execute on the main thread when image task is either cancelled or completed.
54 | */
55 | @property (nullable, atomic, copy) void (^completionHandler)(UIImage *__nullable image, NSError *__nullable error, DFImageResponse *__nullable response, DFImageTask *__nonnull imageTask);
56 |
57 | /*! Progressive image handler which gets called on the main thread when partial image data is decoded.
58 | */
59 | @property (nullable, atomic, copy) void (^progressiveImageHandler)(UIImage *__nonnull image);
60 |
61 | /*! Resumes the task.
62 | */
63 | - (nonnull DFImageTask *)resume;
64 |
65 | /*! Advices the image manager that the task should be cancelled. The completion block will be called with error value of { DFImageManagerErrorDomain, DFImageManagerErrorCancelled }
66 | */
67 | - (void)cancel;
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Protocols/DFImageFetching.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | @protocol DFImageFetchingOperation;
9 | @class DFImageRequest;
10 |
11 | typedef void (^DFImageFetchingProgressHandler)(NSData *__nullable data, int64_t completedUnitCount, int64_t totalUnitCount);
12 | typedef void (^DFImageFetchingCompletionHandler)(NSData *__nullable data, NSDictionary *__nullable info, NSError *__nullable error);
13 |
14 | /*! The DFImageFetching protocol provides the basic structure for performing fetching of image data for specific DFImageRequest objects. Classes adopting DFImageFetching protocol handle the specifics associated with one of more types of the image requests.
15 | @note The role and the structure of the DFImageFetching protocol is largely inspired by the NSURLProtocol abstract class.
16 | */
17 | @protocol DFImageFetching
18 |
19 | /*! Inspects the given request and determines whether the receiver can handle the given request.
20 | */
21 | - (BOOL)canHandleRequest:(nonnull DFImageRequest *)request;
22 |
23 | /*! Compares two requests for equivalence with regard to fetching the image data. Requests should be considered equivalent if the image fetcher can handle both requests with a single operation.
24 | */
25 | - (BOOL)isRequestFetchEquivalent:(nonnull DFImageRequest *)request1 toRequest:(nonnull DFImageRequest *)request2;
26 |
27 | /*! Compares two requests for equivalence with regard to caching the image data.
28 | @note The DFImageManager uses this method for memory caching only, which means that there is no need for filtering out the dynamic part of the request (is there is any). For example, the dynamic part might be a username and password in a URL.
29 | */
30 | - (BOOL)isRequestCacheEquivalent:(nonnull DFImageRequest *)request1 toRequest:(nonnull DFImageRequest *)request2;
31 |
32 | /*! Starts fetching an image data for the request.
33 | @param progressHandler Progress handler that can be called on any thread. Image fetcher that don't report progress should ignore this the handler.
34 | @param completion Completion handler, can be called on arbitrary thread.
35 | */
36 | - (nonnull id)startOperationWithRequest:(nonnull DFImageRequest *)request progressHandler:(nullable DFImageFetchingProgressHandler)progressHandler completion:(nullable DFImageFetchingCompletionHandler)completion;
37 |
38 | @optional
39 |
40 | /*! Remove all cached images.
41 | */
42 | - (void)removeAllCachedImages;
43 |
44 | /*! Invalidates the reciever.
45 | */
46 | - (void)invalidate;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFMomentHeaderCollectionReusableView.m:
--------------------------------------------------------------------------------
1 | //
2 | // DFMomentHeaderCollectionReusableView.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/8/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFStickyHeaderCollectionViewFlowLayout.h"
10 | #import "SDFMomentHeaderCollectionReusableView.h"
11 |
12 | @interface SDFMomentHeaderCollectionReusableView ()
13 |
14 | @property (weak, nonatomic) UIVisualEffectView *visualEffectView;
15 |
16 | @end
17 |
18 | @implementation SDFMomentHeaderCollectionReusableView
19 |
20 | - (void)awakeFromNib {
21 | [super awakeFromNib];
22 | self.labelBottomLeft.text = @"";
23 | self.labelBottomRight.text = @"";
24 | self.labelTopLeft.text = @"";
25 |
26 | if ([UIVisualEffectView class] != nil) {
27 | UIVisualEffectView *blur = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
28 | blur.translatesAutoresizingMaskIntoConstraints = NO;
29 | NSDictionary *views = NSDictionaryOfVariableBindings(blur);
30 | [self insertSubview:blur atIndex:0];
31 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[blur]|" options:kNilOptions metrics:nil views:views]];
32 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[blur]|" options:kNilOptions metrics:nil views:views]];
33 | self.visualEffectView = blur;
34 | } else {
35 | self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.6f];
36 | }
37 |
38 | self.labelTopLeftConstraintCenterVertically = [NSLayoutConstraint constraintWithItem:self.labelTopLeft attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.f constant:0.f];
39 | self.labelTopLeftConstraintCenterVertically.active = NO;
40 | [self addConstraint:self.labelTopLeftConstraintCenterVertically];
41 | }
42 |
43 | - (void)prepareForReuse {
44 | [super prepareForReuse];
45 | self.visualEffectView.hidden = YES;
46 | self.labelBottomLeft.text = @"";
47 | self.labelBottomRight.text = @"";
48 | self.labelTopLeft.text = @"";
49 | self.labelTopLeftConstraintCenterVertically.active = NO;
50 | self.labelTopLeftConstraintTopSpacing.active = YES;
51 | }
52 |
53 | - (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
54 | [super applyLayoutAttributes:layoutAttributes];
55 | BOOL hidden = layoutAttributes.zIndex != kStickyHeaderZIndex;
56 | if (self.visualEffectView.hidden != hidden) {
57 | self.visualEffectView.hidden = hidden;
58 | }
59 | }
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/DFImageManager.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'DFImageManager'
3 | s.version = '2.0.2'
4 | s.summary = 'Advanced framework for managing images. Zero config, yet immense customization.'
5 | s.description = <<-DESC
6 | Advanced framework for loading, caching, processing, displaying and preheating images. DFImageManager is a pipeline that loads images using multiple dependencies which can be injected in runtime. It features optional AFNetworking, FLAnimatedImage and WebP integration.
7 | DESC
8 | s.license = { :type => 'MIT', :file => 'LICENSE' }
9 | s.homepage = 'https://github.com/kean/DFImageManager'
10 | s.author = 'Alexander Grebenyuk'
11 | s.social_media_url = 'https://twitter.com/a_grebenyuk'
12 | s.ios.deployment_target = '8.0'
13 | s.watchos.deployment_target = '2.0'
14 | s.source = { :git => 'https://github.com/kean/DFImageManager.git', :tag => s.version.to_s }
15 | s.requires_arc = true
16 | s.default_subspecs = 'Core', 'UI'
17 |
18 | s.subspec 'Core' do |ss|
19 | ss.source_files = 'Pod/Source/Core/**/*.{h,m}'
20 | ss.private_header_files = 'Pod/Source/Core/Private/*.h'
21 | end
22 |
23 | s.subspec 'UI' do |ss|
24 | ss.ios.deployment_target = '8.0'
25 | ss.dependency 'DFImageManager/Core'
26 | ss.ios.source_files = 'Pod/Source/UI/**/*.{h,m}'
27 | end
28 |
29 | s.subspec 'AFNetworking' do |ss|
30 | ss.ios.deployment_target = '8.0'
31 | ss.prefix_header_contents = '#define DF_SUBSPEC_AFNETWORKING_ENABLED 1'
32 | ss.dependency 'DFImageManager/Core'
33 | ss.dependency 'AFNetworking/NSURLSession', '~> 3.0'
34 | ss.source_files = 'Pod/Source/AFNetworking/**/*.{h,m}'
35 | end
36 |
37 | s.subspec 'PhotosKit' do |ss|
38 | ss.ios.deployment_target = '8.0'
39 | ss.prefix_header_contents = '#define DF_SUBSPEC_PHOTOSKIT_ENABLED 1'
40 | ss.dependency 'DFImageManager/Core'
41 | ss.source_files = 'Pod/Source/PhotosKit/**/*.{h,m}'
42 | end
43 |
44 | s.subspec 'GIF' do |ss|
45 | ss.ios.deployment_target = '8.0'
46 | ss.prefix_header_contents = '#define DF_SUBSPEC_GIF_ENABLED 1'
47 | ss.dependency 'DFImageManager/Core'
48 | ss.dependency 'DFImageManager/UI'
49 | ss.dependency 'FLAnimatedImage', '~> 1.0'
50 | ss.source_files = 'Pod/Source/GIF/**/*.{h,m}'
51 | end
52 |
53 | s.subspec 'WebP' do |ss|
54 | ss.ios.deployment_target = '8.0'
55 | ss.prefix_header_contents = '#define DF_SUBSPEC_WEBP_ENABLED 1'
56 | ss.dependency 'DFImageManager/Core'
57 | ss.dependency 'libwebp'
58 | ss.source_files = 'Pod/Source/WebP/**/*.{h,m}'
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/Demo/Tests/Source/TDFMockFetcher.m:
--------------------------------------------------------------------------------
1 | //
2 | // TDFMockResourceImageFetcher.m
3 | // DFImageManager
4 | //
5 | // Created by Alexander Grebenyuk on 11/07/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "TDFMockFetcher.h"
10 | #import "TDFMockFetchOperation.h"
11 |
12 | NSString *TDFMockFetcherDidStartOperationNotification = @"TDFMockFetcherDidStartOperationNotification";
13 |
14 | @implementation TDFMockResponse
15 |
16 | + (instancetype)mockWithData:(NSData *)data {
17 | TDFMockResponse *response = [TDFMockResponse new];
18 | response.data = data;
19 | return response;
20 | }
21 |
22 | + (instancetype)mockWithData:(NSData *)data elapsedTime:(NSTimeInterval)elapsedTime {
23 | TDFMockResponse *response = [TDFMockResponse new];
24 | response.data = data;
25 | response.elapsedTime = elapsedTime;
26 | return response;
27 | }
28 |
29 | + (instancetype)mockWithError:(NSError *)error elapsedTime:(NSTimeInterval)elapsedTime {
30 | TDFMockResponse *response = [TDFMockResponse new];
31 | response.error = error;
32 | response.elapsedTime = elapsedTime;
33 | return response;
34 | }
35 |
36 | @end
37 |
38 |
39 | @implementation TDFMockFetcher {
40 | NSMutableDictionary *_responses;
41 | }
42 |
43 | - (instancetype)init {
44 | if (self = [super init]) {
45 | _queue = [NSOperationQueue new];
46 | _responses = [NSMutableDictionary new];
47 | }
48 | return self;
49 | }
50 |
51 | - (void)setResponse:(TDFMockResponse *)response forResource:(NSString *)resource {
52 | [_responses setObject:response forKey:resource];
53 | }
54 |
55 | #pragma mark - DFImageFetching
56 |
57 | - (BOOL)canHandleRequest:(DFImageRequest *)request {
58 | return [request.resource isKindOfClass:[NSString class]];
59 | }
60 |
61 | - (BOOL)isRequestFetchEquivalent:(DFImageRequest *)request1 toRequest:(DFImageRequest *)request2 {
62 | return [request1.resource isEqual:request2.resource];
63 | }
64 |
65 | - (BOOL)isRequestCacheEquivalent:(DFImageRequest *)request1 toRequest:(DFImageRequest *)request2 {
66 | return [request1.resource isEqual:request2.resource];
67 | }
68 |
69 | - (id)startOperationWithRequest:(DFImageRequest *)request progressHandler:(DFImageFetchingProgressHandler)progressHandler completion:(DFImageFetchingCompletionHandler)completion {
70 | TDFMockFetchOperation *operation = [TDFMockFetchOperation blockOperationWithBlock:^{
71 | TDFMockResponse *response = _responses[request.resource];
72 | [NSThread sleepForTimeInterval:response.elapsedTime];
73 | dispatch_async(dispatch_get_main_queue(), ^{
74 | if (completion) {
75 | completion(response.data, response.info, response.error);
76 | }
77 | });
78 | }];
79 | operation.request = request;
80 | [_queue addOperation:operation];
81 | [[NSNotificationCenter defaultCenter] postNotificationName:TDFMockFetcherDidStartOperationNotification object:self userInfo:nil];
82 | return operation;
83 | }
84 |
85 | @end
86 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Private/DFProgressiveImageDecoder.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import "DFProgressiveImageDecoder.h"
7 | #import "DFImageDecoding.h"
8 |
9 | @interface DFProgressiveImageDecoder ()
10 |
11 | @property (nonnull, nonatomic, readonly) id decoder;
12 | @property (nonnull, nonatomic, readonly) NSOperationQueue *queue;
13 | @property (nullable, nonatomic, readonly) NSMutableData *data;
14 | @property (nonatomic) BOOL executing;
15 | @property (nonatomic) BOOL decoding;
16 | @property (nonatomic) uint64_t decodedByteCount;
17 | @property (nonnull, nonatomic, readonly) NSRecursiveLock *recursiveLock;
18 |
19 | @end
20 |
21 | @implementation DFProgressiveImageDecoder
22 |
23 | - (nonnull instancetype)initWithQueue:(nonnull NSOperationQueue *)queue decoder:(nonnull id)decoder {
24 | if (self = [super init]) {
25 | _decoder = decoder;
26 | _queue = queue;
27 | _data = [NSMutableData new];
28 | _recursiveLock = [NSRecursiveLock new];
29 | }
30 | return self;
31 | }
32 |
33 | - (void)resume {
34 | [self lock];
35 | if (!_executing) {
36 | _executing = YES;
37 | [self _decodeIfNeeded];
38 | }
39 | [self unlock];
40 | }
41 |
42 | - (void)invalidate {
43 | [self lock];
44 | _executing = NO;
45 | _data = nil;
46 | [self unlock];
47 | }
48 |
49 | - (void)appendData:(nullable NSData *)data {
50 | if (data.length) {
51 | [self lock];
52 | [_data appendData:data];
53 | [self _decodeIfNeeded];
54 | [self unlock];
55 | }
56 | }
57 |
58 | - (void)_decodeIfNeeded {
59 | if (_decoding || !_executing) {
60 | return;
61 | }
62 | if (_data.length <= _decodedByteCount) {
63 | return;
64 | }
65 | if (self.totalByteCount > 0) {
66 | if ((_data.length / (_totalByteCount * 1.0)) - (_decodedByteCount / (_totalByteCount * 1.0)) < _threshold) {
67 | return;
68 | }
69 | }
70 | _decoding = YES;
71 | typeof(self) __weak weakSelf = self;
72 | [_queue addOperationWithBlock:^{
73 | DFProgressiveImageDecoder *strongSelf = weakSelf;
74 | if (!strongSelf || !strongSelf.executing) {
75 | return;
76 | }
77 | [strongSelf lock];
78 | NSData *data = [strongSelf.data copy];
79 | [strongSelf unlock];
80 | UIImage *image = [strongSelf.decoder imageWithData:data partial:YES];
81 | void (^handler)(UIImage *) = strongSelf.handler;
82 | if (image && handler) {
83 | handler(image);
84 | }
85 | [strongSelf lock];
86 | strongSelf.decodedByteCount = data.length;
87 | strongSelf.decoding = NO;
88 | [self _decodeIfNeeded];
89 | [strongSelf unlock];
90 | }];
91 | }
92 |
93 | #pragma mark
94 |
95 | - (void)lock {
96 | [_recursiveLock lock];
97 | }
98 |
99 | - (void)unlock {
100 | [_recursiveLock unlock];
101 | }
102 |
103 | @end
104 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFFilesystemDemoViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDFFilesystemDemoViewController.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/7/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFFilesystemDemoViewController.h"
10 | #import
11 | #import
12 |
13 |
14 | static NSString * const reuseIdentifier = @"Cell";
15 |
16 | @implementation SDFFilesystemDemoViewController {
17 | NSArray *_photos;
18 | }
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 |
23 | [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
24 | }
25 |
26 | - (void)viewWillAppear:(BOOL)animated {
27 | [super viewWillAppear:animated];
28 |
29 | _photos = [self _photosWithNames:@[ @"10669363", @"10849093", @"10861057", @"10872981", @"10915709", @"10926234" ]];
30 | [self.collectionView reloadData];
31 | }
32 |
33 | - (NSArray *)_photosWithNames:(NSArray *)names {
34 | NSMutableArray *photos = [NSMutableArray new];
35 | for (NSString *name in names) {
36 | NSURL *URL = [[NSBundle mainBundle] URLForResource:name withExtension:@"jpg"];
37 | if (URL != nil) {
38 | [photos addObject:URL];
39 | }
40 | }
41 | return [photos copy];
42 | }
43 |
44 | #pragma mark -
45 |
46 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
47 | return 1;
48 | }
49 |
50 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
51 | return _photos.count;
52 | }
53 |
54 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
55 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
56 | cell.backgroundColor = [UIColor colorWithWhite:235.f/255.f alpha:1.f];
57 |
58 | DFImageView *imageView = (id)[cell viewWithTag:15];
59 | if (!imageView) {
60 | imageView = [[DFImageView alloc] initWithFrame:cell.bounds];
61 | imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
62 | imageView.tag = 15;
63 | [cell addSubview:imageView];
64 | }
65 |
66 | NSURL *imageURL = _photos[indexPath.row];
67 | [imageView setImageWithResource:imageURL targetSize:[self _imageTargetSize] contentMode:DFImageContentModeAspectFill options:nil];
68 |
69 | return cell;
70 | }
71 |
72 | - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
73 | DFImageView *imageView = (id)[cell viewWithTag:15];
74 | [imageView prepareForReuse];
75 | }
76 |
77 | - (CGSize)_imageTargetSize {
78 | CGSize size = ((UICollectionViewFlowLayout *)self.collectionViewLayout).itemSize;
79 | CGFloat scale = [UIScreen mainScreen].scale;
80 | return CGSizeMake(size.width * scale, size.height * scale);
81 | }
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Processing/DFImageProcessor.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageProcessor.h"
6 | #import "DFImageRequest.h"
7 | #import "DFImageRequestOptions.h"
8 | #import "UIImage+DFImageUtilities.h"
9 |
10 | NSString *DFImageProcessingCornerRadiusKey = @"DFImageProcessingCornerRadiusKey";
11 |
12 | @implementation DFImageProcessor
13 |
14 | - (instancetype)init {
15 | if (self = [super init]) {
16 | _shouldDecompressImages = YES;
17 | }
18 | return self;
19 | }
20 |
21 | #pragma mark
22 |
23 | - (BOOL)isProcessingForRequestEquivalent:(nonnull DFImageRequest *)request1 toRequest:(nonnull DFImageRequest *)request2 {
24 | if (request1 == request2) {
25 | return YES;
26 | }
27 | if (!(CGSizeEqualToSize(request1.targetSize, request2.targetSize) &&
28 | request1.contentMode == request2.contentMode &&
29 | request1.options.allowsClipping == request2.options.allowsClipping)) {
30 | return NO;
31 | }
32 | NSNumber *cornerRadius1 = request1.options.userInfo[DFImageProcessingCornerRadiusKey];
33 | NSNumber *cornerRadius2 = request2.options.userInfo[DFImageProcessingCornerRadiusKey];
34 | return (!cornerRadius1 && !cornerRadius2) || ((!!cornerRadius1 && !!cornerRadius2) && [cornerRadius1 isEqualToNumber:cornerRadius2]);
35 | }
36 |
37 | - (nullable UIImage *)processedImage:(nonnull UIImage *)image forRequest:(nonnull DFImageRequest *)request partial:(BOOL)partial {
38 | if (request.contentMode == DFImageContentModeAspectFill && request.options.allowsClipping) {
39 | image = [DFImageProcessor _croppedImage:image aspectFillPixelSize:request.targetSize];
40 | }
41 | CGFloat scale = [UIImage df_scaleForImage:image targetSize:request.targetSize contentMode:request.contentMode];
42 | if (scale < 1.f || self.shouldDecompressImages) {
43 | image = [UIImage df_decompressedImage:image scale:scale];
44 | }
45 | NSNumber *normalizedCornerRadius = request.options.userInfo[DFImageProcessingCornerRadiusKey];
46 | if (normalizedCornerRadius) {
47 | CGFloat cornerRadius = normalizedCornerRadius.floatValue * MIN(image.size.width, image.size.height);
48 | image = [UIImage df_imageWithImage:image cornerRadius:cornerRadius];
49 | }
50 | return image;
51 | }
52 |
53 | + (nullable UIImage *)_croppedImage:(nonnull UIImage *)image aspectFillPixelSize:(CGSize)targetSize {
54 | CGSize scaledSize = ({
55 | CGFloat scale = [UIImage df_scaleForImage:image targetSize:targetSize contentMode:DFImageContentModeAspectFill];
56 | CGSizeMake(CGImageGetWidth(image.CGImage) * scale, CGImageGetHeight(image.CGImage) * scale);
57 | });
58 | CGRect cropRect = CGRectMake((scaledSize.width - targetSize.width) / 2.f, (scaledSize.height - targetSize.height) / 2.f, targetSize.width, targetSize.height);
59 | CGRect normalizedCropRect = CGRectMake(cropRect.origin.x / scaledSize.width, cropRect.origin.y / scaledSize.height, cropRect.size.width / scaledSize.width, cropRect.size.height / scaledSize.height);
60 | return [UIImage df_croppedImage:image normalizedCropRect:normalizedCropRect];
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/Pod/DFImageManager.xcodeproj/xcshareddata/xcschemes/DFImageManager.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
72 |
73 |
74 |
75 |
77 |
78 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Managing/DFImageManager.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManaging.h"
6 | #import
7 |
8 | @class DFImageManagerConfiguration;
9 |
10 | /*! The DFImageManager manages execution of image tasks by delegating the actual job to the objects conforming to DFImageFetching, DFImageCaching, DFImageDecoding, and DFImageProcessing protocols.
11 |
12 | @note Reusing Operations
13 |
14 | DFImageManager might uses a single fetch operation for image tasks with equivalent requests. Image manager cancels fetch operations only when there are no remaining image tasks registered with a given operation.
15 | */
16 | @interface DFImageManager : NSObject
17 |
18 | /*! Returns a copy of the configuration object for this manager.
19 | */
20 | @property (nonnull, nonatomic, copy, readonly) DFImageManagerConfiguration *configuration;
21 |
22 | /*! Creates image manager with a given configuration. Manager copies the configuration object.
23 | */
24 | - (nonnull instancetype)initWithConfiguration:(nonnull DFImageManagerConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
25 |
26 | /*! Unavailable initializer, please use designated initializer.
27 | */
28 | - (nullable instancetype)init NS_UNAVAILABLE;
29 |
30 | @end
31 |
32 |
33 | /*! Dependency injectors.
34 | */
35 | @interface DFImageManager (SharedManager)
36 |
37 | /*! Returns the shared image manager instance.
38 | */
39 | + (nonnull id)sharedManager;
40 |
41 | /*! Sets the shared image manager.
42 | */
43 | + (void)setSharedManager:(nonnull id)manager;
44 |
45 | @end
46 |
47 |
48 | @interface DFImageManager (Convenience)
49 |
50 | /* Creates an image task with a given resource. After you create the task, you must start it by calling its resume method.
51 | */
52 | + (nonnull DFImageTask *)imageTaskForResource:(nonnull id)resource completion:(nullable DFImageTaskCompletion)completion;
53 |
54 | /*! Creates an image task with a given request. After you create the task, you must start it by calling its resume method.
55 | */
56 | + (nonnull DFImageTask *)imageTaskForRequest:(nonnull DFImageRequest *)request completion:(nullable DFImageTaskCompletion)completion;
57 |
58 | /*! Asynchronously calls a completion block on the main thread with all resumed outstanding image tasks and separate array with all preheating tasks.
59 | */
60 | + (void)getImageTasksWithCompletion:(void (^__nullable)(NSArray *__nonnull tasks, NSArray *__nonnull preheatingTasks))completion;
61 |
62 | /*! Cancels all outstanding requests, including preheating requests, and then invalidates the image manager. New image tasks may not be started.
63 | */
64 | + (void)invalidateAndCancel;
65 |
66 | /*! Prepares images for the given requests for later use.
67 | */
68 | + (void)startPreheatingImagesForRequests:(nonnull NSArray *)requests;
69 |
70 | /*! Cancels preheating for the given requests.
71 | */
72 | + (void)stopPreheatingImagesForRequests:(nonnull NSArray *)requests;
73 |
74 | /*! Cancels all image preheating tasks registered with a manager.
75 | */
76 | + (void)stopPreheatingImagesForAllRequests;
77 |
78 | /*! Removes all cached images from all cache layers.
79 | */
80 | + (void)removeAllCachedImages;
81 |
82 | @end
83 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFStickyHeaderCollectionViewFlowLayout.m:
--------------------------------------------------------------------------------
1 | //
2 | // DFStickyHeaderCollectionViewFlowLayout.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 1/8/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFStickyHeaderCollectionViewFlowLayout.h"
10 |
11 |
12 | @implementation SDFStickyHeaderCollectionViewFlowLayout
13 |
14 | - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
15 | return YES;
16 | }
17 |
18 | - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
19 | NSMutableArray *allItems = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
20 |
21 | NSMutableDictionary *headers = [NSMutableDictionary new];
22 | NSMutableDictionary *lastCells = [NSMutableDictionary new];
23 |
24 | [allItems enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *attributes, NSUInteger idx, BOOL *stop) {
25 | if ([[attributes representedElementKind] isEqualToString:UICollectionElementKindSectionHeader]) {
26 | headers[@(attributes.indexPath.section)] = attributes;
27 | } else if ([[attributes representedElementKind] isEqualToString:UICollectionElementKindSectionFooter]) {
28 | // Not implemeneted
29 | } else {
30 | UICollectionViewLayoutAttributes *currentAttribute = lastCells[@(attributes.indexPath.section)];
31 |
32 | // Get the bottom most cell of that section
33 | if ( ! currentAttribute || attributes.indexPath.row > currentAttribute.indexPath.row) {
34 | lastCells[@(attributes.indexPath.section)] = attributes;
35 | }
36 | }
37 |
38 | // For iOS 7.0, the cell zIndex should be above sticky section header
39 | attributes.zIndex = 1;
40 | }];
41 |
42 | [lastCells enumerateKeysAndObjectsUsingBlock:^(id key, UICollectionViewLayoutAttributes *attributes, BOOL *stop) {
43 | NSNumber *indexPathKey = @(attributes.indexPath.section);
44 |
45 | UICollectionViewLayoutAttributes *header = headers[indexPathKey];
46 | // CollectionView automatically removes headers not in bounds
47 | if ( ! header) {
48 | header = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:attributes.indexPath.section]];
49 | if (header != nil) {
50 | [allItems addObject:header];
51 | }
52 | }
53 | [self _updateHeaderAttributes:header lastCellAttributes:lastCells[indexPathKey]];
54 | }];
55 |
56 | return allItems;
57 | }
58 |
59 | - (void)_updateHeaderAttributes:(UICollectionViewLayoutAttributes *)attributes lastCellAttributes:(UICollectionViewLayoutAttributes *)lastCellAttributes {
60 | CGRect currentBounds = self.collectionView.bounds;
61 |
62 | CGPoint origin = attributes.frame.origin;
63 |
64 | CGFloat sectionMaxY = CGRectGetMaxY(lastCellAttributes.frame) - attributes.frame.size.height;
65 | CGFloat y = CGRectGetMaxY(currentBounds) - currentBounds.size.height + self.collectionView.contentInset.top;
66 |
67 | CGFloat maxY = MIN(MAX(y, attributes.frame.origin.y), sectionMaxY);
68 |
69 | if (origin.y != maxY) {
70 | origin.y = maxY;
71 | attributes.zIndex = kStickyHeaderZIndex;
72 | }
73 |
74 | attributes.frame = (CGRect){
75 | origin,
76 | attributes.frame.size
77 | };
78 | }
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Processing/UIImage+DFImageUtilities.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "UIImage+DFImageUtilities.h"
6 |
7 | @implementation UIImage (DFImageUtilities)
8 |
9 | + (CGFloat)df_scaleForImage:(nullable UIImage *)image targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode {
10 | CGSize bitmapSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));
11 | CGFloat scaleWidth = targetSize.width / bitmapSize.width;
12 | CGFloat scaleHeight = targetSize.height / bitmapSize.height;
13 | return (contentMode == DFImageContentModeAspectFill) ? MAX(scaleWidth, scaleHeight) : MIN(scaleWidth, scaleHeight);
14 | }
15 |
16 | + (UIImage *)df_decompressedImage:(UIImage *)image scale:(CGFloat)scale {
17 | if (!image) {
18 | return nil;
19 | }
20 | if (image.images) {
21 | return image;
22 | }
23 | CGImageRef imageRef = image.CGImage;
24 | CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
25 | if (scale < 1.f) {
26 | imageSize = CGSizeMake(imageSize.width * scale, imageSize.height * scale);
27 | }
28 |
29 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
30 | CGContextRef contextRef = CGBitmapContextCreate(NULL, (size_t)imageSize.width, (size_t)imageSize.height, CGImageGetBitsPerComponent(imageRef), 0, colorSpaceRef, (kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst));
31 | if (colorSpaceRef) {
32 | CGColorSpaceRelease(colorSpaceRef);
33 | }
34 | if (!contextRef) {
35 | return image;
36 | }
37 |
38 | CGContextDrawImage(contextRef, (CGRect){CGPointZero, imageSize}, imageRef);
39 | CGImageRef decompressedImageRef = CGBitmapContextCreateImage(contextRef);
40 | CGContextRelease(contextRef);
41 | UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation];
42 | if (decompressedImageRef) {
43 | CGImageRelease(decompressedImageRef);
44 | }
45 | return decompressedImage;
46 | }
47 |
48 | + (UIImage *)df_croppedImage:(UIImage *)image normalizedCropRect:(CGRect)cropRect {
49 | CGSize imageSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));
50 | CGRect imageCropRect = CGRectMake((CGFloat)floor(cropRect.origin.x * imageSize.width),
51 | (CGFloat)floor(cropRect.origin.y * imageSize.height),
52 | (CGFloat)floor(cropRect.size.width * imageSize.width),
53 | (CGFloat)floor(cropRect.size.height * imageSize.height));
54 | CGImageRef croppedImageRef = CGImageCreateWithImageInRect([image CGImage], imageCropRect);
55 | UIImage *croppedImage = [UIImage imageWithCGImage:croppedImageRef scale:image.scale orientation:image.imageOrientation];
56 | if (croppedImageRef) {
57 | CGImageRelease(croppedImageRef);
58 | }
59 | return croppedImage;
60 | }
61 |
62 | + (UIImage *)df_imageWithImage:(UIImage *)image cornerRadius:(CGFloat)cornerRadius {
63 | UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
64 | [[UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, image.size} cornerRadius:cornerRadius] addClip];
65 | [image drawInRect:(CGRect){CGPointZero, image.size}];
66 | UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
67 | UIGraphicsEndImageContext();
68 | return processedImage;
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/Pod/Source/UI/DFCollectionViewPreheatingController.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import
6 | #import
7 |
8 | @class DFCollectionViewPreheatingController;
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @protocol DFCollectionViewPreheatingControllerDelegate
13 |
14 | /*! Tells the delegate that the preheat window changed significantly.
15 | @param addedIndexPaths Index paths for items added to the preheat window. Index paths are sorted so that the items closest to the previous preheat window are in the beginning of the array; no matter whether user is scrolling forward of backward.
16 | @param removedIndexPaths Index paths for items there were removed from the preheat window.
17 | */
18 | - (void)collectionViewPreheatingController:(DFCollectionViewPreheatingController *)controller didUpdatePreheatRectWithAddedIndexPaths:(NSArray *)addedIndexPaths removedIndexPaths:(NSArray *)removedIndexPaths;
19 |
20 | @end
21 |
22 |
23 | /*! Detects changes in collection view content offset and updates preheat window. The preheat window is a rect inside the collection view content which is bigger than the viewport of the collection view. Provides delegate with index paths for added and removed cells when the preheat window changes significantly.
24 | @note Supports UICollectionViewFlowLayout and it's subclasses with either vertical or horizontal scroll direction.
25 | */
26 | @interface DFCollectionViewPreheatingController : NSObject
27 |
28 | /*! The collection view the receiver was initialized with.
29 | */
30 | @property (nonatomic, readonly) UICollectionView *collectionView;
31 |
32 | /*! The delegate object for the receiver.
33 | */
34 | @property (nullable, nonatomic, weak) id delegate;
35 |
36 | /*! The proportion of the collection view bounds (either width or height depending on the scroll direction) that is used as a preheat window. Default value is 2.0.
37 | */
38 | @property (nonatomic) CGFloat preheatRectRatio;
39 |
40 | /*! Determines the offset of the preheat from the center of the collection view visible area. The default value is 0.33.
41 | @note The value of this property is the ratio of the collection view height for UICollectionViewScrollDirectionVertical and width for UICollectionViewScrollDirectionHorizontal.
42 | */
43 | @property (nonatomic) CGFloat preheatRectOffset;
44 |
45 | /*! Determines how far the user needs to scroll from the point where the current preheat rect was set to refresh it. Default value is 0.33.
46 | @note The value of this property is the ratio of the collection view height for UICollectionViewScrollDirectionVertical and width for UICollectionViewScrollDirectionHorizontal.
47 | */
48 | @property (nonatomic) CGFloat preheatRectUpdateRatio;
49 |
50 | /*! Returns current preheat rect.
51 | */
52 | @property (nonatomic, readonly) CGRect preheatRect;
53 |
54 | /*! Returns current preheat indexes.
55 | */
56 | @property (nonatomic, readonly) NSSet *preheatIndexPaths;
57 |
58 | /*! Initializes preheating controller with a collection view.
59 | @param collectionView Collection view.
60 | */
61 | - (instancetype)initWithCollectionView:(UICollectionView *)collectionView NS_DESIGNATED_INITIALIZER;
62 |
63 | /*! Unavailable initializer, please use designated initializer.
64 | */
65 | - (nullable instancetype)init NS_UNAVAILABLE;
66 |
67 | /*! Resets preheat rect and calls delegate with removed index paths.
68 | */
69 | - (void)resetPreheatRect;
70 |
71 | /*! Updates current preheat rect and all items contained in it.
72 | */
73 | - (void)updatePreheatRect;
74 |
75 | @end
76 |
77 | NS_ASSUME_NONNULL_END
78 |
--------------------------------------------------------------------------------
/Pod/Source/UI/DFImageView.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManager.h"
6 | #import "DFImageManagerDefines.h"
7 | #import "DFImageManaging.h"
8 | #import "DFImageRequest+UIKitAdditions.h"
9 | #import "DFImageRequest.h"
10 | #import "DFImageRequestOptions.h"
11 | #import "DFImageResponse.h"
12 | #import "DFImageTask.h"
13 | #import "DFImageView.h"
14 |
15 | @implementation DFImageView
16 |
17 | - (void)dealloc {
18 | [self _cancelFetching];
19 | }
20 |
21 | - (nonnull instancetype)initWithFrame:(CGRect)frame {
22 | if (self = [super initWithFrame:frame]) {
23 | self.contentMode = UIViewContentModeScaleAspectFill;
24 | self.clipsToBounds = YES;
25 | [self _commonInit];
26 | }
27 | return self;
28 | }
29 |
30 | - (instancetype)initWithCoder:(NSCoder *)decoder {
31 | if (self = [super initWithCoder:decoder]) {
32 | [self _commonInit];
33 | }
34 | return self;
35 | }
36 |
37 | - (void)_commonInit {
38 | self.imageManager = [DFImageManager sharedManager];
39 | _allowsAnimations = YES;
40 | _fadeDuration = 0.25f;
41 | }
42 |
43 | - (void)prepareForReuse {
44 | [self _cancelFetching];
45 | self.image = nil;
46 | [self.layer removeAllAnimations];
47 | }
48 |
49 | - (void)_cancelFetching {
50 | _imageTask.completionHandler = nil;
51 | _imageTask.progressiveImageHandler = nil;
52 | [_imageTask cancel];
53 | _imageTask = nil;
54 | }
55 |
56 | - (void)setImageWithResource:(nullable id)resource {
57 | [self setImageWithResource:resource targetSize:[DFImageRequest targetSizeForView:self] contentMode:DFImageContentModeAspectFill options:nil];
58 | }
59 |
60 | - (void)setImageWithResource:(nullable id)resource targetSize:(CGSize)targetSize contentMode:(DFImageContentMode)contentMode options:(nullable DFImageRequestOptions *)options {
61 | [self setImageWithRequest:(resource ? [DFImageRequest requestWithResource:resource targetSize:targetSize contentMode:contentMode options:options] : nil)];
62 | }
63 |
64 | - (void)setImageWithRequest:(DFImageRequest *)request {
65 | [self _cancelFetching];
66 | if (!request) {
67 | return;
68 | }
69 | typeof(self) __weak weakSelf = self;
70 | DFImageTask *task = [self.imageManager imageTaskForRequest:request completion:^(UIImage *__nullable image, NSError *__nullable error, DFImageResponse *__nullable response, DFImageTask *__nonnull imageTask){
71 | [weakSelf didCompleteImageTask:imageTask withImage:image];
72 | }];
73 | task.progressiveImageHandler = ^(UIImage *__nonnull image){
74 | weakSelf.image = image;
75 | };
76 | _imageTask = task;
77 | [task resume];
78 | }
79 |
80 | - (void)didCompleteImageTask:(nonnull DFImageTask *)task withImage:(nullable UIImage *)image {
81 | if (self.allowsAnimations && !task.response.isFastResponse && !self.image) {
82 | self.image = image;
83 | [self.layer addAnimation:({
84 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
85 | animation.keyPath = @"opacity";
86 | animation.fromValue = @0.f;
87 | animation.toValue = @1.f;
88 | animation.duration = self.fadeDuration;
89 | animation;
90 | }) forKey:@"opacity"];
91 | } else {
92 | self.image = image;
93 | }
94 | }
95 |
96 | - (void)willMoveToWindow:(UIWindow *)newWindow {
97 | [super willMoveToWindow:newWindow];
98 | if (self.managesRequestPriorities) {
99 | [_imageTask setPriority:(newWindow ? DFImageRequestPriorityNormal: DFImageRequestPriorityLow)];
100 | }
101 | }
102 |
103 | @end
104 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFImageCollectionViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDFImageCollectionViewCell.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 20/07/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFImageCollectionViewCell.h"
10 | #import
11 | #import
12 | #import
13 |
14 | @interface SDFImageCollectionViewCell ()
15 |
16 | @property (nonatomic, readonly) UIProgressView *progressView;
17 | @property (nonatomic) NSProgress *currentProgress;
18 |
19 | @end
20 |
21 | @implementation SDFImageCollectionViewCell
22 |
23 | - (void)dealloc {
24 | self.currentProgress = nil;
25 | }
26 |
27 | - (instancetype)initWithFrame:(CGRect)frame {
28 | if (self = [super initWithFrame:frame]) {
29 | _imageView = [DFAnimatedImageView new];
30 | _progressView = [UIProgressView new];
31 |
32 | [self addSubview:_imageView];
33 | [self addSubview:_progressView];
34 |
35 | _imageView.translatesAutoresizingMaskIntoConstraints = NO;
36 | _progressView.translatesAutoresizingMaskIntoConstraints = NO;
37 |
38 | NSDictionary *views = NSDictionaryOfVariableBindings(_imageView, _progressView);
39 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_imageView]|" options:kNilOptions metrics:nil views:views]];
40 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imageView]|" options:kNilOptions metrics:nil views:views]];
41 |
42 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_progressView]|" options:kNilOptions metrics:nil views:views]];
43 | [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_progressView(==4)]" options:kNilOptions metrics:nil views:views]];
44 | }
45 | return self;
46 | }
47 |
48 | - (void)prepareForReuse {
49 | [super prepareForReuse];
50 |
51 | self.progressView.progress = 0;
52 | self.progressView.alpha = 1;
53 | self.currentProgress = nil;
54 | [self.imageView prepareForReuse];
55 | }
56 |
57 | - (void)setImageWithURL:(NSURL *)imageURL {
58 | [self setImageWithRequest:[DFImageRequest requestWithResource:imageURL]];
59 | }
60 |
61 | - (void)setImageWithRequest:(DFImageRequest *)request {
62 | [_imageView setImageWithRequest:request];
63 | self.currentProgress = _imageView.imageTask.progress;
64 | if (_imageView.imageTask.state == DFImageTaskStateCompleted) {
65 | self.progressView.alpha = 0;
66 | }
67 | }
68 |
69 | - (void)setCurrentProgress:(NSProgress *)currentProgress {
70 | if (_currentProgress != currentProgress) {
71 | [_currentProgress removeObserver:self forKeyPath:@"fractionCompleted" context:nil];
72 | _currentProgress = currentProgress;
73 | [self.progressView setProgress:currentProgress.fractionCompleted];
74 | [currentProgress addObserver:self forKeyPath:@"fractionCompleted" options:kNilOptions context:nil];
75 | }
76 | }
77 |
78 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
79 | if (object == _currentProgress) {
80 | dispatch_async(dispatch_get_main_queue(), ^{
81 | [self.progressView setProgress:_currentProgress.fractionCompleted animated:YES];
82 | if (_currentProgress.fractionCompleted == 1) {
83 | [UIView animateWithDuration:0.2 animations:^{
84 | self.progressView.alpha = 0;
85 | }];
86 | }
87 | });
88 | } else {
89 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
90 | }
91 | }
92 |
93 | @end
94 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFBuiltinNetworkingDemoViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDFAFNetworkingDemoViewController.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 3/8/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFPhotos.h"
10 | #import "SDFBuiltinNetworkingDemoViewController.h"
11 | #import
12 | #import
13 |
14 | static NSString * const reuseIdentifier = @"Cell";
15 |
16 | @implementation SDFBuiltinNetworkingDemoViewController {
17 | id _previousSharedManager;
18 |
19 | NSArray *_photos;
20 | }
21 |
22 | - (void)dealloc {
23 | [[DFImageManager sharedManager] invalidateAndCancel];
24 | [DFImageManager setSharedManager:_previousSharedManager];
25 | }
26 |
27 | - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout {
28 | if (self = [super initWithCollectionViewLayout:layout]) {
29 | [self _configureBuiltinManager];
30 | }
31 | return self;
32 | }
33 |
34 | - (void)_configureBuiltinManager {
35 | _previousSharedManager = [DFImageManager sharedManager];
36 |
37 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
38 | configuration.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:1024 * 1024 * 256 diskPath:@"com.github.kean.default_image_cache"];
39 |
40 | DFURLImageFetcher *fetcher = [[DFURLImageFetcher alloc] initWithSessionConfiguration:configuration];
41 | id manager = [[DFImageManager alloc] initWithConfiguration:[DFImageManagerConfiguration configurationWithFetcher:fetcher processor:[DFImageProcessor new] cache:[DFImageCache new]]];
42 | [DFImageManager setSharedManager:manager];
43 | }
44 |
45 | - (void)viewDidLoad {
46 | [super viewDidLoad];
47 |
48 | [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
49 |
50 | _photos = [SDFPhotos URLsForSmallPhotos];
51 | }
52 |
53 | #pragma mark -
54 |
55 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
56 | return 1;
57 | }
58 |
59 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
60 | return _photos.count;
61 | }
62 |
63 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
64 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
65 | cell.backgroundColor = [UIColor colorWithWhite:235.f/255.f alpha:1.f];
66 |
67 | DFImageView *imageView = (id)[cell viewWithTag:15];
68 | if (!imageView) {
69 | imageView = [[DFImageView alloc] initWithFrame:cell.bounds];
70 | imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
71 | imageView.tag = 15;
72 | [cell addSubview:imageView];
73 | }
74 |
75 | NSURL *URL = _photos[indexPath.row];
76 | [imageView prepareForReuse];
77 | [imageView setImageWithResource:URL targetSize:[self _imageTargetSize] contentMode:DFImageContentModeAspectFill options:nil];
78 |
79 | return cell;
80 | }
81 |
82 | - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
83 | DFImageView *imageView = (id)[cell viewWithTag:15];
84 | [imageView prepareForReuse];
85 | }
86 |
87 | - (CGSize)_imageTargetSize {
88 | CGSize size = ((UICollectionViewFlowLayout *)self.collectionViewLayout).itemSize;
89 | CGFloat scale = [UIScreen mainScreen].scale;
90 | return CGSizeMake(size.width * scale, size.height * scale);
91 | }
92 |
93 | @end
94 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/Launch Screen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
23 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Base.lproj/Launch Screen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
23 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Protocols/DFImageManaging.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | /*! For more info check the enumerations and other definitions provided in this header file:
6 | */
7 | #import "DFImageManagerDefines.h"
8 |
9 | @class DFImageRequest;
10 | @class DFImageResponse;
11 | @class DFImageTask;
12 |
13 | typedef void (^DFImageTaskCompletion)(UIImage *__nullable image, NSError *__nullable error, DFImageResponse *__nullable response, DFImageTask *__nonnull imageTask);
14 |
15 | /*! Provides a high-level API for loading images.
16 | */
17 | @protocol DFImageManaging
18 |
19 | /*! Inspects the given request and determines whether it can be handled.
20 | */
21 | - (BOOL)canHandleRequest:(nonnull DFImageRequest *)request;
22 |
23 | /*! Creates an image task with a given resource. After you create the task, you must start it by calling its resume method.
24 | @note Creates image request with a DFImageMaximumSize, DFImageContentModeAspectFill, and default options.
25 | @param completion Completion block to be called on the main thread when image task is either completed or cancelled. Completion block is called synchronously when the requested image can be retrieved from the memory cache and the request was made from the main thread. For more info see DFImageManager class reference.
26 | */
27 | - (nonnull DFImageTask *)imageTaskForResource:(nonnull id)resource completion:(nullable DFImageTaskCompletion)completion;
28 |
29 | /*! Creates an image task with a given request. After you create the task, you must start it by calling its resume method.
30 | @param request The request that contains the resource whose image is to be loaded, and additional options.
31 | @param completion Completion block to be called on the main thread when image task is either completed or cancelled. Completion block is called synchronously when the requested image can be retrieved from the memory cache and the request was made from the main thread. For more info see DFImageManager class reference.
32 | */
33 | - (nonnull DFImageTask *)imageTaskForRequest:(nonnull DFImageRequest *)request completion:(nullable DFImageTaskCompletion)completion;
34 |
35 | /*! Asynchronously calls a completion block on the main thread with all resumed outstanding image tasks and separate array with all preheating tasks.
36 | */
37 | - (void)getImageTasksWithCompletion:(void (^__nullable)(NSArray *__nonnull tasks, NSArray *__nonnull preheatingTasks))completion;
38 |
39 | /*! Cancels all outstanding requests, including preheating requests, and then invalidates the image manager. New image tasks may not be started.
40 | */
41 | - (void)invalidateAndCancel;
42 |
43 | /*! Prepares images for the given requests for later use.
44 | @note When you call this method, DFImageManager starts to fetch image data and cache images for the given requests. At any time afterward, you can create image tasks with equivalent requests.
45 | @note DFImageManager caches images with the exact target size, content mode, and options you specify in this method. If you later request an image with, for example, a different target size than you passed when calling this method, DFImageManager might have to generate a new image but would still be able to use cached image data.
46 | @note If this method is called twice with the same requests the second call would have no effect (unless first requests are completed).
47 | */
48 | - (void)startPreheatingImagesForRequests:(nonnull NSArray *)requests;
49 |
50 | /*! Cancels preheating for the given requests.
51 | @note The request parameters shall exactly match the parameters used in startPreheatingImagesForRequests: method.
52 | */
53 | - (void)stopPreheatingImagesForRequests:(nonnull NSArray *)requests;
54 |
55 | /*! Cancels all image preheating tasks registered with a manager.
56 | */
57 | - (void)stopPreheatingImagesForAllRequests;
58 |
59 | /*! Removes all cached images from all cache layers.
60 | */
61 | - (void)removeAllCachedImages;
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFProgressiveJPEGDemoViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDFProgressiveJPEGDemoViewController.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 14/08/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFProgressiveJPEGDemoViewController.h"
10 | #import "SDFImageCollectionViewCell.h"
11 | #import
12 |
13 | static NSString *const kReuseIdentifierImageCell = @"kReuseIdentifierImageCell";
14 |
15 | @implementation SDFProgressiveJPEGDemoViewController {
16 | UISegmentedControl *_segmentedControl;
17 | NSArray *_imageURLs;
18 | }
19 |
20 | - (void)dealloc {
21 | [DFImageManagerConfiguration setAllowsProgressiveImage:NO];
22 | }
23 |
24 | - (instancetype)init {
25 | return [self initWithCollectionViewLayout:[UICollectionViewFlowLayout new]];
26 | }
27 |
28 | - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout {
29 | if (self = [super initWithCollectionViewLayout:layout]) {
30 | [DFImageManagerConfiguration setAllowsProgressiveImage:YES];
31 | }
32 | return self;
33 | }
34 |
35 | - (void)viewDidLoad {
36 | [super viewDidLoad];
37 |
38 | _imageURLs = @[ @[[NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/9428404/2b0c8f16-49b6-11e5-8f38-f89cae5d9a8f.jpg"]],
39 | @[[NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/9428407/3ab53594-49b6-11e5-9ed8-9ccef592826e.jpg"]] ];
40 |
41 | self.navigationItem.titleView = ({
42 | UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"progressive", @"baseline"]];
43 | segmentedControl.selectedSegmentIndex = 0;
44 | [segmentedControl addTarget:self action:@selector(_segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];
45 | _segmentedControl = segmentedControl;
46 | segmentedControl;
47 | });
48 |
49 | [self.collectionView registerClass:[SDFImageCollectionViewCell class] forCellWithReuseIdentifier:kReuseIdentifierImageCell];
50 | self.collectionView.alwaysBounceVertical = YES;
51 | self.view.backgroundColor = [UIColor whiteColor];
52 | self.collectionView.backgroundColor = self.view.backgroundColor;
53 |
54 | UICollectionViewFlowLayout *layout = (id)self.collectionViewLayout;
55 | layout.sectionInset = UIEdgeInsetsMake(8.f, 8.f, 8.f, 8.f);
56 | layout.minimumInteritemSpacing = 8.f;
57 | }
58 |
59 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
60 | SDFImageCollectionViewCell *cell = (id)[collectionView dequeueReusableCellWithReuseIdentifier:kReuseIdentifierImageCell forIndexPath:indexPath];
61 | cell.backgroundColor = [UIColor colorWithWhite:235.f/255.f alpha:1.f];
62 | NSURL *URL = [self _currentDataSource][indexPath.row];
63 | [cell setImageWithRequest:({
64 | [DFImageRequest requestWithResource:URL targetSize:DFImageMaximumSize contentMode:DFImageContentModeAspectFill options:({
65 | DFMutableImageRequestOptions *options = [DFMutableImageRequestOptions new];
66 | options.allowsProgressiveImage = YES;
67 | options.options;
68 | })];
69 | })];
70 | return cell;
71 | }
72 |
73 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
74 | UICollectionViewFlowLayout *layout = (id)self.collectionViewLayout;
75 | CGFloat width = (self.view.bounds.size.width - layout.sectionInset.left - layout.sectionInset.right);
76 | return CGSizeMake(width, width);
77 | }
78 |
79 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
80 | return [self _currentDataSource].count;
81 | }
82 |
83 | - (NSArray *)_currentDataSource {
84 | return _imageURLs[_segmentedControl.selectedSegmentIndex];
85 | }
86 |
87 | #pragma mark - Actions
88 |
89 | - (void)_segmentedControlValueChanged:(UISegmentedControl *)control {
90 | [self.collectionView reloadData];
91 | }
92 |
93 | @end
94 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Support/DFImageRequestOptions.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFImageManagerDefines.h"
6 |
7 | @class DFMutableImageRequestOptions;
8 |
9 | /*! Use a DFImageRequestOptions object to specify options when requesting image representations of resources using classes conforming DFImageManaging protocol.
10 | */
11 | @interface DFImageRequestOptions : NSObject
12 |
13 | /*! Image request priority.
14 | */
15 | @property (nonatomic, readonly) DFImageRequestPriority priority;
16 |
17 | /*! A Boolean value that specifies whether image manager can download the requested image using network connection.
18 | */
19 | @property (nonatomic, readonly) BOOL allowsNetworkAccess;
20 |
21 | /*! If YES allows some portion of the image content to be clipped when filling the content to target size. Only works with DFImageContentModeAspectFill.
22 | */
23 | @property (nonatomic, readonly) BOOL allowsClipping;
24 |
25 | /*! If YES allows progressive image decoding.
26 | */
27 | @property (nonatomic, readonly) BOOL allowsProgressiveImage;
28 |
29 | /*! The request cache policy used for memory caching.
30 | */
31 | @property (nonatomic, readonly) DFImageRequestCachePolicy memoryCachePolicy;
32 |
33 | /*! The amount of time to elapse before memory-cached images associated with a request are considered to have expired.
34 | @warning This property doesn't affect caching implemented in a classes conforming to DFImageFetching protocol (for example, NSURLSession caching). For more info see DFImageCaching protocol and DFCachedImageResponse class.
35 | */
36 | @property (nonatomic, readonly) NSTimeInterval expirationAge;
37 |
38 | /*! A dictionary containing image manager-specific data pertaining to the receiver. Default value is nil.
39 | */
40 | @property (nullable, nonatomic, readonly) NSDictionary *userInfo;
41 |
42 | /*! Initializes DFImageRequestOptions with default options.
43 | */
44 | - (nonnull instancetype)init;
45 |
46 | @end
47 |
48 |
49 | /*! DFImageRequestOptions builder. Use options property of the builder to build DFImageRequestOptions object.
50 | @warning This class is not a mutable counterpart of DFImageRequestOptions! It's a builder that allows DFImageRequestOptions to be immutable without having a telescoping constructor.
51 | */
52 | @interface DFMutableImageRequestOptions : NSObject
53 |
54 | /*! Builds request options from the receiver.
55 | */
56 | @property (nonnull, nonatomic, readonly) DFImageRequestOptions *options;
57 |
58 | /*! Initializes DFMutableImageRequestOptions with default options.
59 | */
60 | - (nonnull instancetype)init NS_DESIGNATED_INITIALIZER;
61 |
62 | /*! Image request priority. Default value is DFImageRequestPriorityNormal.
63 | */
64 | @property (nonatomic) DFImageRequestPriority priority;
65 |
66 | /*! A Boolean value that specifies whether image manager can download the requested image using network connection. Default value is YES.
67 | */
68 | @property (nonatomic) BOOL allowsNetworkAccess;
69 |
70 | /*! If YES allows some portion of the image content to be clipped when filling the content to target size. Only works with DFImageContentModeAspectFill. Default value is NO.
71 | */
72 | @property (nonatomic) BOOL allowsClipping;
73 |
74 | /*! If YES allows progressive image decoding. Default value is NO.
75 | */
76 | @property (nonatomic) BOOL allowsProgressiveImage;
77 |
78 | /*! The request cache policy used for memory caching. Default value is DFImageRequestCachePolicyDefault.
79 | */
80 | @property (nonatomic) DFImageRequestCachePolicy memoryCachePolicy;
81 |
82 | /*! The amount of time to elapse before memory-cached images associated with a request are considered to have expired. Default value is 600.0 seconds.
83 | @warning This property doesn't affect caching implemented in a classes conforming to DFImageFetching protocol (for example, NSURLSession caching)! For more info see DFImageCaching protocol and DFCachedImageResponse class.
84 | */
85 | @property (nonatomic) NSTimeInterval expirationAge;
86 |
87 | /*! A dictionary containing image manager-specific data pertaining to the receiver. Default value is nil.
88 | */
89 | @property (nullable, copy, nonatomic) NSDictionary *userInfo;
90 |
91 | /*! Returns default image request options builder that is used when new DFMutableImageRequestOptions instance is initialized.
92 | */
93 | + (nonnull instancetype)defaultOptions;
94 |
95 | @end
96 |
--------------------------------------------------------------------------------
/Demo/DFImageManager.xcodeproj/xcshareddata/xcschemes/DFImageManager-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Managing/DFImageManager+SharedManager.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFCompositeImageManager.h"
6 | #import "DFImageCache.h"
7 | #import "DFImageDecoder.h"
8 | #import "DFImageManager.h"
9 | #import "DFImageManagerConfiguration.h"
10 | #import "DFImageProcessor.h"
11 | #import "DFURLImageFetcher.h"
12 | #import
13 |
14 | #if DF_SUBSPEC_GIF_ENABLED
15 | #import "DFImageManagerKit+GIF.h"
16 | #endif
17 |
18 | #if DF_SUBSPEC_WEBP_ENABLED
19 | #import "DFImageManagerKit+WebP.h"
20 | #endif
21 |
22 | #if DF_SUBSPEC_PHOTOSKIT_ENABLED
23 | #import "DFImageManagerKit+PhotosKit.h"
24 | #endif
25 |
26 | #if DF_SUBSPEC_AFNETWORKING_ENABLED
27 | #import "DFImageManagerKit+AFNetworking.h"
28 | #import
29 | #endif
30 |
31 | @implementation DFImageManager (SharedManager)
32 |
33 | static id _sharedManager;
34 | static OSSpinLock _lock = OS_SPINLOCK_INIT;
35 |
36 | + (nonnull id)sharedManager {
37 | static dispatch_once_t onceToken;
38 | dispatch_once(&onceToken, ^{
39 | if (!_sharedManager) {
40 | _sharedManager = [self _createDefaultManager];
41 | }
42 | });
43 |
44 | id manager;
45 | OSSpinLockLock(&_lock);
46 | manager = _sharedManager;
47 | OSSpinLockUnlock(&_lock);
48 | return manager;
49 | }
50 |
51 | + (void)setSharedManager:(nonnull id)manager {
52 | OSSpinLockLock(&_lock);
53 | _sharedManager = manager;
54 | OSSpinLockUnlock(&_lock);
55 | }
56 |
57 | + (id)_createDefaultManager {
58 | DFImageManagerConfiguration *conf = [self _defaultImageManagerConfiguration];
59 |
60 | NSMutableArray *managers = [NSMutableArray new];
61 |
62 | #if DF_SUBSPEC_AFNETWORKING_ENABLED
63 | [managers addObject:({
64 | AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[self _defaultSessionConfiguration]];
65 | sessionManager.responseSerializer = [AFHTTPResponseSerializer new];
66 | conf.fetcher = [[DFAFImageFetcher alloc] initWithSessionManager:sessionManager];
67 | [[DFImageManager alloc] initWithConfiguration:conf];
68 | })];
69 | #else
70 | [managers addObject:({
71 | conf.fetcher = [[DFURLImageFetcher alloc] initWithSessionConfiguration:[self _defaultSessionConfiguration]];
72 | [[DFImageManager alloc] initWithConfiguration:conf];
73 | })];
74 | #endif
75 |
76 | #if DF_SUBSPEC_PHOTOSKIT_ENABLED
77 | [managers addObject:({
78 | conf.fetcher = [DFPhotosKitImageFetcher new];
79 | [[DFImageManager alloc] initWithConfiguration:conf];
80 | })];
81 | #endif
82 |
83 | return managers.count > 1 ? [[DFCompositeImageManager alloc] initWithImageManagers:managers] : managers.firstObject;
84 | }
85 |
86 |
87 | + (DFImageManagerConfiguration *)_defaultImageManagerConfiguration {
88 | DFImageManagerConfiguration *conf = [DFImageManagerConfiguration new];
89 |
90 | conf.decoder = ({
91 | NSMutableArray *decoders = [NSMutableArray new];
92 | #if DF_SUBSPEC_GIF_ENABLED
93 | [decoders addObject:[DFAnimatedImageDecoder new]];
94 | #endif
95 | #if DF_SUBSPEC_WEBP_ENABLED
96 | [decoders addObject:[DFWebPImageDecoder new]];
97 | #endif
98 | [decoders addObject:[DFImageDecoder new]];
99 | decoders.count > 1 ? [[DFCompositeImageDecoder alloc] initWithDecoders:decoders] : decoders.firstObject;
100 | });
101 |
102 | conf.processor = ({
103 | id processor = [DFImageProcessor new];
104 | #if DF_SUBSPEC_GIF_ENABLED
105 | processor = [[DFAnimatedImageProcessor alloc] initWithProcessor:processor];
106 | #endif
107 | processor;
108 | });
109 |
110 | conf.cache = [DFImageCache new];
111 | return conf;
112 | }
113 |
114 | + (NSURLSessionConfiguration *)_defaultSessionConfiguration {
115 | NSURLSessionConfiguration *conf = [NSURLSessionConfiguration defaultSessionConfiguration];
116 | conf.URLCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:1024 * 1024 * 200 diskPath:@"com.github.kean.default_image_cache"];
117 | #if DF_SUBSPEC_WEBP_ENABLED
118 | conf.HTTPAdditionalHeaders = @{ @"Accept" : @"image/webp,image/*;q=0.8" };
119 | #else
120 | conf.HTTPAdditionalHeaders = @{ @"Accept" : @"image/*" };
121 | #endif
122 | conf.timeoutIntervalForRequest = 60.f;
123 | conf.timeoutIntervalForResource = 360.f;
124 | return conf;
125 | }
126 |
127 | @end
128 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFMomentHeaderCollectionReusableView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Pod/Source/Core/Managing/DFCompositeImageManager.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Alexander Grebenyuk (github.com/kean).
4 |
5 | #import "DFCompositeImageManager.h"
6 | #import "DFImageRequest.h"
7 |
8 | #define DFManagerForRequest(request) ({ \
9 | id __df_outManager; \
10 | for (id __df_manager in _managers) { \
11 | if ([__df_manager canHandleRequest:request]) { \
12 | __df_outManager = __df_manager; \
13 | break; \
14 | } \
15 | } \
16 | __df_outManager; })
17 |
18 | @implementation DFCompositeImageManager {
19 | NSMutableArray> *_managers;
20 | }
21 |
22 | - (nonnull instancetype)initWithImageManagers:(nonnull NSArray> *)imageManagers {
23 | if (self = [super init]) {
24 | _managers = [NSMutableArray arrayWithArray:imageManagers];
25 | }
26 | return self;
27 | }
28 |
29 | - (nonnull instancetype)init {
30 | return [self initWithImageManagers:@[]];
31 | }
32 |
33 | - (void)addImageManager:(nonnull id)imageManager {
34 | [_managers addObject:imageManager];
35 | }
36 |
37 | - (void)removeImageManager:(nonnull id)imageManager {
38 | [_managers removeObject:imageManager];
39 | }
40 |
41 | #pragma mark
42 |
43 | - (BOOL)canHandleRequest:(nonnull DFImageRequest *)request {
44 | return DFManagerForRequest(request) != nil;
45 | }
46 |
47 | - (nonnull DFImageTask *)imageTaskForResource:(nonnull id)resource completion:(nullable DFImageTaskCompletion)completion {
48 | return [self imageTaskForRequest:[DFImageRequest requestWithResource:resource] completion:completion];
49 | }
50 |
51 | - (nonnull DFImageTask *)imageTaskForRequest:(nonnull DFImageRequest *)request completion:(nullable DFImageTaskCompletion)completion {
52 | id manager = DFManagerForRequest(request);
53 | if (!manager) {
54 | [NSException raise:NSInvalidArgumentException format:@"There are no managers that can handle the request %@", request];
55 | }
56 | return [manager imageTaskForRequest:request completion:completion];
57 | }
58 |
59 | - (void)getImageTasksWithCompletion:(void (^ __nullable)(NSArray * __nonnull, NSArray * __nonnull))completion {
60 | NSMutableArray *allTasks = [NSMutableArray new];
61 | NSMutableArray *allPreheatingTasks = [NSMutableArray new];
62 | NSInteger __block numberOfCallbacks = (NSInteger)_managers.count;
63 | for (id manager in _managers) {
64 | [manager getImageTasksWithCompletion:^(NSArray *tasks, NSArray *preheatingTasks) {
65 | [allTasks addObjectsFromArray:tasks];
66 | [allPreheatingTasks addObjectsFromArray:preheatingTasks];
67 | numberOfCallbacks--;
68 | if (numberOfCallbacks == 0) {
69 | completion(allTasks, allPreheatingTasks);
70 | }
71 | }];
72 | }
73 | }
74 |
75 | - (void)invalidateAndCancel {
76 | for (id manager in _managers) {
77 | [manager invalidateAndCancel];
78 | }
79 | }
80 |
81 | - (void)startPreheatingImagesForRequests:(nonnull NSArray *)requests {
82 | NSMapTable *table = [self _dispatchTableForRequests:requests];
83 | for (id manager in table) {
84 | [manager startPreheatingImagesForRequests:[table objectForKey:manager]];
85 | }
86 | }
87 |
88 | - (void)stopPreheatingImagesForRequests:(nonnull NSArray *)requests {
89 | NSMapTable *table = [self _dispatchTableForRequests:requests];
90 | for (id manager in table) {
91 | [manager stopPreheatingImagesForRequests:[table objectForKey:manager]];
92 | }
93 | }
94 |
95 | - (nonnull NSMapTable *)_dispatchTableForRequests:(nonnull NSArray *)inputRequests {
96 | id manager;
97 | NSMutableArray *requests;
98 | NSMapTable *table = [NSMapTable strongToStrongObjectsMapTable];
99 | for (DFImageRequest *request in inputRequests) {
100 | if (![manager canHandleRequest:request]) {
101 | manager = DFManagerForRequest(request);
102 | if (!manager) {
103 | [NSException raise:NSInvalidArgumentException format:@"There are no managers that can handle the request %@", request];
104 | }
105 | requests = [table objectForKey:manager];
106 | if (!requests) {
107 | requests = [NSMutableArray new];
108 | [table setObject:requests forKey:manager];
109 | }
110 | }
111 | [requests addObject:request];
112 | }
113 | return table;
114 | }
115 |
116 | - (void)stopPreheatingImagesForAllRequests {
117 | for (id manager in _managers) {
118 | [manager stopPreheatingImagesForAllRequests];
119 | }
120 | }
121 |
122 | - (void)removeAllCachedImages {
123 | for (id manager in _managers) {
124 | [manager removeAllCachedImages];
125 | }
126 | }
127 |
128 | @end
129 |
--------------------------------------------------------------------------------
/Demo/DFImageManager/Source/SDFGIFDemoViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // SDFGIFSampleViewController.m
3 | // DFImageManagerSample
4 | //
5 | // Created by Alexander Grebenyuk on 3/5/15.
6 | // Copyright (c) 2015 Alexander Grebenyuk. All rights reserved.
7 | //
8 |
9 | #import "SDFGIFDemoViewController.h"
10 | #import "SDFImageCollectionViewCell.h"
11 | #import
12 | #import
13 |
14 |
15 | static NSString *const kReuseIdentifierTextViewCell = @"kReuseIdentifierTextViewCell";
16 | static NSString *const kReuseIdentifierImageCell = @"kReuseIdentifierImageCell";
17 |
18 |
19 | @interface SDFGIFDemoViewController ()
20 |
21 | @end
22 |
23 | @implementation SDFGIFDemoViewController {
24 | NSArray *_imageURLs;
25 | }
26 |
27 | - (instancetype)init {
28 | return [self initWithCollectionViewLayout:[UICollectionViewFlowLayout new]];
29 | }
30 |
31 | - (void)viewDidLoad {
32 | [super viewDidLoad];
33 |
34 | [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kReuseIdentifierTextViewCell];
35 | [self.collectionView registerClass:[SDFImageCollectionViewCell class] forCellWithReuseIdentifier:kReuseIdentifierImageCell];
36 | self.collectionView.alwaysBounceVertical = YES;
37 | self.view.backgroundColor = [UIColor whiteColor];
38 | self.collectionView.backgroundColor = self.view.backgroundColor;
39 |
40 | _imageURLs =
41 | @[
42 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505557/77ff05ac-c2e7-11e4-9a09-ce5b7995cad0.gif"],
43 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505565/8aa02c90-c2e7-11e4-8127-71df010ca06d.gif"],
44 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505571/a28a6e2e-c2e7-11e4-8161-9f39cc3bb8df.gif"],
45 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505576/b785a8ac-c2e7-11e4-831a-666e2b064b95.gif"],
46 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505579/c88c77ca-c2e7-11e4-88ad-d98c7360602d.gif"],
47 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505595/def06c06-c2e7-11e4-9cdf-d37d28618af0.gif"],
48 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505634/26e5dad2-c2e8-11e4-89c3-3c3a63110ac0.gif"],
49 | [NSURL URLWithString:@"https://cloud.githubusercontent.com/assets/1567433/6505643/42eb3ee8-c2e8-11e4-8666-ac9c8e1dc9b5.gif"]
50 | ];
51 |
52 | UICollectionViewFlowLayout *layout = (id)self.collectionViewLayout;
53 | layout.sectionInset = UIEdgeInsetsMake(8.f, 8.f, 8.f, 8.f);
54 | layout.minimumInteritemSpacing = 8.f;
55 | }
56 |
57 | #pragma mark - UICollectionViewController
58 |
59 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
60 | UICollectionViewCell *cell;
61 | if (indexPath.section == 0) {
62 | cell = [collectionView dequeueReusableCellWithReuseIdentifier:kReuseIdentifierTextViewCell forIndexPath:indexPath];
63 |
64 | UITextView *textView = (id)[cell viewWithTag:14];
65 | if (!textView) {
66 | textView = [UITextView new];
67 | textView.textColor = [UIColor blackColor];
68 | textView.font = [UIFont systemFontOfSize:16.f];
69 | textView.editable = NO;
70 | textView.textAlignment = NSTextAlignmentCenter;
71 | textView.dataDetectorTypes = UIDataDetectorTypeLink;
72 |
73 | [cell.contentView addSubview:textView];
74 | textView.frame = cell.contentView.bounds;
75 | textView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
76 |
77 | textView.text = @"Images by Florian de Looij\n http://flrn.nl/gifs/";
78 | }
79 | } else {
80 | cell = [collectionView dequeueReusableCellWithReuseIdentifier:kReuseIdentifierImageCell forIndexPath:indexPath];
81 | cell.backgroundColor = [UIColor colorWithWhite:235.f/255.f alpha:1.f];
82 |
83 | SDFImageCollectionViewCell *imageCell = (id)cell;
84 | [imageCell setImageWithURL:_imageURLs[indexPath.item]];
85 | }
86 | return cell;
87 | }
88 |
89 | - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
90 | if (indexPath.section == 1) {
91 | SDFImageCollectionViewCell *imageCell = (id)cell;
92 | [imageCell prepareForReuse];
93 | }
94 | }
95 |
96 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
97 | UICollectionViewFlowLayout *layout = (id)self.collectionViewLayout;
98 | CGFloat width = (self.view.bounds.size.width - layout.sectionInset.left - layout.sectionInset.right);
99 | if (indexPath.section == 0) {
100 | return CGSizeMake(width, 50.f);
101 | } else {
102 | return CGSizeMake(width, width);
103 | }
104 | }
105 |
106 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
107 | return 2;
108 | }
109 |
110 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
111 | return section == 0 ? 1 : _imageURLs.count;
112 | }
113 |
114 | @end
115 |
--------------------------------------------------------------------------------