├── .gitignore ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── FLAnimatedImage │ ├── FLAnimatedImage │ │ ├── FLAnimatedImage.h │ │ ├── FLAnimatedImage.m │ │ ├── FLAnimatedImageView.h │ │ └── FLAnimatedImageView.m │ ├── LICENSE │ └── README.md ├── Manifest.lock ├── PINCache │ ├── LICENSE.txt │ ├── PINCache │ │ ├── Nullability.h │ │ ├── PINCache.h │ │ ├── PINCache.m │ │ ├── PINCacheObjectSubscripting.h │ │ ├── PINDiskCache.h │ │ ├── PINDiskCache.m │ │ ├── PINMemoryCache.h │ │ └── PINMemoryCache.m │ └── README.md ├── PINRemoteImage │ ├── LICENSE │ ├── Pod │ │ └── Classes │ │ │ ├── Categories │ │ │ ├── NSData+ImageDetectors.h │ │ │ ├── NSData+ImageDetectors.m │ │ │ ├── PINImage+DecodedImage.h │ │ │ ├── PINImage+DecodedImage.m │ │ │ ├── PINImage+WebP.h │ │ │ └── PINImage+WebP.m │ │ │ ├── Image Categories │ │ │ ├── FLAnimatedImageView+PINRemoteImage.h │ │ │ ├── FLAnimatedImageView+PINRemoteImage.m │ │ │ ├── PINButton+PINRemoteImage.h │ │ │ ├── PINButton+PINRemoteImage.m │ │ │ ├── PINImageView+PINRemoteImage.h │ │ │ └── PINImageView+PINRemoteImage.m │ │ │ ├── PINDataTaskOperation.h │ │ │ ├── PINDataTaskOperation.m │ │ │ ├── PINProgressiveImage.h │ │ │ ├── PINProgressiveImage.m │ │ │ ├── PINRemoteImage.h │ │ │ ├── PINRemoteImageCallbacks.h │ │ │ ├── PINRemoteImageCallbacks.m │ │ │ ├── PINRemoteImageCategoryManager.h │ │ │ ├── PINRemoteImageCategoryManager.m │ │ │ ├── PINRemoteImageDownloadTask.h │ │ │ ├── PINRemoteImageDownloadTask.m │ │ │ ├── PINRemoteImageMacros.h │ │ │ ├── PINRemoteImageManager.h │ │ │ ├── PINRemoteImageManager.m │ │ │ ├── PINRemoteImageManagerResult.h │ │ │ ├── PINRemoteImageManagerResult.m │ │ │ ├── PINRemoteImageProcessorTask.h │ │ │ ├── PINRemoteImageProcessorTask.m │ │ │ ├── PINRemoteImageTask.h │ │ │ ├── PINRemoteImageTask.m │ │ │ ├── PINRemoteLock.h │ │ │ ├── PINRemoteLock.m │ │ │ ├── PINURLSessionManager.h │ │ │ └── PINURLSessionManager.m │ └── README.md ├── Pods.xcodeproj │ └── project.pbxproj └── Target Support Files │ ├── FLAnimatedImage │ ├── FLAnimatedImage-dummy.m │ ├── FLAnimatedImage-prefix.pch │ ├── FLAnimatedImage-umbrella.h │ ├── FLAnimatedImage.modulemap │ ├── FLAnimatedImage.xcconfig │ └── Info.plist │ ├── PINCache │ ├── Info.plist │ ├── PINCache-dummy.m │ ├── PINCache-prefix.pch │ ├── PINCache-umbrella.h │ ├── PINCache.modulemap │ └── PINCache.xcconfig │ ├── PINRemoteImage │ ├── Info.plist │ ├── PINRemoteImage-dummy.m │ ├── PINRemoteImage-prefix.pch │ ├── PINRemoteImage-umbrella.h │ ├── PINRemoteImage.modulemap │ └── PINRemoteImage.xcconfig │ └── Pods-dojo-table-performance │ ├── Info.plist │ ├── Pods-dojo-table-performance-acknowledgements.markdown │ ├── Pods-dojo-table-performance-acknowledgements.plist │ ├── Pods-dojo-table-performance-dummy.m │ ├── Pods-dojo-table-performance-frameworks.sh │ ├── Pods-dojo-table-performance-resources.sh │ ├── Pods-dojo-table-performance-umbrella.h │ ├── Pods-dojo-table-performance.debug.xcconfig │ ├── Pods-dojo-table-performance.modulemap │ └── Pods-dojo-table-performance.release.xcconfig ├── README.md ├── dojo-table-performance.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── dojo-table-performance.xcworkspace └── contents.xcworkspacedata └── dojo-table-performance ├── AppDelegate.swift ├── Base.lproj └── Main.storyboard ├── Dog.swift ├── FeedTableViewCell.swift ├── FeedTableViewController.swift ├── Images.xcassets ├── AppIcon.appiconset │ ├── Contents.json │ ├── icon@2x.png │ └── icon@3x.png ├── Contents.json ├── development.imageset │ ├── Contents.json │ └── development@3x.png ├── icon.imageset │ └── Contents.json ├── like.imageset │ ├── Contents.json │ ├── like@2x.png │ └── like@3x.png ├── like256.imageset │ ├── Contents.json │ └── like256.png ├── siberian0.imageset │ ├── Contents.json │ └── siberian0.png ├── siberian1.imageset │ ├── Contents.json │ └── siberian1.png ├── siberian10.imageset │ ├── Contents.json │ └── siberian10.png ├── siberian11.imageset │ ├── Contents.json │ └── siberian11.png ├── siberian12.imageset │ ├── Contents.json │ └── siberian12.png ├── siberian13.imageset │ ├── Contents.json │ └── siberian13.png ├── siberian14.imageset │ ├── Contents.json │ └── siberian14.png ├── siberian15.imageset │ ├── Contents.json │ └── siberian15.png ├── siberian16.imageset │ ├── Contents.json │ └── siberian16.png ├── siberian17.imageset │ ├── Contents.json │ └── siberian17.png ├── siberian18.imageset │ ├── Contents.json │ └── siberian18.png ├── siberian19.imageset │ ├── Contents.json │ └── siberian19.png ├── siberian2.imageset │ ├── Contents.json │ └── siberian2.png ├── siberian3.imageset │ ├── Contents.json │ └── siberian3.png ├── siberian4.imageset │ ├── Contents.json │ └── siberian4.png ├── siberian5.imageset │ ├── Contents.json │ └── siberian5.png ├── siberian6.imageset │ ├── Contents.json │ └── siberian6.png ├── siberian7.imageset │ ├── Contents.json │ └── siberian7.png ├── siberian8.imageset │ ├── Contents.json │ └── siberian8.png └── siberian9.imageset │ ├── Contents.json │ └── siberian9.png ├── Info.plist └── LaunchScreen_rank_3.xib /.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 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 David McGraw 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 | 23 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'dojo-table-performance' do 4 | pod 'PINRemoteImage' 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FLAnimatedImage (1.0.12) 3 | - PINCache (2.3) 4 | - PINRemoteImage (2.1.4): 5 | - PINRemoteImage/FLAnimatedImage (= 2.1.4) 6 | - PINRemoteImage/Core (2.1.4): 7 | - PINCache (>= 2.1) 8 | - PINRemoteImage/FLAnimatedImage (2.1.4): 9 | - FLAnimatedImage (>= 1.0) 10 | - PINRemoteImage/Core 11 | 12 | DEPENDENCIES: 13 | - PINRemoteImage 14 | 15 | SPEC CHECKSUMS: 16 | FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31 17 | PINCache: ce36ed282031b92fc7733ffe831f474ff80fddc2 18 | PINRemoteImage: 4ac4011c5caefd6befd99758e09becede05d3226 19 | 20 | PODFILE CHECKSUM: f5a32e1fe4c614b012ed3fe719bf998857f64247 21 | 22 | COCOAPODS: 1.2.0 23 | -------------------------------------------------------------------------------- /Pods/FLAnimatedImage/FLAnimatedImage/FLAnimatedImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLAnimatedImage.h 3 | // Flipboard 4 | // 5 | // Created by Raphael Schaad on 7/8/13. 6 | // Copyright (c) 2013-2015 Flipboard. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | // Allow user classes conveniently just importing one header. 13 | #import "FLAnimatedImageView.h" 14 | 15 | 16 | #ifndef NS_DESIGNATED_INITIALIZER 17 | #if __has_attribute(objc_designated_initializer) 18 | #define NS_DESIGNATED_INITIALIZER __attribute((objc_designated_initializer)) 19 | #else 20 | #define NS_DESIGNATED_INITIALIZER 21 | #endif 22 | #endif 23 | 24 | extern const NSTimeInterval kFLAnimatedImageDelayTimeIntervalMinimum; 25 | 26 | // 27 | // An `FLAnimatedImage`'s job is to deliver frames in a highly performant way and works in conjunction with `FLAnimatedImageView`. 28 | // It subclasses `NSObject` and not `UIImage` because it's only an "image" in the sense that a sea lion is a lion. 29 | // It tries to intelligently choose the frame cache size depending on the image and memory situation with the goal to lower CPU usage for smaller ones, lower memory usage for larger ones and always deliver frames for high performant play-back. 30 | // Note: `posterImage`, `size`, `loopCount`, `delayTimes` and `frameCount` don't change after successful initialization. 31 | // 32 | @interface FLAnimatedImage : NSObject 33 | 34 | @property (nonatomic, strong, readonly) UIImage *posterImage; // Guaranteed to be loaded; usually equivalent to `-imageLazilyCachedAtIndex:0` 35 | @property (nonatomic, assign, readonly) CGSize size; // The `.posterImage`'s `.size` 36 | 37 | @property (nonatomic, assign, readonly) NSUInteger loopCount; // 0 means repeating the animation indefinitely 38 | @property (nonatomic, strong, readonly) NSDictionary *delayTimesForIndexes; // Of type `NSTimeInterval` boxed in `NSNumber`s 39 | @property (nonatomic, assign, readonly) NSUInteger frameCount; // Number of valid frames; equal to `[.delayTimes count]` 40 | 41 | @property (nonatomic, assign, readonly) NSUInteger frameCacheSizeCurrent; // Current size of intelligently chosen buffer window; can range in the interval [1..frameCount] 42 | @property (nonatomic, assign) NSUInteger frameCacheSizeMax; // Allow to cap the cache size; 0 means no specific limit (default) 43 | 44 | // Intended to be called from main thread synchronously; will return immediately. 45 | // If the result isn't cached, will return `nil`; the caller should then pause playback, not increment frame counter and keep polling. 46 | // After an initial loading time, depending on `frameCacheSize`, frames should be available immediately from the cache. 47 | - (UIImage *)imageLazilyCachedAtIndex:(NSUInteger)index; 48 | 49 | // Pass either a `UIImage` or an `FLAnimatedImage` and get back its size 50 | + (CGSize)sizeForImage:(id)image; 51 | 52 | // On success, the initializers return an `FLAnimatedImage` with all fields initialized, on failure they return `nil` and an error will be logged. 53 | - (instancetype)initWithAnimatedGIFData:(NSData *)data; 54 | // Pass 0 for optimalFrameCacheSize to get the default, predrawing is enabled by default. 55 | - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NSUInteger)optimalFrameCacheSize predrawingEnabled:(BOOL)isPredrawingEnabled NS_DESIGNATED_INITIALIZER; 56 | + (instancetype)animatedImageWithGIFData:(NSData *)data; 57 | 58 | @property (nonatomic, strong, readonly) NSData *data; // The data the receiver was initialized with; read-only 59 | 60 | @end 61 | 62 | typedef NS_ENUM(NSUInteger, FLLogLevel) { 63 | FLLogLevelNone = 0, 64 | FLLogLevelError, 65 | FLLogLevelWarn, 66 | FLLogLevelInfo, 67 | FLLogLevelDebug, 68 | FLLogLevelVerbose 69 | }; 70 | 71 | @interface FLAnimatedImage (Logging) 72 | 73 | + (void)setLogBlock:(void (^)(NSString *logString, FLLogLevel logLevel))logBlock logLevel:(FLLogLevel)logLevel; 74 | + (void)logStringFromBlock:(NSString *(^)(void))stringBlock withLevel:(FLLogLevel)level; 75 | 76 | @end 77 | 78 | #define FLLog(logLevel, format, ...) [FLAnimatedImage logStringFromBlock:^NSString *{ return [NSString stringWithFormat:(format), ## __VA_ARGS__]; } withLevel:(logLevel)] 79 | 80 | @interface FLWeakProxy : NSProxy 81 | 82 | + (instancetype)weakProxyForObject:(id)targetObject; 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /Pods/FLAnimatedImage/FLAnimatedImage/FLAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLAnimatedImageView.h 3 | // Flipboard 4 | // 5 | // Created by Raphael Schaad on 7/8/13. 6 | // Copyright (c) 2013-2015 Flipboard. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | @class FLAnimatedImage; 13 | @protocol FLAnimatedImageViewDebugDelegate; 14 | 15 | 16 | // 17 | // An `FLAnimatedImageView` can take an `FLAnimatedImage` and plays it automatically when in view hierarchy and stops when removed. 18 | // The animation can also be controlled with the `UIImageView` methods `-start/stop/isAnimating`. 19 | // It is a fully compatible `UIImageView` subclass and can be used as a drop-in component to work with existing code paths expecting to display a `UIImage`. 20 | // Under the hood it uses a `CADisplayLink` for playback, which can be inspected with `currentFrame` & `currentFrameIndex`. 21 | // 22 | @interface FLAnimatedImageView : UIImageView 23 | 24 | // Setting `[UIImageView.image]` to a non-`nil` value clears out existing `animatedImage`. 25 | // And vice versa, setting `animatedImage` will initially populate the `[UIImageView.image]` to its `posterImage` and then start animating and hold `currentFrame`. 26 | @property (nonatomic, strong) FLAnimatedImage *animatedImage; 27 | @property (nonatomic, copy) void(^loopCompletionBlock)(NSUInteger loopCountRemaining); 28 | 29 | @property (nonatomic, strong, readonly) UIImage *currentFrame; 30 | @property (nonatomic, assign, readonly) NSUInteger currentFrameIndex; 31 | 32 | // The animation runloop mode. Enables playback during scrolling by allowing timer events (i.e. animation) with NSRunLoopCommonModes. 33 | // To keep scrolling smooth on single-core devices such as iPhone 3GS/4 and iPod Touch 4th gen, the default run loop mode is NSDefaultRunLoopMode. Otherwise, the default is NSDefaultRunLoopMode. 34 | @property (nonatomic, copy) NSString *runLoopMode; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Pods/FLAnimatedImage/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2016 Flipboard 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 | -------------------------------------------------------------------------------- /Pods/FLAnimatedImage/README.md: -------------------------------------------------------------------------------- 1 | FLAnimatedImage is a performant animated GIF engine for iOS: 2 | 3 | - Plays multiple GIFs simultaneously with a playback speed comparable to desktop browsers 4 | - Honors variable frame delays 5 | - Behaves gracefully under memory pressure 6 | - Eliminates delays or blocking during the first playback loop 7 | - Interprets the frame delays of fast GIFs the same way modern browsers do 8 | 9 | It's a well-tested [component that powers all GIFs in Flipboard](http://engineering.flipboard.com/2014/05/animated-gif/). To understand its behavior it comes with an interactive demo: 10 | 11 | ![Flipboard playing multiple GIFs](https://github.com/Flipboard/FLAnimatedImage/raw/master/images/flanimatedimage-demo-player.gif) 12 | 13 | ## Who is this for? 14 | 15 | - Apps that don't support animated GIFs yet 16 | - Apps that already support animated GIFs but want a higher performance solution 17 | - People who want to tinker with the code ([the corresponding blog post](http://engineering.flipboard.com/2014/05/animated-gif/) is a great place to start; also see the *To Do* section below) 18 | 19 | ## Installation & Usage 20 | 21 | FLAnimatedImage is a well encapsulated drop-in component. Simply replace your `UIImageView` instances with instances of `FLAnimatedImageView` to get animated GIF support. There is no central cache or state to manage. 22 | 23 | If using CocoaPods, the quickest way to try it out is to type this on the command line: 24 | 25 | ```shell 26 | $ pod try FLAnimatedImage 27 | ``` 28 | 29 | To add it to your app, copy the two classes `FLAnimatedImage.h/.m` and `FLAnimatedImageView.h/.m` into your Xcode project or add via [CocoaPods](http://cocoapods.org) by adding this to your Podfile: 30 | 31 | ```ruby 32 | pod 'FLAnimatedImage', '~> 1.0' 33 | ``` 34 | 35 | If using [Carthage](https://github.com/Carthage/Carthage), add following line into your `Cartfile` 36 | 37 | ``` 38 | github "Flipboard/FLAnimatedImage" 39 | ``` 40 | 41 | In your code, `#import "FLAnimatedImage.h"`, create an image from an animated GIF, and setup the image view to display it: 42 | 43 | ```objective-c 44 | FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"]]]; 45 | FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init]; 46 | imageView.animatedImage = image; 47 | imageView.frame = CGRectMake(0.0, 0.0, 100.0, 100.0); 48 | [self.view addSubview:imageView]; 49 | ``` 50 | 51 | It's flexible to integrate in your custom image loading stack and backwards compatible to iOS 6. 52 | 53 | It uses ARC and the Apple frameworks `QuartzCore`, `ImageIO`, `MobileCoreServices`, and `CoreGraphics`. 54 | 55 | It is capable of fine-grained logging. A block can be set on `FLAnimatedImage` that's invoked when logging occurs with various log levels via the `+setLogBlock:logLevel:` method. For example: 56 | 57 | ```objective-c 58 | // Set up FLAnimatedImage logging. 59 | [FLAnimatedImage setLogBlock:^(NSString *logString, FLLogLevel logLevel) { 60 | // Using NSLog 61 | NSLog(@"%@", logString); 62 | 63 | // ...or CocoaLumberjackLogger only logging warnings and errors 64 | if (logLevel == FLLogLevelError) { 65 | DDLogError(@"%@", logString); 66 | } else if (logLevel == FLLogLevelWarn) { 67 | DDLogWarn(@"%@", logString); 68 | } 69 | } logLevel:FLLogLevelWarn]; 70 | ``` 71 | 72 | Since FLAnimatedImage is licensed under MIT, it's compatible with the terms of using it for any app on the App Store. 73 | 74 | ## To Do 75 | - Support other animated image formats such as APNG or WebP (WebP support implemented [here](https://github.com/Flipboard/FLAnimatedImage/pull/86)) 76 | - Integration into network libraries and image caches 77 | - Investigate whether `FLAnimatedImage` should become a `UIImage` subclass 78 | - Smarter buffering 79 | - Bring demo app to iPhone 80 | 81 | This has successfully shipped to many people as is, but please do come with your questions, issues and pull requests! 82 | 83 | ## Select apps using FLAnimatedImage 84 | - [Dropbox](https://www.dropbox.com) 85 | - [Medium](https://medium.com) 86 | - [Facebook](https://facebook.com) 87 | - [Pinterest](https://pinterest.com) 88 | - [LiveBooth](http://www.liveboothapp.com) 89 | - [Design Shots](https://itunes.apple.com/app/id792517951) 90 | - [lWlVl Festival](http://lwlvl.com) 91 | - [Close-up](http://closeu.pe) 92 | - [Zip Code Finder](https://itunes.apple.com/app/id893031254) 93 | - [getGIF](https://itunes.apple.com/app/id964784701) 94 | - [Giffage](http://giffage.com) 95 | - [Flipboard](https://flipboard.com) 96 | - [Gifalicious](https://itunes.apple.com/us/app/gifalicious-see-your-gifs/id965346708?mt=8) 97 | - [Slack](https://slack.com/) 98 | - [Telegram](https://telegram.org/) 99 | - [HashPhotos](https://itunes.apple.com/app/id685784609) 100 | - [Ello](https://ello.co/) 101 | - [Dumpert](http://dumpert.nl) 102 | 103 | If you're using FLAnimatedImage in your app please open a PR to add it to this list! 104 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FLAnimatedImage (1.0.12) 3 | - PINCache (2.3) 4 | - PINRemoteImage (2.1.4): 5 | - PINRemoteImage/FLAnimatedImage (= 2.1.4) 6 | - PINRemoteImage/Core (2.1.4): 7 | - PINCache (>= 2.1) 8 | - PINRemoteImage/FLAnimatedImage (2.1.4): 9 | - FLAnimatedImage (>= 1.0) 10 | - PINRemoteImage/Core 11 | 12 | DEPENDENCIES: 13 | - PINRemoteImage 14 | 15 | SPEC CHECKSUMS: 16 | FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31 17 | PINCache: ce36ed282031b92fc7733ffe831f474ff80fddc2 18 | PINRemoteImage: 4ac4011c5caefd6befd99758e09becede05d3226 19 | 20 | PODFILE CHECKSUM: f5a32e1fe4c614b012ed3fe719bf998857f64247 21 | 22 | COCOAPODS: 1.2.0 23 | -------------------------------------------------------------------------------- /Pods/PINCache/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2013] [Tumblr, Inc.] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Pods/PINCache/PINCache/Nullability.h: -------------------------------------------------------------------------------- 1 | // PINCache is a modified version of TMCache 2 | // Modifications by Garrett Moon 3 | // Copyright (c) 2015 Pinterest. All rights reserved. 4 | 5 | #ifndef PINCache_nullability_h 6 | #define PINCache_nullability_h 7 | 8 | #if !__has_feature(nullability) 9 | #define NS_ASSUME_NONNULL_BEGIN 10 | #define NS_ASSUME_NONNULL_END 11 | #define nullable 12 | #define nonnull 13 | #define null_unspecified 14 | #define null_resettable 15 | #define __nullable 16 | #define __nonnull 17 | #define __null_unspecified 18 | #endif 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /Pods/PINCache/PINCache/PINCache.h: -------------------------------------------------------------------------------- 1 | // PINCache is a modified version of TMCache 2 | // Modifications by Garrett Moon 3 | // Copyright (c) 2015 Pinterest. All rights reserved. 4 | 5 | #import 6 | 7 | #import "PINDiskCache.h" 8 | #import "PINMemoryCache.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @class PINCache; 13 | 14 | /** 15 | A callback block which provides only the cache as an argument 16 | */ 17 | typedef void (^PINCacheBlock)(PINCache *cache); 18 | 19 | /** 20 | A callback block which provides the cache, key and object as arguments 21 | */ 22 | typedef void (^PINCacheObjectBlock)(PINCache *cache, NSString *key, id __nullable object); 23 | 24 | /** 25 | A callback block which provides a BOOL value as argument 26 | */ 27 | typedef void (^PINCacheObjectContainmentBlock)(BOOL containsObject); 28 | 29 | 30 | /** 31 | `PINCache` is a thread safe key/value store designed for persisting temporary objects that are expensive to 32 | reproduce, such as downloaded data or the results of slow processing. It is comprised of two self-similar 33 | stores, one in memory () and one on disk (). 34 | 35 | `PINCache` itself actually does very little; its main function is providing a front end for a common use case: 36 | a small, fast memory cache that asynchronously persists itself to a large, slow disk cache. When objects are 37 | removed from the memory cache in response to an "apocalyptic" event they remain in the disk cache and are 38 | repopulated in memory the next time they are accessed. `PINCache` also does the tedious work of creating a 39 | dispatch group to wait for both caches to finish their operations without blocking each other. 40 | 41 | The parallel caches are accessible as public properties ( and ) and can be manipulated 42 | separately if necessary. See the docs for and for more details. 43 | 44 | @warning when using in extension or watch extension, define PIN_APP_EXTENSIONS=1 45 | */ 46 | 47 | @interface PINCache : NSObject 48 | 49 | #pragma mark - 50 | /// @name Core 51 | 52 | /** 53 | The name of this cache, used to create the and also appearing in stack traces. 54 | */ 55 | @property (readonly) NSString *name; 56 | 57 | /** 58 | A concurrent queue on which blocks passed to the asynchronous access methods are run. 59 | */ 60 | @property (readonly) dispatch_queue_t concurrentQueue; 61 | 62 | /** 63 | Synchronously retrieves the total byte count of the on the shared disk queue. 64 | */ 65 | @property (readonly) NSUInteger diskByteCount; 66 | 67 | /** 68 | The underlying disk cache, see for additional configuration and trimming options. 69 | */ 70 | @property (readonly) PINDiskCache *diskCache; 71 | 72 | /** 73 | The underlying memory cache, see for additional configuration and trimming options. 74 | */ 75 | @property (readonly) PINMemoryCache *memoryCache; 76 | 77 | #pragma mark - 78 | /// @name Initialization 79 | 80 | /** 81 | A shared cache. 82 | 83 | @result The shared singleton cache instance. 84 | */ 85 | + (instancetype)sharedCache; 86 | 87 | - (instancetype)init NS_UNAVAILABLE; 88 | 89 | /** 90 | Multiple instances with the same name are allowed and can safely access 91 | the same data on disk thanks to the magic of seriality. Also used to create the . 92 | 93 | @see name 94 | @param name The name of the cache. 95 | @result A new cache with the specified name. 96 | */ 97 | - (instancetype)initWithName:(NSString *)name; 98 | 99 | /** 100 | Multiple instances with the same name are allowed and can safely access 101 | the same data on disk thanks to the magic of seriality. Also used to create the . 102 | 103 | @see name 104 | @param name The name of the cache. 105 | @param rootPath The path of the cache on disk. 106 | @result A new cache with the specified name. 107 | */ 108 | - (instancetype)initWithName:(NSString *)name rootPath:(NSString *)rootPath NS_DESIGNATED_INITIALIZER; 109 | 110 | #pragma mark - 111 | /// @name Asynchronous Methods 112 | 113 | /** 114 | This method determines whether an object is present for the given key in the cache. This method returns immediately 115 | and executes the passed block after the object is available, potentially in parallel with other blocks on the 116 | . 117 | 118 | @see containsObjectForKey: 119 | @param key The key associated with the object. 120 | @param block A block to be executed concurrently after the containment check happened 121 | */ 122 | - (void)containsObjectForKey:(NSString *)key block:(PINCacheObjectContainmentBlock)block; 123 | 124 | /** 125 | Retrieves the object for the specified key. This method returns immediately and executes the passed 126 | block after the object is available, potentially in parallel with other blocks on the . 127 | 128 | @param key The key associated with the requested object. 129 | @param block A block to be executed concurrently when the object is available. 130 | */ 131 | - (void)objectForKey:(NSString *)key block:(PINCacheObjectBlock)block; 132 | 133 | /** 134 | Stores an object in the cache for the specified key. This method returns immediately and executes the 135 | passed block after the object has been stored, potentially in parallel with other blocks on the . 136 | 137 | @param object An object to store in the cache. 138 | @param key A key to associate with the object. This string will be copied. 139 | @param block A block to be executed concurrently after the object has been stored, or nil. 140 | */ 141 | - (void)setObject:(id )object forKey:(NSString *)key block:(nullable PINCacheObjectBlock)block; 142 | 143 | /** 144 | Removes the object for the specified key. This method returns immediately and executes the passed 145 | block after the object has been removed, potentially in parallel with other blocks on the . 146 | 147 | @param key The key associated with the object to be removed. 148 | @param block A block to be executed concurrently after the object has been removed, or nil. 149 | */ 150 | - (void)removeObjectForKey:(NSString *)key block:(nullable PINCacheObjectBlock)block; 151 | 152 | /** 153 | Removes all objects from the cache that have not been used since the specified date. This method returns immediately and 154 | executes the passed block after the cache has been trimmed, potentially in parallel with other blocks on the . 155 | 156 | @param date Objects that haven't been accessed since this date are removed from the cache. 157 | @param block A block to be executed concurrently after the cache has been trimmed, or nil. 158 | */ 159 | - (void)trimToDate:(NSDate *)date block:(nullable PINCacheBlock)block; 160 | 161 | /** 162 | Removes all objects from the cache.This method returns immediately and executes the passed block after the 163 | cache has been cleared, potentially in parallel with other blocks on the . 164 | 165 | @param block A block to be executed concurrently after the cache has been cleared, or nil. 166 | */ 167 | - (void)removeAllObjects:(nullable PINCacheBlock)block; 168 | 169 | #pragma mark - 170 | /// @name Synchronous Methods 171 | 172 | /** 173 | This method determines whether an object is present for the given key in the cache. 174 | 175 | @see containsObjectForKey:block: 176 | @param key The key associated with the object. 177 | @result YES if an object is present for the given key in the cache, otherwise NO. 178 | */ 179 | - (BOOL)containsObjectForKey:(NSString *)key; 180 | 181 | /** 182 | Retrieves the object for the specified key. This method blocks the calling thread until the object is available. 183 | Uses a semaphore to achieve synchronicity on the disk cache. 184 | 185 | @see objectForKey:block: 186 | @param key The key associated with the object. 187 | @result The object for the specified key. 188 | */ 189 | - (__nullable id)objectForKey:(NSString *)key; 190 | 191 | /** 192 | Stores an object in the cache for the specified key. This method blocks the calling thread until the object has been set. 193 | Uses a semaphore to achieve synchronicity on the disk cache. 194 | 195 | @see setObject:forKey:block: 196 | @param object An object to store in the cache. 197 | @param key A key to associate with the object. This string will be copied. 198 | */ 199 | - (void)setObject:(id )object forKey:(NSString *)key; 200 | 201 | /** 202 | Removes the object for the specified key. This method blocks the calling thread until the object 203 | has been removed. 204 | Uses a semaphore to achieve synchronicity on the disk cache. 205 | 206 | @param key The key associated with the object to be removed. 207 | */ 208 | - (void)removeObjectForKey:(NSString *)key; 209 | 210 | /** 211 | Removes all objects from the cache that have not been used since the specified date. 212 | This method blocks the calling thread until the cache has been trimmed. 213 | Uses a semaphore to achieve synchronicity on the disk cache. 214 | 215 | @param date Objects that haven't been accessed since this date are removed from the cache. 216 | */ 217 | - (void)trimToDate:(NSDate *)date; 218 | 219 | /** 220 | Removes all objects from the cache. This method blocks the calling thread until the cache has been cleared. 221 | Uses a semaphore to achieve synchronicity on the disk cache. 222 | */ 223 | - (void)removeAllObjects; 224 | 225 | @end 226 | 227 | NS_ASSUME_NONNULL_END 228 | -------------------------------------------------------------------------------- /Pods/PINCache/PINCache/PINCacheObjectSubscripting.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINCacheObjectSubscripting.h 3 | // PINCache 4 | // 5 | // Created by Rocir Marcos Leite Santiago on 4/2/16. 6 | // Copyright © 2016 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol PINCacheObjectSubscripting 12 | 13 | @required 14 | 15 | /** 16 | This method enables using literals on the receiving object, such as `id object = cache[@"key"];`. 17 | 18 | @param key The key associated with the object. 19 | @result The object for the specified key. 20 | */ 21 | - (id)objectForKeyedSubscript:(NSString *)key; 22 | 23 | /** 24 | This method enables using literals on the receiving object, such as `cache[@"key"] = object;`. 25 | 26 | @param object An object to be assigned for the key. 27 | @param key A key to associate with the object. This string will be copied. 28 | */ 29 | - (void)setObject:(id)obj forKeyedSubscript:(NSString *)key; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Pods/PINCache/README.md: -------------------------------------------------------------------------------- 1 | # PINCache 2 | 3 | [![CocoaPods](https://img.shields.io/cocoapods/v/PINCache.svg)](http://cocoadocs.org/docsets/PINCache/) 4 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Tavis CI build](https://img.shields.io/travis/pinterest/PINCache.svg?style=flat)](https://travis-ci.org/pinterest/PINCache) 6 | 7 | ## Fast, non-deadlocking parallel object cache for iOS and OS X. 8 | 9 | [PINCache](PINCache/PINCache.h) is a fork of [TMCache](https://github.com/tumblr/TMCache) re-architected to fix issues with deadlocking caused by heavy use. It is a key/value store designed for persisting temporary objects that are expensive to reproduce, such as downloaded data or the results of slow processing. It is comprised of two self-similar stores, one in memory ([PINMemoryCache](PINCache/PINMemoryCache.h)) and one on disk ([PINDiskCache](PINCache/PINDiskCache.h)), all backed by GCD and safe to access from multiple threads simultaneously. On iOS, `PINMemoryCache` will clear itself when the app receives a memory warning or goes into the background. Objects stored in `PINDiskCache` remain until you trim the cache yourself, either manually or by setting a byte or age limit. 10 | 11 | `PINCache` and `PINDiskCache` accept any object conforming to [NSCoding](https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/Reference/Reference.html). Put things in like this: 12 | 13 | ```objective-c 14 | UIImage *img = [[UIImage alloc] initWithData:data scale:[[UIScreen mainScreen] scale]]; 15 | [[PINCache sharedCache] setObject:img forKey:@"image" block:nil]; // returns immediately 16 | ``` 17 | 18 | Get them back out like this: 19 | 20 | ```objective-c 21 | [[PINCache sharedCache] objectForKey:@"image" 22 | block:^(PINCache *cache, NSString *key, id object) { 23 | UIImage *image = (UIImage *)object; 24 | NSLog(@"image scale: %f", image.scale); 25 | }]; 26 | ``` 27 | 28 | Both `PINMemoryCache` and PINDiskCache use locks to protect reads and writes. `PINCache` coordinates them so that objects added to memory are available immediately to other threads while being written to disk safely in the background. Both caches are public properties of `PINCache`, so it's easy to manipulate one or the other separately if necessary. 29 | 30 | Collections work too. Thanks to the magic of `NSKeyedArchiver`, objects repeated in a collection only occupy the space of one on disk: 31 | 32 | ```objective-c 33 | NSArray *images = @[ image, image, image ]; 34 | [[PINCache sharedCache] setObject:images forKey:@"images"]; 35 | NSLog(@"3 for the price of 1: %d", [[[PINCache sharedCache] diskCache] byteCount]); 36 | ``` 37 | 38 | ## Installation 39 | 40 | ### Manually 41 | 42 | [Download the latest tag](https://github.com/pinterest/PINCache/tags) and drag the `PINCache` folder into your Xcode project. 43 | 44 | Install the docs by double clicking the `.docset` file under `docs/`, or view them online at [cocoadocs.org](http://cocoadocs.org/docsets/PINCache/) 45 | 46 | ### Git Submodule 47 | 48 | git submodule add https://github.com/pinterest/PINCache.git 49 | git submodule update --init 50 | 51 | ### CocoaPods 52 | 53 | Add [PINCache](http://cocoapods.org/?q=name%3APINCache) to your `Podfile` and run `pod install`. 54 | 55 | ### Carthage 56 | 57 | Add the following line to your `Cartfile` and run `carthage update --platform ios`. Then follow [this instruction of Carthage](https://github.com/carthage/carthage#adding-frameworks-to-unit-tests-or-a-framework) to embed the framework. 58 | 59 | ```github "pinterest/PINCache"``` 60 | 61 | ## Requirements 62 | 63 | __PINCache__ requires iOS 5.0 or OS X 10.7 and greater. 64 | 65 | ## Contact 66 | 67 | [Garrett Moon](mailto:garrett@pinterest.com) 68 | 69 | ## License 70 | 71 | Copyright 2013 Tumblr, Inc. 72 | Copyright 2015 Pinterest, Inc. 73 | 74 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 75 | 76 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. [See the License](LICENSE.txt) for the specific language governing permissions and limitations under the License. 77 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Pinterest, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Categories/NSData+ImageDetectors.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ImageDetectors.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/19/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface NSData (PINImageDetectors) 12 | 13 | - (BOOL)pin_isGIF; 14 | #ifdef PIN_WEBP 15 | - (BOOL)pin_isWebP; 16 | #endif 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Categories/NSData+ImageDetectors.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ImageDetectors.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/19/14. 6 | // 7 | // 8 | 9 | #import "NSData+ImageDetectors.h" 10 | 11 | @implementation NSData (PINImageDetectors) 12 | 13 | - (BOOL)pin_isGIF 14 | { 15 | const NSInteger length = 3; 16 | Byte firstBytes[length]; 17 | if ([self length] >= length) { 18 | [self getBytes:&firstBytes length:length]; 19 | //G, I, F 20 | if (firstBytes[0] == 0x47 && firstBytes[1] == 0x49 && firstBytes[2] == 0x46) { 21 | return YES; 22 | } 23 | } 24 | return NO; 25 | } 26 | 27 | #ifdef PIN_WEBP 28 | - (BOOL)pin_isWebP 29 | { 30 | const NSInteger length = 12; 31 | Byte firstBytes[length]; 32 | if ([self length] >= length) { 33 | [self getBytes:&firstBytes length:length]; 34 | //R, I, F, F, -, -, -, -, W, E, B, P 35 | if (firstBytes[0] == 0x52 && firstBytes[1] == 0x49 && firstBytes[2] == 0x46 && firstBytes[3] == 0x46 && firstBytes[8] == 0x57 && firstBytes[9] == 0x45 && firstBytes[10] == 0x42 && firstBytes[11] == 0x50) { 36 | return YES; 37 | } 38 | } 39 | return NO; 40 | } 41 | #endif 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Categories/PINImage+DecodedImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+DecodedImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/19/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #if PIN_TARGET_IOS 12 | #import 13 | #elif PIN_TARGET_MAC 14 | #import 15 | #endif 16 | 17 | #import "PINRemoteImageMacros.h" 18 | 19 | #if !PIN_TARGET_IOS 20 | @interface NSImage (PINiOSMapping) 21 | 22 | @property(nonatomic, readonly, nullable) CGImageRef CGImage; 23 | 24 | + (nullable NSImage *)imageWithData:(nonnull NSData *)imageData; 25 | + (nullable NSImage *)imageWithContentsOfFile:(nonnull NSString *)path; 26 | + (nonnull NSImage *)imageWithCGImage:(nonnull CGImageRef)imageRef; 27 | 28 | @end 29 | #endif 30 | 31 | NSData * __nullable PINImageJPEGRepresentation(PINImage * __nonnull image, CGFloat compressionQuality); 32 | NSData * __nullable PINImagePNGRepresentation(PINImage * __nonnull image); 33 | 34 | @interface PINImage (PINDecodedImage) 35 | 36 | + (nullable PINImage *)pin_decodedImageWithData:(nonnull NSData *)data; 37 | + (nullable PINImage *)pin_decodedImageWithData:(nonnull NSData *)data skipDecodeIfPossible:(BOOL)skipDecodeIfPossible; 38 | + (nullable PINImage *)pin_decodedImageWithCGImageRef:(nonnull CGImageRef)imageRef; 39 | #if PIN_TARGET_IOS 40 | + (nullable PINImage *)pin_decodedImageWithCGImageRef:(nonnull CGImageRef)imageRef orientation:(UIImageOrientation) orientation; 41 | #endif 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Categories/PINImage+DecodedImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+DecodedImage.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/19/14. 6 | // 7 | // 8 | 9 | #import "PINImage+DecodedImage.h" 10 | 11 | #import 12 | 13 | #ifdef PIN_WEBP 14 | #import "PINImage+WebP.h" 15 | #endif 16 | 17 | #import "NSData+ImageDetectors.h" 18 | 19 | #if !PIN_TARGET_IOS 20 | @implementation NSImage (PINiOSMapping) 21 | 22 | - (CGImageRef)CGImage 23 | { 24 | NSGraphicsContext *context = [NSGraphicsContext currentContext]; 25 | NSRect rect = NSMakeRect(0.0, 0.0, self.size.width, self.size.height); 26 | return [self CGImageForProposedRect:&rect context:context hints:NULL]; 27 | } 28 | 29 | + (NSImage *)imageWithData:(NSData *)imageData; 30 | { 31 | return [[self alloc] initWithData:imageData]; 32 | } 33 | 34 | + (NSImage *)imageWithContentsOfFile:(NSString *)path 35 | { 36 | return path ? [[self alloc] initWithContentsOfFile:path] : nil; 37 | } 38 | 39 | + (NSImage *)imageWithCGImage:(CGImageRef)imageRef 40 | { 41 | return [[self alloc] initWithCGImage:imageRef size:CGSizeZero]; 42 | } 43 | 44 | @end 45 | #endif 46 | 47 | NSData * __nullable PINImageJPEGRepresentation(PINImage * __nonnull image, CGFloat compressionQuality) 48 | { 49 | #if PIN_TARGET_IOS 50 | return UIImageJPEGRepresentation(image, compressionQuality); 51 | #elif PIN_TARGET_MAC 52 | NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]]; 53 | NSDictionary *imageProperties = @{NSImageCompressionFactor : @(compressionQuality)}; 54 | return [imageRep representationUsingType:NSJPEGFileType properties:imageProperties]; 55 | #endif 56 | } 57 | 58 | NSData * __nullable PINImagePNGRepresentation(PINImage * __nonnull image) { 59 | #if PIN_TARGET_IOS 60 | return UIImagePNGRepresentation(image); 61 | #elif PIN_TARGET_MAC 62 | NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]]; 63 | NSDictionary *imageProperties = @{NSImageCompressionFactor : @1}; 64 | return [imageRep representationUsingType:NSPNGFileType properties:imageProperties]; 65 | #endif 66 | } 67 | 68 | 69 | @implementation PINImage (PINDecodedImage) 70 | 71 | + (PINImage *)pin_decodedImageWithData:(NSData *)data 72 | { 73 | return [self pin_decodedImageWithData:data skipDecodeIfPossible:NO]; 74 | } 75 | 76 | + (PINImage *)pin_decodedImageWithData:(NSData *)data skipDecodeIfPossible:(BOOL)skipDecodeIfPossible 77 | { 78 | if (data == nil) { 79 | return nil; 80 | } 81 | 82 | if ([data pin_isGIF]) { 83 | return [PINImage imageWithData:data]; 84 | } 85 | #ifdef PIN_WEBP 86 | if ([data pin_isWebP]) { 87 | return [PINImage pin_imageWithWebPData:data]; 88 | } 89 | #endif 90 | 91 | PINImage *decodedImage = nil; 92 | 93 | CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData((CFDataRef)data, NULL); 94 | 95 | if (imageSourceRef) { 96 | CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSourceRef, 0, (CFDictionaryRef)@{(NSString *)kCGImageSourceShouldCache : (NSNumber *)kCFBooleanFalse}); 97 | if (imageRef) { 98 | #if PIN_TARGET_IOS 99 | UIImageOrientation orientation = pin_UIImageOrientationFromImageSource(imageSourceRef); 100 | if (skipDecodeIfPossible) { 101 | decodedImage = [PINImage imageWithCGImage:imageRef scale:1.0 orientation:orientation]; 102 | } else { 103 | decodedImage = [self pin_decodedImageWithCGImageRef:imageRef orientation:orientation]; 104 | } 105 | #elif PIN_TARGET_MAC 106 | if (skipDecodeIfPossible) { 107 | CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); 108 | decodedImage = [[NSImage alloc] initWithCGImage:imageRef size:imageSize]; 109 | } else { 110 | decodedImage = [self pin_decodedImageWithCGImageRef:imageRef]; 111 | } 112 | #endif 113 | CGImageRelease(imageRef); 114 | } 115 | 116 | CFRelease(imageSourceRef); 117 | } 118 | 119 | return decodedImage; 120 | } 121 | 122 | + (PINImage *)pin_decodedImageWithCGImageRef:(CGImageRef)imageRef 123 | { 124 | #if PIN_TARGET_IOS 125 | return [self pin_decodedImageWithCGImageRef:imageRef orientation:UIImageOrientationUp]; 126 | } 127 | 128 | + (PINImage *)pin_decodedImageWithCGImageRef:(CGImageRef)imageRef orientation:(UIImageOrientation)orientation 129 | { 130 | #endif 131 | BOOL opaque = YES; 132 | CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef); 133 | if (alpha == kCGImageAlphaFirst || alpha == kCGImageAlphaLast || alpha == kCGImageAlphaOnly || alpha == kCGImageAlphaPremultipliedFirst || alpha == kCGImageAlphaPremultipliedLast) { 134 | opaque = NO; 135 | } 136 | 137 | CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); 138 | 139 | CGBitmapInfo info = opaque ? (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) : (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); 140 | CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 141 | 142 | //Use UIGraphicsBeginImageContext parameters from docs: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIGraphicsBeginImageContextWithOptions 143 | CGContextRef ctx = CGBitmapContextCreate(NULL, imageSize.width, imageSize.height, 144 | 8, 145 | 0, 146 | colorspace, 147 | info); 148 | 149 | CGColorSpaceRelease(colorspace); 150 | 151 | PINImage *decodedImage = nil; 152 | if (ctx) { 153 | CGContextDrawImage(ctx, CGRectMake(0, 0, imageSize.width, imageSize.height), imageRef); 154 | 155 | CGImageRef newImage = CGBitmapContextCreateImage(ctx); 156 | 157 | #if PIN_TARGET_IOS 158 | decodedImage = [UIImage imageWithCGImage:newImage scale:1.0 orientation:orientation]; 159 | #elif PIN_TARGET_MAC 160 | decodedImage = [[NSImage alloc] initWithCGImage:newImage size:imageSize]; 161 | #endif 162 | CGImageRelease(newImage); 163 | CGContextRelease(ctx); 164 | 165 | } else { 166 | #if PIN_TARGET_IOS 167 | decodedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:orientation]; 168 | #elif PIN_TARGET_MAC 169 | decodedImage = [[NSImage alloc] initWithCGImage:imageRef size:imageSize]; 170 | #endif 171 | } 172 | 173 | return decodedImage; 174 | } 175 | 176 | #if PIN_TARGET_IOS 177 | UIImageOrientation pin_UIImageOrientationFromImageSource(CGImageSourceRef imageSourceRef) { 178 | UIImageOrientation orientation = UIImageOrientationUp; 179 | 180 | if (imageSourceRef != nil) { 181 | NSDictionary *dict = (NSDictionary *)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0, NULL)); 182 | 183 | if (dict != nil) { 184 | 185 | NSNumber* exifOrientation = dict[(id)kCGImagePropertyOrientation]; 186 | if (exifOrientation != nil) { 187 | 188 | switch (exifOrientation.intValue) { 189 | case 1: /*kCGImagePropertyOrientationUp*/ 190 | orientation = UIImageOrientationUp; 191 | break; 192 | 193 | case 2: /*kCGImagePropertyOrientationUpMirrored*/ 194 | orientation = UIImageOrientationUpMirrored; 195 | break; 196 | 197 | case 3: /*kCGImagePropertyOrientationDown*/ 198 | orientation = UIImageOrientationDown; 199 | break; 200 | 201 | case 4: /*kCGImagePropertyOrientationDownMirrored*/ 202 | orientation = UIImageOrientationDownMirrored; 203 | break; 204 | case 5: /*kCGImagePropertyOrientationLeftMirrored*/ 205 | orientation = UIImageOrientationLeftMirrored; 206 | break; 207 | 208 | case 6: /*kCGImagePropertyOrientationRight*/ 209 | orientation = UIImageOrientationRight; 210 | break; 211 | 212 | case 7: /*kCGImagePropertyOrientationRightMirrored*/ 213 | orientation = UIImageOrientationRightMirrored; 214 | break; 215 | 216 | case 8: /*kCGImagePropertyOrientationLeft*/ 217 | orientation = UIImageOrientationLeft; 218 | break; 219 | 220 | default: 221 | break; 222 | } 223 | } 224 | } 225 | } 226 | 227 | return orientation; 228 | } 229 | 230 | #endif 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Categories/PINImage+WebP.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+WebP.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/18/14. 6 | // 7 | // 8 | 9 | #ifdef PIN_WEBP 10 | 11 | #if PIN_TARGET_IOS 12 | #import 13 | #elif PIN_TARGET_MAC 14 | #import 15 | #endif 16 | 17 | #import "PINRemoteImageMacros.h" 18 | 19 | @interface PINImage (PINWebP) 20 | 21 | + (PINImage *)pin_imageWithWebPData:(NSData *)webPData; 22 | 23 | @end 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Categories/PINImage+WebP.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+WebP.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/18/14. 6 | // 7 | // 8 | 9 | #import "PINImage+WebP.h" 10 | 11 | #ifdef PIN_WEBP 12 | #if !COCOAPODS 13 | #import "webp/decode.h" 14 | #else 15 | #import "libwebp/webp/decode.h" 16 | #endif 17 | 18 | static void releaseData(void *info, const void *data, size_t size) 19 | { 20 | free((void *)data); 21 | } 22 | 23 | @implementation PINImage (PINWebP) 24 | 25 | + (PINImage *)pin_imageWithWebPData:(NSData *)webPData 26 | { 27 | WebPBitstreamFeatures features; 28 | if (WebPGetFeatures([webPData bytes], [webPData length], &features) == VP8_STATUS_OK) { 29 | // Decode the WebP image data into a RGBA value array 30 | int height, width; 31 | uint8_t *data = NULL; 32 | int pixelLength = 0; 33 | 34 | if (features.has_alpha) { 35 | data = WebPDecodeRGBA([webPData bytes], [webPData length], &width, &height); 36 | pixelLength = 4; 37 | } else { 38 | data = WebPDecodeRGB([webPData bytes], [webPData length], &width, &height); 39 | pixelLength = 3; 40 | } 41 | 42 | if (data) { 43 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, width * height * pixelLength, releaseData); 44 | 45 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 46 | CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; 47 | 48 | if (features.has_alpha) { 49 | bitmapInfo |= kCGImageAlphaLast; 50 | } else { 51 | bitmapInfo |= kCGImageAlphaNone; 52 | } 53 | 54 | CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; 55 | CGImageRef imageRef = CGImageCreate(width, 56 | height, 57 | 8, 58 | 8 * pixelLength, 59 | pixelLength * width, 60 | colorSpaceRef, 61 | bitmapInfo, 62 | provider, 63 | NULL, 64 | NO, 65 | renderingIntent); 66 | 67 | PINImage *image = nil; 68 | #if PIN_TARGET_IOS 69 | image = [UIImage imageWithCGImage:imageRef]; 70 | #elif PIN_TARGET_MAC 71 | image = [[self alloc] initWithCGImage:imageRef size:CGSizeZero]; 72 | #endif 73 | 74 | CGImageRelease(imageRef); 75 | CGColorSpaceRelease(colorSpaceRef); 76 | CGDataProviderRelease(provider); 77 | 78 | return image; 79 | } 80 | } 81 | return nil; 82 | } 83 | 84 | @end 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Image Categories/FLAnimatedImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // FLAnimatedImageView+PINRemoteImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/17/14. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageMacros.h" 10 | #if USE_FLANIMATED_IMAGE 11 | #import 12 | 13 | #import "PINRemoteImageCategoryManager.h" 14 | 15 | @interface FLAnimatedImageView (PINRemoteImage) 16 | 17 | @end 18 | 19 | #endif -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Image Categories/FLAnimatedImageView+PINRemoteImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // FLAnimatedImageView+PINRemoteImage.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/17/14. 6 | // 7 | // 8 | 9 | #import "FLAnimatedImageView+PINRemoteImage.h" 10 | 11 | #if USE_FLANIMATED_IMAGE 12 | @implementation FLAnimatedImageView (PINRemoteImage) 13 | 14 | - (void)pin_setImageFromURL:(NSURL *)url 15 | { 16 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url]; 17 | } 18 | 19 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage 20 | { 21 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage]; 22 | } 23 | 24 | - (void)pin_setImageFromURL:(NSURL *)url completion:(PINRemoteImageManagerImageCompletion)completion 25 | { 26 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url completion:completion]; 27 | } 28 | 29 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 30 | { 31 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage completion:completion]; 32 | } 33 | 34 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 35 | { 36 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor]; 37 | } 38 | 39 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 40 | { 41 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage processorKey:processorKey processor:processor]; 42 | } 43 | 44 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 45 | { 46 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor completion:completion]; 47 | } 48 | 49 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 50 | { 51 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:@[url] placeholderImage:placeholderImage processorKey:processorKey processor:processor completion:completion]; 52 | } 53 | 54 | - (void)pin_setImageFromURLs:(NSArray *)urls 55 | { 56 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls]; 57 | } 58 | 59 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(UIImage *)placeholderImage 60 | { 61 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage]; 62 | } 63 | 64 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(UIImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 65 | { 66 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage completion:completion]; 67 | } 68 | 69 | - (void)pin_cancelImageDownload 70 | { 71 | [PINRemoteImageCategoryManager cancelImageDownloadOnView:self]; 72 | } 73 | 74 | - (NSUUID *)pin_downloadImageOperationUUID 75 | { 76 | return [PINRemoteImageCategoryManager downloadImageOperationUUIDOnView:self]; 77 | } 78 | 79 | - (void)pin_setDownloadImageOperationUUID:(NSUUID *)downloadImageOperationUUID 80 | { 81 | [PINRemoteImageCategoryManager setDownloadImageOperationUUID:downloadImageOperationUUID onView:self]; 82 | } 83 | 84 | - (BOOL)pin_updateWithProgress 85 | { 86 | return [PINRemoteImageCategoryManager updateWithProgressOnView:self]; 87 | } 88 | 89 | - (void)setPin_updateWithProgress:(BOOL)updateWithProgress 90 | { 91 | [PINRemoteImageCategoryManager setUpdateWithProgressOnView:updateWithProgress onView:self]; 92 | } 93 | 94 | - (void)pin_setPlaceholderWithImage:(UIImage *)image 95 | { 96 | self.image = image; 97 | } 98 | 99 | - (void)pin_updateUIWithImage:(UIImage *)image animatedImage:(FLAnimatedImage *)animatedImage 100 | { 101 | if (animatedImage) { 102 | self.animatedImage = animatedImage; 103 | [self setNeedsLayout]; 104 | } else if (image) { 105 | self.image = image; 106 | [self setNeedsLayout]; 107 | } 108 | } 109 | 110 | - (void)pin_clearImages 111 | { 112 | self.animatedImage = nil; 113 | self.image = nil; 114 | [self setNeedsLayout]; 115 | } 116 | 117 | - (BOOL)pin_ignoreGIFs 118 | { 119 | return NO; 120 | } 121 | 122 | @end 123 | 124 | #endif -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Image Categories/PINButton+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+PINRemoteImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/18/14. 6 | // 7 | // 8 | 9 | #if PIN_TARGET_IOS 10 | #import 11 | #elif PIN_TARGET_MAC 12 | #import 13 | #endif 14 | 15 | #import "PINRemoteImageManager.h" 16 | #import "PINRemoteImageCategoryManager.h" 17 | 18 | @interface PINButton (PINRemoteImage) 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Image Categories/PINButton+PINRemoteImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+PINRemoteImage.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/18/14. 6 | // 7 | // 8 | 9 | #import "PINButton+PINRemoteImage.h" 10 | 11 | @implementation PINButton (PINRemoteImage) 12 | 13 | - (void)pin_setImageFromURL:(NSURL *)url 14 | { 15 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url]; 16 | } 17 | 18 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage 19 | { 20 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage]; 21 | } 22 | 23 | - (void)pin_setImageFromURL:(NSURL *)url completion:(PINRemoteImageManagerImageCompletion)completion 24 | { 25 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url completion:completion]; 26 | } 27 | 28 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 29 | { 30 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage completion:completion]; 31 | } 32 | 33 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 34 | { 35 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor]; 36 | } 37 | 38 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 39 | { 40 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage processorKey:processorKey processor:processor]; 41 | } 42 | 43 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 44 | { 45 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor completion:completion]; 46 | } 47 | 48 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 49 | { 50 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:url?@[url]:nil placeholderImage:placeholderImage processorKey:processorKey processor:processor completion:completion]; 51 | } 52 | 53 | - (void)pin_setImageFromURLs:(NSArray *)urls 54 | { 55 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls]; 56 | } 57 | 58 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage 59 | { 60 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage]; 61 | } 62 | 63 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 64 | { 65 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage completion:completion]; 66 | } 67 | 68 | - (void)pin_cancelImageDownload 69 | { 70 | [PINRemoteImageCategoryManager cancelImageDownloadOnView:self]; 71 | } 72 | 73 | - (NSUUID *)pin_downloadImageOperationUUID 74 | { 75 | return [PINRemoteImageCategoryManager downloadImageOperationUUIDOnView:self]; 76 | } 77 | 78 | - (void)pin_setDownloadImageOperationUUID:(NSUUID *)downloadImageOperationUUID 79 | { 80 | [PINRemoteImageCategoryManager setDownloadImageOperationUUID:downloadImageOperationUUID onView:self]; 81 | } 82 | 83 | - (BOOL)pin_updateWithProgress 84 | { 85 | return [PINRemoteImageCategoryManager updateWithProgressOnView:self]; 86 | } 87 | 88 | - (void)setPin_updateWithProgress:(BOOL)updateWithProgress 89 | { 90 | [PINRemoteImageCategoryManager setUpdateWithProgressOnView:updateWithProgress onView:self]; 91 | } 92 | 93 | - (void)pin_setPlaceholderWithImage:(PINImage *)image 94 | { 95 | #if PIN_TARGET_IOS 96 | [self setImage:image forState:UIControlStateNormal]; 97 | #elif PIN_TARGET_MAC 98 | [self setImage:image]; 99 | #endif 100 | } 101 | 102 | - (void)pin_updateUIWithImage:(PINImage *)image animatedImage:(FLAnimatedImage *)animatedImage 103 | { 104 | if (image) { 105 | #if PIN_TARGET_IOS 106 | [self setImage:image forState:UIControlStateNormal]; 107 | [self setNeedsLayout]; 108 | #elif PIN_TARGET_MAC 109 | [self setImage:image]; 110 | [self setNeedsLayout:YES]; 111 | #endif 112 | } 113 | } 114 | 115 | - (void)pin_clearImages 116 | { 117 | #if PIN_TARGET_IOS 118 | [self setImage:nil forState:UIControlStateNormal]; 119 | [self setNeedsLayout]; 120 | #elif PIN_TARGET_MAC 121 | [self setImage:nil]; 122 | [self setNeedsLayout:YES]; 123 | #endif 124 | } 125 | 126 | - (BOOL)pin_ignoreGIFs 127 | { 128 | return YES; 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Image Categories/PINImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+PINRemoteImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/17/14. 6 | // 7 | // 8 | 9 | #if PIN_TARGET_IOS 10 | #import 11 | #elif PIN_TARGET_MAC 12 | #import 13 | #endif 14 | 15 | #import "PINRemoteImageManager.h" 16 | #import "PINRemoteImageCategoryManager.h" 17 | 18 | @interface PINImageView (PINRemoteImage) 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/Image Categories/PINImageView+PINRemoteImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+PINRemoteImage.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/17/14. 6 | // 7 | // 8 | 9 | #import "PINImageView+PINRemoteImage.h" 10 | 11 | @implementation PINImageView (PINRemoteImage) 12 | 13 | - (void)pin_setImageFromURL:(NSURL *)url 14 | { 15 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url]; 16 | } 17 | 18 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage 19 | { 20 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage]; 21 | } 22 | 23 | - (void)pin_setImageFromURL:(NSURL *)url completion:(PINRemoteImageManagerImageCompletion)completion 24 | { 25 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url completion:completion]; 26 | } 27 | 28 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 29 | { 30 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage completion:completion]; 31 | } 32 | 33 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 34 | { 35 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor]; 36 | } 37 | 38 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 39 | { 40 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage processorKey:processorKey processor:processor]; 41 | } 42 | 43 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 44 | { 45 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor completion:completion]; 46 | } 47 | 48 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 49 | { 50 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:url?@[url]:nil placeholderImage:placeholderImage processorKey:processorKey processor:processor completion:completion]; 51 | } 52 | 53 | - (void)pin_setImageFromURLs:(NSArray *)urls 54 | { 55 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls]; 56 | } 57 | 58 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage 59 | { 60 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage]; 61 | } 62 | 63 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 64 | { 65 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage completion:completion]; 66 | } 67 | 68 | - (void)pin_cancelImageDownload 69 | { 70 | [PINRemoteImageCategoryManager cancelImageDownloadOnView:self]; 71 | } 72 | 73 | - (NSUUID *)pin_downloadImageOperationUUID 74 | { 75 | return [PINRemoteImageCategoryManager downloadImageOperationUUIDOnView:self]; 76 | } 77 | 78 | - (void)pin_setDownloadImageOperationUUID:(NSUUID *)downloadImageOperationUUID 79 | { 80 | [PINRemoteImageCategoryManager setDownloadImageOperationUUID:downloadImageOperationUUID onView:self]; 81 | } 82 | 83 | - (BOOL)pin_updateWithProgress 84 | { 85 | return [PINRemoteImageCategoryManager updateWithProgressOnView:self]; 86 | } 87 | 88 | - (void)setPin_updateWithProgress:(BOOL)updateWithProgress 89 | { 90 | [PINRemoteImageCategoryManager setUpdateWithProgressOnView:updateWithProgress onView:self]; 91 | } 92 | 93 | - (void)pin_setPlaceholderWithImage:(PINImage *)image 94 | { 95 | self.image = image; 96 | } 97 | 98 | - (void)pin_updateUIWithImage:(PINImage *)image animatedImage:(FLAnimatedImage *)animatedImage 99 | { 100 | if (image) { 101 | self.image = image; 102 | 103 | #if PIN_TARGET_IOS 104 | [self setNeedsLayout]; 105 | #elif PIN_TARGET_MAC 106 | [self setNeedsLayout:YES]; 107 | #endif 108 | } 109 | } 110 | 111 | - (void)pin_clearImages 112 | { 113 | self.image = nil; 114 | 115 | #if PIN_TARGET_IOS 116 | [self setNeedsLayout]; 117 | #elif PIN_TARGET_MAC 118 | [self setNeedsLayout:YES]; 119 | #endif 120 | } 121 | 122 | - (BOOL)pin_ignoreGIFs 123 | { 124 | return YES; 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINDataTaskOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINDataTaskOperation.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/12/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINURLSessionManager.h" 12 | 13 | @interface PINDataTaskOperation : NSOperation 14 | 15 | @property (nonatomic, readonly, nullable) NSURLSessionDataTask *dataTask; 16 | 17 | + (nonnull instancetype)dataTaskOperationWithSessionManager:(nonnull PINURLSessionManager *)sessionManager 18 | request:(nonnull NSURLRequest *)request 19 | completionHandler:(nonnull void (^)(NSURLResponse * _Nonnull response, NSError * _Nullable error))completionHandler; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINDataTaskOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINDataTaskOperation.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/12/15. 6 | // 7 | // 8 | 9 | #import "PINDataTaskOperation.h" 10 | 11 | #import "PINURLSessionManager.h" 12 | 13 | typedef NS_ENUM(NSUInteger, PIDataTaskOperationState) { 14 | PIDataTaskOperationStateReady, 15 | PIDataTaskOperationStateExecuting, 16 | PIDataTaskOperationStateFinished, 17 | }; 18 | 19 | @interface PINDataTaskOperation () 20 | { 21 | NSRecursiveLock *_lock;; 22 | } 23 | 24 | @property (nonatomic, strong, readwrite) NSURLSessionDataTask *dataTask; 25 | @property (nonatomic, assign, readwrite) PIDataTaskOperationState state; 26 | 27 | @end 28 | 29 | static inline NSString * PIKeyPathFromOperationState(PIDataTaskOperationState state) { 30 | switch (state) { 31 | case PIDataTaskOperationStateReady: 32 | return @"isReady"; 33 | case PIDataTaskOperationStateExecuting: 34 | return @"isExecuting"; 35 | case PIDataTaskOperationStateFinished: 36 | return @"isFinished"; 37 | } 38 | } 39 | 40 | @implementation PINDataTaskOperation 41 | 42 | - (instancetype)init 43 | { 44 | if (self = [super init]) { 45 | _state = PIDataTaskOperationStateReady; 46 | _lock = [[NSRecursiveLock alloc] init]; 47 | } 48 | return self; 49 | } 50 | 51 | + (instancetype)dataTaskOperationWithSessionManager:(PINURLSessionManager *)sessionManager 52 | request:(NSURLRequest *)request 53 | completionHandler:(void (^)(NSURLResponse *response, NSError *error))completionHandler 54 | { 55 | PINDataTaskOperation *operation = [[self alloc] init]; 56 | operation.dataTask = [sessionManager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, NSError *error) { 57 | completionHandler(response, error); 58 | if (operation.isCancelled == NO) { 59 | [operation finish]; 60 | } 61 | }]; 62 | 63 | return operation; 64 | } 65 | 66 | - (void)start 67 | { 68 | [self lock]; 69 | if ([self isCancelled]) { 70 | [self cancelTask]; 71 | } else if ([self isReady]) { 72 | self.state = PIDataTaskOperationStateExecuting; 73 | 74 | [self.dataTask resume]; 75 | } 76 | [self unlock]; 77 | } 78 | 79 | - (void)cancel 80 | { 81 | [self lock]; 82 | if (![self isFinished] && ![self isCancelled]) { 83 | [super cancel]; 84 | 85 | if ([self isExecuting]) { 86 | [self cancelTask]; 87 | } 88 | } 89 | [self unlock]; 90 | } 91 | 92 | - (BOOL)isConcurrent 93 | { 94 | return YES; 95 | } 96 | 97 | - (BOOL)isExecuting 98 | { 99 | return self.state == PIDataTaskOperationStateExecuting; 100 | } 101 | 102 | - (BOOL)isFinished 103 | { 104 | return self.state == PIDataTaskOperationStateFinished; 105 | } 106 | 107 | - (void)finish 108 | { 109 | self.state = PIDataTaskOperationStateFinished; 110 | } 111 | 112 | - (void)cancelTask 113 | { 114 | [self lock]; 115 | if (![self isFinished]) { 116 | if (self.dataTask) { 117 | [self.dataTask cancel]; 118 | } 119 | [self finish]; 120 | } 121 | [self unlock]; 122 | } 123 | 124 | - (void)setState:(PIDataTaskOperationState)state 125 | { 126 | [self lock]; 127 | NSString *oldStateKey = PIKeyPathFromOperationState(self.state); 128 | NSString *newStateKey = PIKeyPathFromOperationState(state); 129 | 130 | [self willChangeValueForKey:newStateKey]; 131 | [self willChangeValueForKey:oldStateKey]; 132 | _state = state; 133 | [self didChangeValueForKey:oldStateKey]; 134 | [self didChangeValueForKey:newStateKey]; 135 | [self unlock]; 136 | } 137 | 138 | - (void)lock 139 | { 140 | [_lock lock]; 141 | } 142 | 143 | - (void)unlock 144 | { 145 | [_lock unlock]; 146 | } 147 | 148 | @end 149 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINProgressiveImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINProgressiveImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 2/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #if PIN_TARGET_IOS 12 | #import 13 | #elif PIN_TARGET_MAC 14 | #import 15 | #endif 16 | 17 | #import "PINRemoteImageMacros.h" 18 | 19 | /** An object which store the data of a downloading image and vends progressive scans **/ 20 | @interface PINProgressiveImage : NSObject 21 | 22 | @property (atomic, copy, nonnull) NSArray *progressThresholds; 23 | @property (atomic, assign) CFTimeInterval estimatedRemainingTimeThreshold; 24 | @property (atomic, assign) CFTimeInterval startTime; 25 | 26 | - (void)updateProgressiveImageWithData:(nonnull NSData *)data expectedNumberOfBytes:(int64_t)expectedNumberOfBytes; 27 | 28 | /** 29 | Returns the latest image based on thresholds, returns nil if no new image is generated 30 | 31 | @param blurred A boolean to indicate if the image should be blurred 32 | @param maxProgressiveRenderSize the maximum dimensions at which to apply a blur. If an image exceeds either the height 33 | or width of this dimension, the image will *not* be blurred regardless of the blurred parameter. 34 | @param renderedImageQuality Value between 0 and 1. Computed by dividing the received number of bytes by the expected number of bytes 35 | @return PINImage a progressive scan of the image or nil if a new one has not been generated 36 | */ 37 | - (nullable PINImage *)currentImageBlurred:(BOOL)blurred maxProgressiveRenderSize:(CGSize)maxProgressiveRenderSize renderedImageQuality:(nonnull out CGFloat *)renderedImageQuality; 38 | 39 | /** 40 | Returns the current data for the image. 41 | 42 | @return NSData the current data for the image 43 | */ 44 | - (nullable NSData *)data; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/17/14. 6 | // 7 | // 8 | 9 | #ifndef Pods_PINRemoteImage_h 10 | #define Pods_PINRemoteImage_h 11 | 12 | #import "PINRemoteImageMacros.h" 13 | 14 | #import "PINRemoteImageManager.h" 15 | #import "PINRemoteImageCategoryManager.h" 16 | #import "PINRemoteImageManagerResult.h" 17 | #import "PINProgressiveImage.h" 18 | #import "PINURLSessionManager.h" 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageCallbacks.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageCallbacks.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageManager.h" 12 | 13 | @interface PINRemoteImageCallbacks : NSObject 14 | 15 | @property (nonatomic, strong, nullable) PINRemoteImageManagerImageCompletion completionBlock; 16 | @property (nonatomic, strong, nullable) PINRemoteImageManagerImageCompletion progressImageBlock; 17 | @property (nonatomic, strong, nullable) PINRemoteImageManagerProgressDownload progressDownloadBlock; 18 | @property (nonatomic, assign) CFTimeInterval requestTime; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageCallbacks.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageCallbacks.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageCallbacks.h" 10 | 11 | @implementation PINRemoteImageCallbacks 12 | 13 | - (void)setCompletionBlock:(PINRemoteImageManagerImageCompletion)completionBlock 14 | { 15 | _completionBlock = [completionBlock copy]; 16 | self.requestTime = CACurrentMediaTime(); 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageCategoryManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageCategory.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/4/14. 6 | // 7 | // 8 | 9 | #if PIN_TARGET_IOS 10 | #import 11 | #elif PIN_TARGET_MAC 12 | #import 13 | #endif 14 | 15 | #import "PINRemoteImageManager.h" 16 | 17 | @protocol PINRemoteImageCategory; 18 | 19 | /** 20 | PINRemoteImageCategoryManager is a class that handles subclassing image display classes. PINImage+PINRemoteImage, UIButton+PINRemoteImage, etc, all delegate their work to this class. If you'd like to create a category to display an image on a view, you should mimic one of the above categories. 21 | */ 22 | 23 | @interface PINRemoteImageCategoryManager : NSObject 24 | 25 | + (void)setImageOnView:(nonnull id )view 26 | fromURL:(nullable NSURL *)url; 27 | 28 | + (void)setImageOnView:(nonnull id )view 29 | fromURL:(nullable NSURL *)url 30 | placeholderImage:(nullable PINImage *)placeholderImage; 31 | 32 | + (void)setImageOnView:(nonnull id )view 33 | fromURL:(nullable NSURL *)url 34 | placeholderImage:(nullable PINImage *)placeholderImage 35 | completion:(nullable PINRemoteImageManagerImageCompletion)completion; 36 | 37 | + (void)setImageOnView:(nonnull id )view 38 | fromURL:(nullable NSURL *)url 39 | completion:(nullable PINRemoteImageManagerImageCompletion)completion; 40 | 41 | + (void)setImageOnView:(nonnull id )view 42 | fromURL:(nullable NSURL *)url 43 | processorKey:(nullable NSString *)processorKey 44 | processor:(nullable PINRemoteImageManagerImageProcessor)processor; 45 | 46 | + (void)setImageOnView:(nonnull id )view 47 | fromURL:(nullable NSURL *)url 48 | placeholderImage:(nullable PINImage *)placeholderImage 49 | processorKey:(nullable NSString *)processorKey 50 | processor:(nullable PINRemoteImageManagerImageProcessor)processor; 51 | 52 | + (void)setImageOnView:(nonnull id )view 53 | fromURL:(nullable NSURL *)url 54 | processorKey:(nullable NSString *)processorKey 55 | processor:(nullable PINRemoteImageManagerImageProcessor)processor 56 | completion:(nullable PINRemoteImageManagerImageCompletion)completion; 57 | 58 | + (void)setImageOnView:(nonnull id )view 59 | fromURLs:(nullable NSArray *)urls 60 | placeholderImage:(nullable PINImage *)placeholderImage 61 | processorKey:(nullable NSString *)processorKey 62 | processor:(nullable PINRemoteImageManagerImageProcessor)processor 63 | completion:(nullable PINRemoteImageManagerImageCompletion)completion; 64 | 65 | + (void)setImageOnView:(nonnull id )view 66 | fromURLs:(nullable NSArray *)urls; 67 | 68 | + (void)setImageOnView:(nonnull id )view 69 | fromURLs:(nullable NSArray *)urls 70 | placeholderImage:(nullable PINImage *)placeholderImage; 71 | 72 | + (void)setImageOnView:(nonnull id )view 73 | fromURLs:(nullable NSArray *)urls 74 | placeholderImage:(nullable PINImage *)placeholderImage 75 | completion:(nullable PINRemoteImageManagerImageCompletion)completion; 76 | 77 | + (void)cancelImageDownloadOnView:(nonnull id )view; 78 | 79 | + (nullable NSUUID *)downloadImageOperationUUIDOnView:(nonnull id )view; 80 | 81 | + (void)setDownloadImageOperationUUID:(nullable NSUUID *)downloadImageOperationUUID onView:(nonnull id )view; 82 | 83 | + (BOOL)updateWithProgressOnView:(nonnull id )view; 84 | 85 | + (void)setUpdateWithProgressOnView:(BOOL)updateWithProgress onView:(nonnull id )view; 86 | 87 | @end 88 | 89 | /** 90 | Protocol to implement on UIView subclasses to support PINRemoteImage 91 | */ 92 | @protocol PINRemoteImageCategory 93 | 94 | //Call manager 95 | 96 | /** 97 | Set the image from the given URL. 98 | 99 | @param url NSURL to fetch from. 100 | */ 101 | - (void)pin_setImageFromURL:(nullable NSURL *)url; 102 | 103 | /** 104 | Set the image from the given URL and set placeholder image while image at URL is being retrieved. 105 | 106 | @param url NSURL to fetch from. 107 | @param placeholderImage PINImage to set on the view while the image at URL is being retrieved. 108 | */ 109 | - (void)pin_setImageFromURL:(nullable NSURL *)url placeholderImage:(nullable PINImage *)placeholderImage; 110 | 111 | /** 112 | Set the image from the given URL and call completion when finished. 113 | 114 | @param url NSURL to fetch from. 115 | @param completion Called when url has been retrieved and set on view. 116 | */ 117 | - (void)pin_setImageFromURL:(nullable NSURL *)url completion:(nullable PINRemoteImageManagerImageCompletion)completion; 118 | 119 | /** 120 | Set the image from the given URL, set placeholder while image at url is being retrieved and call completion when finished. 121 | 122 | @param url NSURL to fetch from. 123 | @param placeholderImage PINImage to set on the view while the image at URL is being retrieved. 124 | @param completion Called when url has been retrieved and set on view. 125 | */ 126 | - (void)pin_setImageFromURL:(nullable NSURL *)url placeholderImage:(nullable PINImage *)placeholderImage completion:(nullable PINRemoteImageManagerImageCompletion)completion; 127 | 128 | /** 129 | Retrieve the image from the given URL, process it using the passed in processor block and set result on view. 130 | 131 | @param url NSURL to fetch from. 132 | @param processorKey NSString key to uniquely identify processor. Used in caching. 133 | @param processor PINRemoteImageManagerImageProcessor processor block which should return the processed image. 134 | */ 135 | - (void)pin_setImageFromURL:(nullable NSURL *)url processorKey:(nullable NSString *)processorKey processor:(nullable PINRemoteImageManagerImageProcessor)processor; 136 | 137 | /** 138 | Set placeholder on view and retrieve the image from the given URL, process it using the passed in processor block and set result on view. 139 | 140 | @param url NSURL to fetch from. 141 | @param placeholderImage PINImage to set on the view while the image at URL is being retrieved. 142 | @param processorKey NSString key to uniquely identify processor. Used in caching. 143 | @param processor PINRemoteImageManagerImageProcessor processor block which should return the processed image. 144 | */ 145 | - (void)pin_setImageFromURL:(nullable NSURL *)url placeholderImage:(nullable PINImage *)placeholderImage processorKey:(nullable NSString *)processorKey processor:(nullable PINRemoteImageManagerImageProcessor)processor; 146 | 147 | /** 148 | Retrieve the image from the given URL, process it using the passed in processor block and set result on view. Call completion after image has been fetched, processed and set on view. 149 | 150 | @param url NSURL to fetch from. 151 | @param processorKey NSString key to uniquely identify processor. Used in caching. 152 | @param processor PINRemoteImageManagerImageProcessor processor block which should return the processed image. 153 | @param completion Called when url has been retrieved and set on view. 154 | */ 155 | - (void)pin_setImageFromURL:(nullable NSURL *)url processorKey:(nullable NSString *)processorKey processor:(nullable PINRemoteImageManagerImageProcessor)processor completion:(nullable PINRemoteImageManagerImageCompletion)completion; 156 | 157 | /** 158 | Set placeholder on view and retrieve the image from the given URL, process it using the passed in processor block and set result on view. Call completion after image has been fetched, processed and set on view. 159 | 160 | @param url NSURL to fetch from. 161 | @param placeholderImage PINImage to set on the view while the image at URL is being retrieved. 162 | @param processorKey NSString key to uniquely identify processor. Used in caching. 163 | @param processor PINRemoteImageManagerImageProcessor processor block which should return the processed image. 164 | @param completion Called when url has been retrieved and set on view. 165 | */ 166 | - (void)pin_setImageFromURL:(nullable NSURL *)url placeholderImage:(nullable PINImage *)placeholderImage processorKey:(nullable NSString *)processorKey processor:(nullable PINRemoteImageManagerImageProcessor)processor completion:(nullable PINRemoteImageManagerImageCompletion)completion; 167 | 168 | /** 169 | Retrieve one of the images at the passed in URLs depending on previous network performance and set result on view. 170 | 171 | @param urls NSArray of NSURLs sorted in increasing quality 172 | */ 173 | - (void)pin_setImageFromURLs:(nullable NSArray *)urls; 174 | 175 | /** 176 | Set placeholder on view and retrieve one of the images at the passed in URLs depending on previous network performance and set result on view. 177 | 178 | @param urls NSArray of NSURLs sorted in increasing quality 179 | @param placeholderImage PINImage to set on the view while the image at URL is being retrieved. 180 | */ 181 | - (void)pin_setImageFromURLs:(nullable NSArray *)urls placeholderImage:(nullable PINImage *)placeholderImage; 182 | 183 | /** 184 | Set placeholder on view and retrieve one of the images at the passed in URLs depending on previous network performance and set result on view. Call completion after image has been fetched and set on view. 185 | 186 | @param urls NSArray of NSURLs sorted in increasing quality 187 | @param placeholderImage PINImage to set on the view while the image at URL is being retrieved. 188 | @param completion Called when url has been retrieved and set on view. 189 | */ 190 | - (void)pin_setImageFromURLs:(nullable NSArray *)urls placeholderImage:(nullable PINImage *)placeholderImage completion:(nullable PINRemoteImageManagerImageCompletion)completion; 191 | 192 | /** 193 | Cancels the image download. Guarantees that previous setImage calls will *not* have their results set on the image view after calling this (as opposed to PINRemoteImageManager which does not guarantee cancellation). 194 | */ 195 | - (void)pin_cancelImageDownload; 196 | 197 | /** 198 | Returns the NSUUID associated with any PINRemoteImage task currently running on the view. 199 | 200 | @return NSUUID associated with any PINRemoteImage task currently running on the view. 201 | */ 202 | - (nullable NSUUID *)pin_downloadImageOperationUUID; 203 | 204 | /** 205 | Set the current NSUUID associated with a PINRemoteImage task running on the view. 206 | 207 | @param downloadImageOperationUUID NSUUID associated with a PINRemoteImage task. 208 | */ 209 | - (void)pin_setDownloadImageOperationUUID:(nullable NSUUID *)downloadImageOperationUUID; 210 | 211 | /** 212 | Whether the view should update with progress images (such as those provided by progressive JPEG images). 213 | 214 | @return BOOL value indicating whether the view should update with progress images 215 | */ 216 | @property (nonatomic, assign) BOOL pin_updateWithProgress; 217 | 218 | //Handle 219 | - (void)pin_setPlaceholderWithImage:(nullable PINImage *)image; 220 | - (void)pin_updateUIWithImage:(nullable PINImage *)image animatedImage:(nullable FLAnimatedImage *)animatedImage; 221 | - (void)pin_clearImages; 222 | - (BOOL)pin_ignoreGIFs; 223 | 224 | @optional 225 | 226 | /** 227 | If you implement this method, it is called instead of pin_updateUIWithImage:animatedImage: 228 | 229 | @param result A PINRemoteImageManagerResult 230 | */ 231 | - (void)pin_updateUIWithRemoteImageManagerResult:(nonnull PINRemoteImageManagerResult *)result; 232 | 233 | - (PINRemoteImageManagerDownloadOptions)pin_defaultOptions; 234 | 235 | @end 236 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageCategoryManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageCategory.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/4/14. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageCategoryManager.h" 10 | 11 | #import 12 | 13 | @implementation PINRemoteImageCategoryManager 14 | 15 | + (void)setImageOnView:(id )view 16 | fromURL:(NSURL *)url 17 | { 18 | [self setImageOnView:view fromURL:url placeholderImage:nil]; 19 | } 20 | 21 | + (void)setImageOnView:(id )view 22 | fromURL:(NSURL *)url 23 | placeholderImage:(PINImage *)placeholderImage 24 | { 25 | [self setImageOnView:view fromURL:url placeholderImage:placeholderImage completion:nil]; 26 | } 27 | 28 | + (void)setImageOnView:(id )view 29 | fromURL:(NSURL *)url 30 | completion:(PINRemoteImageManagerImageCompletion)completion 31 | { 32 | [self setImageOnView:view fromURL:url placeholderImage:nil completion:completion]; 33 | } 34 | 35 | + (void)setImageOnView:(id )view 36 | fromURL:(NSURL *)url 37 | placeholderImage:(PINImage *)placeholderImage 38 | completion:(PINRemoteImageManagerImageCompletion)completion 39 | { 40 | [self setImageOnView:view 41 | fromURLs:url?@[url]:nil 42 | placeholderImage:placeholderImage 43 | processorKey:nil 44 | processor:nil 45 | completion:completion]; 46 | } 47 | 48 | + (void)setImageOnView:(id )view 49 | fromURL:(NSURL *)url 50 | processorKey:(NSString *)processorKey 51 | processor:(PINRemoteImageManagerImageProcessor)processor 52 | { 53 | [self setImageOnView:view 54 | fromURL:url 55 | processorKey:processorKey 56 | processor:processor 57 | completion:nil]; 58 | } 59 | 60 | + (void)setImageOnView:(id )view 61 | fromURL:(NSURL *)url 62 | placeholderImage:(PINImage *)placeholderImage 63 | processorKey:(NSString *)processorKey 64 | processor:(PINRemoteImageManagerImageProcessor)processor 65 | { 66 | [self setImageOnView:view 67 | fromURLs:url?@[url]:nil 68 | placeholderImage:placeholderImage 69 | processorKey:processorKey 70 | processor:processor 71 | completion:nil]; 72 | } 73 | 74 | + (void)setImageOnView:(id )view 75 | fromURL:(NSURL *)url 76 | processorKey:(NSString *)processorKey 77 | processor:(PINRemoteImageManagerImageProcessor)processor 78 | completion:(PINRemoteImageManagerImageCompletion)completion 79 | { 80 | [self setImageOnView:view 81 | fromURLs:url?@[url]:nil 82 | placeholderImage:nil 83 | processorKey:processorKey 84 | processor:processor 85 | completion:completion]; 86 | } 87 | 88 | + (void)setImageOnView:(id )view 89 | fromURLs:(NSArray *)urls 90 | { 91 | [self setImageOnView:view 92 | fromURLs:urls 93 | placeholderImage:nil]; 94 | } 95 | 96 | + (void)setImageOnView:(id )view 97 | fromURLs:(NSArray *)urls 98 | placeholderImage:(PINImage *)placeholderImage 99 | { 100 | [self setImageOnView:view 101 | fromURLs:urls 102 | placeholderImage:placeholderImage 103 | completion:nil]; 104 | } 105 | 106 | + (void)setImageOnView:(id )view 107 | fromURLs:(NSArray *)urls 108 | placeholderImage:(PINImage *)placeholderImage 109 | completion:(PINRemoteImageManagerImageCompletion)completion 110 | { 111 | return [self setImageOnView:view 112 | fromURLs:urls 113 | placeholderImage:placeholderImage 114 | processorKey:nil 115 | processor:nil 116 | completion:completion]; 117 | } 118 | 119 | + (NSUUID *)downloadImageOperationUUIDOnView:(id )view 120 | { 121 | return (NSUUID *)objc_getAssociatedObject(view, @selector(downloadImageOperationUUIDOnView:)); 122 | } 123 | 124 | + (void)setDownloadImageOperationUUID:(NSUUID *)downloadImageOperationUUID onView:(id )view 125 | { 126 | objc_setAssociatedObject(view, @selector(downloadImageOperationUUIDOnView:), downloadImageOperationUUID, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 127 | } 128 | 129 | + (BOOL)updateWithProgressOnView:(id )view 130 | { 131 | return [(NSNumber *)objc_getAssociatedObject(view, @selector(updateWithProgressOnView:)) boolValue]; 132 | } 133 | 134 | + (void)setUpdateWithProgressOnView:(BOOL)updateWithProgress onView:(id )view 135 | { 136 | objc_setAssociatedObject(view, @selector(updateWithProgressOnView:), [NSNumber numberWithBool:updateWithProgress], OBJC_ASSOCIATION_RETAIN); 137 | } 138 | 139 | + (void)cancelImageDownloadOnView:(id )view 140 | { 141 | if ([self downloadImageOperationUUIDOnView:view]) { 142 | [[PINRemoteImageManager sharedImageManager] cancelTaskWithUUID:[self downloadImageOperationUUIDOnView:view]]; 143 | [self setDownloadImageOperationUUID:nil onView:view]; 144 | } 145 | } 146 | 147 | + (void)setImageOnView:(id )view 148 | fromURLs:(NSArray *)urls 149 | placeholderImage:(PINImage *)placeholderImage 150 | processorKey:(NSString *)processorKey 151 | processor:(PINRemoteImageManagerImageProcessor)processor 152 | completion:(PINRemoteImageManagerImageCompletion)completion 153 | { 154 | if (![NSThread isMainThread]) { 155 | dispatch_async(dispatch_get_main_queue(), ^{ 156 | [self setImageOnView:view 157 | fromURLs:urls 158 | placeholderImage:placeholderImage 159 | processorKey:processorKey 160 | processor:processor 161 | completion:completion]; 162 | }); 163 | return; 164 | } 165 | 166 | [self cancelImageDownloadOnView:view]; 167 | 168 | if (placeholderImage) { 169 | [view pin_setPlaceholderWithImage:placeholderImage]; 170 | } 171 | 172 | if (urls == nil || urls.count == 0) { 173 | if (!placeholderImage) { 174 | [view pin_clearImages]; 175 | } 176 | return; 177 | } 178 | 179 | PINRemoteImageManagerDownloadOptions options; 180 | if([view respondsToSelector:@selector(pin_defaultOptions)]) { 181 | options = [view pin_defaultOptions]; 182 | } else { 183 | options = PINRemoteImageManagerDownloadOptionsNone; 184 | } 185 | 186 | if ([view pin_ignoreGIFs]) { 187 | options |= PINRemoteImageManagerDownloadOptionsIgnoreGIFs; 188 | } 189 | 190 | BOOL updateWithFullResult = [view respondsToSelector:@selector(pin_updateUIWithRemoteImageManagerResult:)]; 191 | 192 | PINRemoteImageManagerImageCompletion internalProgress = nil; 193 | if ([self updateWithProgressOnView:view] && processorKey.length <= 0 && processor == nil) { 194 | internalProgress = ^(PINRemoteImageManagerResult *result) 195 | { 196 | void (^mainQueue)() = ^{ 197 | //if result.UUID is nil, we returned immediately and want this result 198 | NSUUID *currentUUID = [self downloadImageOperationUUIDOnView:view]; 199 | if (![currentUUID isEqual:result.UUID] && result.UUID != nil) { 200 | return; 201 | } 202 | if (result.image) { 203 | if (updateWithFullResult) { 204 | [view pin_updateUIWithRemoteImageManagerResult:result]; 205 | } 206 | else { 207 | [view pin_updateUIWithImage:result.image animatedImage:nil]; 208 | } 209 | 210 | } 211 | }; 212 | if ([NSThread isMainThread]) { 213 | mainQueue(); 214 | } else { 215 | dispatch_async(dispatch_get_main_queue(), ^{ 216 | mainQueue(); 217 | }); 218 | } 219 | }; 220 | } 221 | 222 | PINRemoteImageManagerImageCompletion internalCompletion = ^(PINRemoteImageManagerResult *result) 223 | { 224 | void (^mainQueue)() = ^{ 225 | //if result.UUID is nil, we returned immediately and want this result 226 | NSUUID *currentUUID = [self downloadImageOperationUUIDOnView:view]; 227 | if (![currentUUID isEqual:result.UUID] && result.UUID != nil) { 228 | return; 229 | } 230 | [self setDownloadImageOperationUUID:nil onView:view]; 231 | if (result.error) { 232 | if (completion) { 233 | completion(result); 234 | } 235 | return; 236 | } 237 | 238 | if (updateWithFullResult) { 239 | [view pin_updateUIWithRemoteImageManagerResult:result]; 240 | } 241 | else { 242 | [view pin_updateUIWithImage:result.image animatedImage:result.animatedImage]; 243 | } 244 | 245 | if (completion) { 246 | completion(result); 247 | } 248 | }; 249 | if ([NSThread isMainThread]) { 250 | mainQueue(); 251 | } else { 252 | dispatch_async(dispatch_get_main_queue(), ^{ 253 | mainQueue(); 254 | }); 255 | } 256 | }; 257 | 258 | NSUUID *downloadImageOperationUUID = nil; 259 | if (urls.count > 1) { 260 | downloadImageOperationUUID = [[PINRemoteImageManager sharedImageManager] downloadImageWithURLs:urls 261 | options:options 262 | progressImage:internalProgress 263 | completion:internalCompletion]; 264 | } else if (processorKey.length > 0 && processor) { 265 | downloadImageOperationUUID = [[PINRemoteImageManager sharedImageManager] downloadImageWithURL:urls[0] 266 | options:options 267 | processorKey:processorKey 268 | processor:processor 269 | completion:internalCompletion]; 270 | } else { 271 | downloadImageOperationUUID = [[PINRemoteImageManager sharedImageManager] downloadImageWithURL:urls[0] 272 | options:options 273 | progressImage:internalProgress 274 | completion:internalCompletion]; 275 | } 276 | 277 | [self setDownloadImageOperationUUID:downloadImageOperationUUID onView:view]; 278 | } 279 | 280 | @end 281 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageDownloadTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageDownloadTask.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageTask.h" 10 | #import "PINProgressiveImage.h" 11 | #import "PINDataTaskOperation.h" 12 | 13 | @interface PINRemoteImageDownloadTask : PINRemoteImageTask 14 | 15 | @property (nonatomic, strong, nullable) PINDataTaskOperation *urlSessionTaskOperation; 16 | @property (nonatomic, assign) CFTimeInterval sessionTaskStartTime; 17 | @property (nonatomic, assign) CFTimeInterval sessionTaskEndTime; 18 | @property (nonatomic, assign) BOOL hasProgressBlocks; 19 | @property (nonatomic, strong, nullable) PINProgressiveImage *progressImage; 20 | 21 | - (void)callProgressDownloadWithQueue:(nonnull dispatch_queue_t)queue completedBytes:(int64_t)completedBytes totalBytes:(int64_t)totalBytes; 22 | - (void)callProgressImageWithQueue:(nonnull dispatch_queue_t)queue withImage:(nonnull PINImage *)image renderedImageQuality:(CGFloat)renderedImageQuality; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageDownloadTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageDownloadTask.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageDownloadTask.h" 10 | 11 | #import "PINRemoteImage.h" 12 | #import "PINRemoteImageCallbacks.h" 13 | 14 | @interface PINRemoteImageDownloadTask () { 15 | BOOL _canSetDataTaskPriority; 16 | } 17 | 18 | @end 19 | 20 | @implementation PINRemoteImageDownloadTask 21 | 22 | - (instancetype)init 23 | { 24 | if (self = [super init]) { 25 | _canSetDataTaskPriority = [NSURLSessionTask instancesRespondToSelector:@selector(setPriority:)]; 26 | } 27 | return self; 28 | } 29 | 30 | - (BOOL)hasProgressBlocks 31 | { 32 | __block BOOL hasProgressBlocks = NO; 33 | [self.callbackBlocks enumerateKeysAndObjectsUsingBlock:^(NSUUID *UUID, PINRemoteImageCallbacks *callback, BOOL *stop) { 34 | if (callback.progressImageBlock) { 35 | hasProgressBlocks = YES; 36 | *stop = YES; 37 | } 38 | }]; 39 | return hasProgressBlocks; 40 | } 41 | 42 | - (void)callProgressDownloadWithQueue:(nonnull dispatch_queue_t)queue completedBytes:(int64_t)completedBytes totalBytes:(int64_t)totalBytes 43 | { 44 | [self.callbackBlocks enumerateKeysAndObjectsUsingBlock:^(NSUUID *UUID, PINRemoteImageCallbacks *callback, BOOL *stop) { 45 | if (callback.progressDownloadBlock != nil) { 46 | PINLog(@"calling progress for UUID: %@ key: %@", UUID, self.key); 47 | PINRemoteImageManagerProgressDownload progressDownloadBlock = callback.progressDownloadBlock; 48 | //The code run asynchronously below is *not* guaranteed to be run in the manager's lock! 49 | //All access to the callbacks and self should be done outside the block below! 50 | dispatch_async(queue, ^ 51 | { 52 | progressDownloadBlock(completedBytes, totalBytes); 53 | }); 54 | } 55 | }]; 56 | } 57 | 58 | - (void)callProgressImageWithQueue:(nonnull dispatch_queue_t)queue withImage:(nonnull PINImage *)image renderedImageQuality:(CGFloat)renderedImageQuality 59 | { 60 | [self.callbackBlocks enumerateKeysAndObjectsUsingBlock:^(NSUUID *UUID, PINRemoteImageCallbacks *callback, BOOL *stop) { 61 | if (callback.progressImageBlock != nil) { 62 | PINLog(@"calling progress for UUID: %@ key: %@", UUID, self.key); 63 | PINRemoteImageManagerImageCompletion progressImageBlock = callback.progressImageBlock; 64 | CFTimeInterval requestTime = callback.requestTime; 65 | //The code run asynchronously below is *not* guaranteed to be run in the manager's lock! 66 | //All access to the callbacks and self should be done outside the block below! 67 | dispatch_async(queue, ^ 68 | { 69 | progressImageBlock([PINRemoteImageManagerResult imageResultWithImage:image 70 | animatedImage:nil 71 | requestLength:CACurrentMediaTime() - requestTime 72 | error:nil 73 | resultType:PINRemoteImageResultTypeProgress 74 | UUID:UUID 75 | renderedImageQuality:renderedImageQuality]); 76 | }); 77 | } 78 | }]; 79 | } 80 | 81 | - (BOOL)cancelWithUUID:(NSUUID *)UUID manager:(PINRemoteImageManager *)manager 82 | { 83 | BOOL noMoreCompletions = [super cancelWithUUID:UUID manager:manager]; 84 | if (noMoreCompletions) { 85 | [self.urlSessionTaskOperation cancel]; 86 | PINLog(@"Canceling download of URL: %@, UUID: %@", self.urlSessionTaskOperation.dataTask.originalRequest.URL, UUID); 87 | } else { 88 | PINLog(@"Decrementing download of URL: %@, UUID: %@", self.urlSessionTaskOperation.dataTask.originalRequest.URL, UUID); 89 | } 90 | return noMoreCompletions; 91 | } 92 | 93 | - (void)setPriority:(PINRemoteImageManagerPriority)priority 94 | { 95 | [super setPriority:priority]; 96 | if (_canSetDataTaskPriority) { 97 | self.urlSessionTaskOperation.dataTask.priority = dataTaskPriorityWithImageManagerPriority(priority); 98 | } 99 | self.urlSessionTaskOperation.queuePriority = operationPriorityWithImageManagerPriority(priority); 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageMacros.h 3 | // PINRemoteImage 4 | // 5 | 6 | #import 7 | 8 | #ifndef PINRemoteImageMacros_h 9 | #define PINRemoteImageMacros_h 10 | 11 | #define PIN_TARGET_IOS (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR || TARGET_OS_TV) 12 | #define PIN_TARGET_MAC (TARGET_OS_MAC) 13 | 14 | #define PINRemoteImageLogging 0 15 | #if PINRemoteImageLogging 16 | #define PINLog(args...) NSLog(args) 17 | #else 18 | #define PINLog(args...) 19 | #endif 20 | 21 | #if __has_include() 22 | #define USE_FLANIMATED_IMAGE 1 23 | #else 24 | #define USE_FLANIMATED_IMAGE 0 25 | #define FLAnimatedImage NSObject 26 | #endif 27 | 28 | #if PIN_TARGET_IOS 29 | #define PINImage UIImage 30 | #define PINImageView UIImageView 31 | #define PINButton UIButton 32 | #elif PIN_TARGET_MAC 33 | #define PINImage NSImage 34 | #define PINImageView NSImageView 35 | #define PINButton NSButton 36 | #endif 37 | 38 | #define BlockAssert(condition, desc, ...) \ 39 | do { \ 40 | __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ 41 | if (!(condition)) { \ 42 | [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \ 43 | object:strongSelf file:[NSString stringWithUTF8String:__FILE__] \ 44 | lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \ 45 | } \ 46 | __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ 47 | } while(0); 48 | 49 | #endif /* PINRemoteImageMacros_h */ 50 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageManagerResult.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageManagerResult.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #if PIN_TARGET_IOS 12 | #import 13 | #elif PIN_TARGET_MAC 14 | #import 15 | #endif 16 | 17 | #import "PINRemoteImageMacros.h" 18 | #if USE_FLANIMATED_IMAGE 19 | #import 20 | #endif 21 | 22 | /** How the image was fetched. */ 23 | typedef NS_ENUM(NSUInteger, PINRemoteImageResultType) { 24 | /** Returned if no image is returned */ 25 | PINRemoteImageResultTypeNone = 0, 26 | /** Image was fetched from the memory cache */ 27 | PINRemoteImageResultTypeMemoryCache, 28 | /** Image was fetched from the disk cache */ 29 | PINRemoteImageResultTypeCache, 30 | /** Image was downloaded */ 31 | PINRemoteImageResultTypeDownload, 32 | /** Image is progress */ 33 | PINRemoteImageResultTypeProgress, 34 | }; 35 | 36 | @interface PINRemoteImageManagerResult : NSObject 37 | 38 | @property (nonatomic, readonly, strong, nullable) PINImage *image; 39 | @property (nonatomic, readonly, strong, nullable) FLAnimatedImage *animatedImage; 40 | @property (nonatomic, readonly, assign) NSTimeInterval requestDuration; 41 | @property (nonatomic, readonly, strong, nullable) NSError *error; 42 | @property (nonatomic, readonly, assign) PINRemoteImageResultType resultType; 43 | @property (nonatomic, readonly, strong, nullable) NSUUID *UUID; 44 | @property (nonatomic, readonly, assign) CGFloat renderedImageQuality; 45 | 46 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 47 | animatedImage:(nullable FLAnimatedImage *)animatedImage 48 | requestLength:(NSTimeInterval)requestLength 49 | error:(nullable NSError *)error 50 | resultType:(PINRemoteImageResultType)resultType 51 | UUID:(nullable NSUUID *)uuid; 52 | 53 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 54 | animatedImage:(nullable FLAnimatedImage *)animatedImage 55 | requestLength:(NSTimeInterval)requestLength 56 | error:(nullable NSError *)error 57 | resultType:(PINRemoteImageResultType)resultType 58 | UUID:(nullable NSUUID *)uuid 59 | renderedImageQuality:(CGFloat)renderedImageQuality; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageManagerResult.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageManagerResult.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageManagerResult.h" 10 | 11 | @implementation PINRemoteImageManagerResult 12 | 13 | + (instancetype)imageResultWithImage:(PINImage *)image 14 | animatedImage:(FLAnimatedImage *)animatedImage 15 | requestLength:(NSTimeInterval)requestLength 16 | error:(NSError *)error 17 | resultType:(PINRemoteImageResultType)resultType 18 | UUID:(NSUUID *)uuid 19 | { 20 | return [self imageResultWithImage:image 21 | animatedImage:animatedImage 22 | requestLength:requestLength 23 | error:error 24 | resultType:resultType 25 | UUID:uuid 26 | renderedImageQuality:1.0]; 27 | } 28 | 29 | + (instancetype)imageResultWithImage:(PINImage *)image 30 | animatedImage:(nullable FLAnimatedImage *)animatedImage 31 | requestLength:(NSTimeInterval)requestLength 32 | error:(NSError *)error 33 | resultType:(PINRemoteImageResultType)resultType 34 | UUID:(NSUUID *)uuid 35 | renderedImageQuality:(CGFloat)renderedImageQuality 36 | { 37 | return [[self alloc] initWithImage:image 38 | animatedImage:animatedImage 39 | requestLength:requestLength 40 | error:error 41 | resultType:resultType 42 | UUID:uuid 43 | renderedImageQuality:renderedImageQuality]; 44 | } 45 | 46 | - (instancetype)initWithImage:(PINImage *)image 47 | animatedImage:(FLAnimatedImage *)animatedImage 48 | requestLength:(NSTimeInterval)requestLength 49 | error:(NSError *)error 50 | resultType:(PINRemoteImageResultType)resultType 51 | UUID:(NSUUID *)uuid 52 | renderedImageQuality:(CGFloat)renderedImageQuality 53 | { 54 | if (self = [super init]) { 55 | _image = image; 56 | _animatedImage = animatedImage; 57 | _requestDuration = requestLength; 58 | _error = error; 59 | _resultType = resultType; 60 | _UUID = uuid; 61 | _renderedImageQuality = renderedImageQuality; 62 | } 63 | return self; 64 | } 65 | 66 | - (NSString *)description 67 | { 68 | NSString *description = [super description]; 69 | description = [description stringByAppendingString:[NSString stringWithFormat:@"image: %@", self.image]]; 70 | description = [description stringByAppendingString:@"\n"]; 71 | description = [description stringByAppendingString:[NSString stringWithFormat:@"animatedImage: %@", self.animatedImage]]; 72 | description = [description stringByAppendingString:@"\n"]; 73 | description = [description stringByAppendingString:[NSString stringWithFormat:@"requestDuration: %f", self.requestDuration]]; 74 | description = [description stringByAppendingString:@"\n"]; 75 | description = [description stringByAppendingString:[NSString stringWithFormat:@"error: %@", self.error]]; 76 | description = [description stringByAppendingString:@"\n"]; 77 | description = [description stringByAppendingString:[NSString stringWithFormat:@"resultType: %lu", (unsigned long)self.resultType]]; 78 | description = [description stringByAppendingString:@"\n"]; 79 | description = [description stringByAppendingString:[NSString stringWithFormat:@"UUID: %@", self.UUID]]; 80 | description = [description stringByAppendingString:@"\n"]; 81 | description = [description stringByAppendingString:[NSString stringWithFormat:@"UUID: %f", self.renderedImageQuality]]; 82 | return description; 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageProcessorTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageProcessorTask.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageTask.h" 10 | 11 | @interface PINRemoteImageProcessorTask : PINRemoteImageTask 12 | 13 | @property (nonatomic, strong, nullable) NSUUID *downloadTaskUUID; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageProcessorTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageProcessorTask.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageProcessorTask.h" 10 | 11 | @implementation PINRemoteImageProcessorTask 12 | 13 | - (BOOL)cancelWithUUID:(NSUUID *)UUID manager:(PINRemoteImageManager *)manager 14 | { 15 | BOOL noMoreCompletions = [super cancelWithUUID:UUID manager:manager]; 16 | if (noMoreCompletions && self.downloadTaskUUID) { 17 | [manager cancelTaskWithUUID:self.downloadTaskUUID]; 18 | _downloadTaskUUID = nil; 19 | } 20 | return noMoreCompletions; 21 | } 22 | 23 | - (void)setDownloadTaskUUID:(NSUUID *)downloadTaskUUID 24 | { 25 | NSAssert(_downloadTaskUUID == nil, @"downloadTaskUUID should be nil"); 26 | _downloadTaskUUID = downloadTaskUUID; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageTask.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageManager.h" 12 | #import "PINRemoteImageMacros.h" 13 | 14 | @interface PINRemoteImageTask : NSObject 15 | 16 | @property (nonatomic, strong, nonnull) NSMutableDictionary *callbackBlocks; 17 | #if PINRemoteImageLogging 18 | @property (nonatomic, copy, nullable) NSString *key; 19 | #endif 20 | 21 | - (void)addCallbacksWithCompletionBlock:(nonnull PINRemoteImageManagerImageCompletion)completionBlock 22 | progressImageBlock:(nullable PINRemoteImageManagerImageCompletion)progressImageBlock 23 | progressDownloadBlock:(nullable PINRemoteImageManagerProgressDownload)progressDownloadBlock 24 | withUUID:(nonnull NSUUID *)UUID; 25 | - (void)removeCallbackWithUUID:(nonnull NSUUID *)UUID; 26 | - (void)callCompletionsWithQueue:(nonnull dispatch_queue_t)queue remove:(BOOL)remove withImage:(nullable PINImage *)image animatedImage:(nullable FLAnimatedImage *)animatedImage cached:(BOOL)cached error:(nullable NSError *)error; 27 | //returns YES if no more attached completionBlocks 28 | - (BOOL)cancelWithUUID:(nonnull NSUUID *)UUID manager:(nullable PINRemoteImageManager *)manager; 29 | - (void)setPriority:(PINRemoteImageManagerPriority)priority; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteImageTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageTask.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageTask.h" 10 | 11 | #import "PINRemoteImageCallbacks.h" 12 | 13 | @implementation PINRemoteImageTask 14 | 15 | - (instancetype)init 16 | { 17 | if (self = [super init]) { 18 | self.callbackBlocks = [[NSMutableDictionary alloc] init]; 19 | } 20 | return self; 21 | } 22 | 23 | - (NSString *)description 24 | { 25 | return [NSString stringWithFormat:@"<%@: %p> completionBlocks: %lu", NSStringFromClass([self class]), self, (unsigned long)self.callbackBlocks.count]; 26 | } 27 | 28 | - (void)addCallbacksWithCompletionBlock:(PINRemoteImageManagerImageCompletion)completionBlock 29 | progressImageBlock:(PINRemoteImageManagerImageCompletion)progressImageBlock 30 | progressDownloadBlock:(PINRemoteImageManagerProgressDownload)progressDownloadBlock 31 | withUUID:(NSUUID *)UUID 32 | { 33 | PINRemoteImageCallbacks *completion = [[PINRemoteImageCallbacks alloc] init]; 34 | completion.completionBlock = completionBlock; 35 | completion.progressImageBlock = progressImageBlock; 36 | completion.progressDownloadBlock = progressDownloadBlock; 37 | 38 | [self.callbackBlocks setObject:completion forKey:UUID]; 39 | } 40 | 41 | - (void)removeCallbackWithUUID:(NSUUID *)UUID 42 | { 43 | [self.callbackBlocks removeObjectForKey:UUID]; 44 | } 45 | 46 | - (void)callCompletionsWithQueue:(dispatch_queue_t)queue 47 | remove:(BOOL)remove 48 | withImage:(PINImage *)image 49 | animatedImage:(FLAnimatedImage *)animatedImage 50 | cached:(BOOL)cached 51 | error:(NSError *)error 52 | { 53 | __weak typeof(self) weakSelf = self; 54 | [self.callbackBlocks enumerateKeysAndObjectsUsingBlock:^(NSUUID *UUID, PINRemoteImageCallbacks *callback, BOOL *stop) { 55 | typeof(self) strongSelf = weakSelf; 56 | if (callback.completionBlock != nil) { 57 | PINLog(@"calling completion for UUID: %@ key: %@", UUID, strongSelf.key); 58 | PINRemoteImageManagerImageCompletion completionBlock = callback.completionBlock; 59 | CFTimeInterval requestTime = callback.requestTime; 60 | 61 | //The code run asynchronously below is *not* guaranteed to be run in the manager's lock! 62 | //All access to the callbacks and self should be done outside the block below! 63 | dispatch_async(queue, ^ 64 | { 65 | PINRemoteImageResultType result; 66 | if (image || animatedImage) { 67 | result = cached ? PINRemoteImageResultTypeCache : PINRemoteImageResultTypeDownload; 68 | } else { 69 | result = PINRemoteImageResultTypeNone; 70 | } 71 | completionBlock([PINRemoteImageManagerResult imageResultWithImage:image 72 | animatedImage:animatedImage 73 | requestLength:CACurrentMediaTime() - requestTime 74 | error:error 75 | resultType:result 76 | UUID:UUID]); 77 | }); 78 | } 79 | if (remove) { 80 | [strongSelf removeCallbackWithUUID:UUID]; 81 | } 82 | }]; 83 | } 84 | 85 | - (BOOL)cancelWithUUID:(NSUUID *)UUID manager:(PINRemoteImageManager *)manager 86 | { 87 | BOOL noMoreCompletions = NO; 88 | [self removeCallbackWithUUID:UUID]; 89 | if ([self.callbackBlocks count] == 0) { 90 | noMoreCompletions = YES; 91 | } 92 | return noMoreCompletions; 93 | } 94 | 95 | - (void)setPriority:(PINRemoteImageManagerPriority)priority 96 | { 97 | 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteLock.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteLock.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | /** The type of lock, either recursive or non-recursive */ 12 | typedef NS_ENUM(NSUInteger, PINRemoteLockType) { 13 | /** A non-recursive version of the lock. The default. */ 14 | PINRemoteLockTypeNonRecursive = 0, 15 | /** A recursive version of the lock. More expensive. */ 16 | PINRemoteLockTypeRecursive, 17 | }; 18 | 19 | @interface PINRemoteLock : NSObject 20 | 21 | - (instancetype)initWithName:(NSString *)lockName lockType:(PINRemoteLockType)lockType NS_DESIGNATED_INITIALIZER; 22 | - (instancetype)initWithName:(NSString *)lockName; 23 | - (void)lockWithBlock:(dispatch_block_t)block; 24 | 25 | - (void)lock; 26 | - (void)unlock; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINRemoteLock.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteLock.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import "PINRemoteLock.h" 10 | 11 | #import 12 | 13 | #if !defined(PINREMOTELOCK_DEBUG) && defined(DEBUG) 14 | #define PINREMOTELOCK_DEBUG DEBUG 15 | #endif 16 | 17 | @interface PINRemoteLock () 18 | { 19 | #if PINREMOTELOCK_DEBUG 20 | NSLock *_lock; 21 | NSRecursiveLock *_recursiveLock; 22 | #else 23 | pthread_mutex_t _lock; 24 | #endif 25 | } 26 | 27 | @end 28 | 29 | @implementation PINRemoteLock 30 | 31 | - (instancetype)init 32 | { 33 | return [self initWithName:nil]; 34 | } 35 | 36 | - (instancetype)initWithName:(NSString *)lockName lockType:(PINRemoteLockType)lockType 37 | { 38 | if (self = [super init]) { 39 | #if PINREMOTELOCK_DEBUG 40 | if (lockType == PINRemoteLockTypeNonRecursive) { 41 | _lock = [[NSLock alloc] init]; 42 | } else { 43 | _recursiveLock = [[NSRecursiveLock alloc] init]; 44 | } 45 | 46 | if (lockName) { 47 | [_lock setName:lockName]; 48 | [_recursiveLock setName:lockName]; 49 | } 50 | #else 51 | pthread_mutexattr_t attr; 52 | 53 | pthread_mutexattr_init(&attr); 54 | if (lockType == PINRemoteLockTypeRecursive) { 55 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 56 | } 57 | pthread_mutex_init(&_lock, &attr); 58 | #endif 59 | } 60 | return self; 61 | } 62 | 63 | - (instancetype)initWithName:(NSString *)lockName 64 | { 65 | return [self initWithName:lockName lockType:PINRemoteLockTypeNonRecursive]; 66 | } 67 | 68 | #if ! PINREMOTELOCK_DEBUG 69 | - (void)dealloc 70 | { 71 | pthread_mutex_destroy(&_lock); 72 | } 73 | #endif 74 | 75 | - (void)lockWithBlock:(dispatch_block_t)block 76 | { 77 | #if PINREMOTELOCK_DEBUG 78 | [_lock lock]; 79 | [_recursiveLock lock]; 80 | #else 81 | pthread_mutex_lock(&_lock); 82 | #endif 83 | block(); 84 | #if PINREMOTELOCK_DEBUG 85 | [_lock unlock]; 86 | [_recursiveLock unlock]; 87 | #else 88 | pthread_mutex_unlock(&_lock); 89 | #endif 90 | } 91 | 92 | - (void)lock 93 | { 94 | #if PINREMOTELOCK_DEBUG 95 | [_lock lock]; 96 | [_recursiveLock lock]; 97 | #else 98 | pthread_mutex_lock(&_lock); 99 | #endif 100 | } 101 | 102 | - (void)unlock 103 | { 104 | #if PINREMOTELOCK_DEBUG 105 | [_lock unlock]; 106 | [_recursiveLock unlock]; 107 | #else 108 | pthread_mutex_unlock(&_lock); 109 | #endif 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINURLSessionManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINURLSessionManager.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 6/26/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @protocol PINURLSessionManagerDelegate 12 | 13 | @required 14 | - (void)didReceiveData:(nonnull NSData *)data forTask:(nonnull NSURLSessionTask *)task; 15 | - (void)didCompleteTask:(nonnull NSURLSessionTask *)task withError:(nullable NSError *)error; 16 | 17 | @optional 18 | - (void)didReceiveAuthenticationChallenge:(nonnull NSURLAuthenticationChallenge *)challenge forTask:(nullable NSURLSessionTask *)task completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler; 19 | 20 | 21 | @end 22 | 23 | @interface PINURLSessionManager : NSObject 24 | 25 | - (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration; 26 | 27 | - (nonnull NSURLSessionDataTask *)dataTaskWithRequest:(nonnull NSURLRequest *)request completionHandler:(nullable void (^)(NSURLResponse * _Nonnull response, NSError * _Nullable error))completionHandler; 28 | 29 | - (void)invalidateSessionAndCancelTasks; 30 | 31 | @property (atomic, weak, nullable) id delegate; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/Pod/Classes/PINURLSessionManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINURLSessionManager.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 6/26/15. 6 | // 7 | // 8 | 9 | #import "PINURLSessionManager.h" 10 | 11 | @interface PINURLSessionManager () 12 | 13 | @property (nonatomic, strong) NSLock *sessionManagerLock; 14 | @property (nonatomic, strong) NSURLSession *session; 15 | @property (nonatomic, strong) NSOperationQueue *operationQueue; 16 | @property (nonatomic, strong) NSMutableDictionary *delegateQueues; 17 | @property (nonatomic, strong) NSMutableDictionary *completions; 18 | 19 | @end 20 | 21 | @implementation PINURLSessionManager 22 | 23 | - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration 24 | { 25 | if (self = [super init]) { 26 | self.sessionManagerLock = [[NSLock alloc] init]; 27 | self.sessionManagerLock.name = @"PINURLSessionManager"; 28 | self.operationQueue = [[NSOperationQueue alloc] init]; 29 | self.operationQueue.name = @"PINURLSessionManager Operation Queue"; 30 | 31 | //queue must be serial to ensure proper ordering 32 | [self.operationQueue setMaxConcurrentOperationCount:1]; 33 | self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:self.operationQueue]; 34 | self.completions = [[NSMutableDictionary alloc] init]; 35 | self.delegateQueues = [[NSMutableDictionary alloc] init]; 36 | } 37 | return self; 38 | } 39 | 40 | - (void)invalidateSessionAndCancelTasks 41 | { 42 | [self lock]; 43 | [self.session invalidateAndCancel]; 44 | [self unlock]; 45 | } 46 | 47 | - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLResponse *response, NSError *error))completionHandler 48 | { 49 | [self lock]; 50 | NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request]; 51 | if (completionHandler) { 52 | [self.completions setObject:completionHandler forKey:@(dataTask.taskIdentifier)]; 53 | } 54 | NSString *queueName = [NSString stringWithFormat:@"PINURLSessionManager delegate queue - %ld", (unsigned long)dataTask.taskIdentifier]; 55 | dispatch_queue_t delegateQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL); 56 | [self.delegateQueues setObject:delegateQueue forKey:@(dataTask.taskIdentifier)]; 57 | [self unlock]; 58 | return dataTask; 59 | } 60 | 61 | - (void)lock 62 | { 63 | [self.sessionManagerLock lock]; 64 | } 65 | 66 | - (void)unlock 67 | { 68 | [self.sessionManagerLock unlock]; 69 | } 70 | 71 | #pragma mark NSURLSessionDataDelegate 72 | 73 | - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler 74 | { 75 | if ([self.delegate respondsToSelector:@selector(didReceiveAuthenticationChallenge:forTask:completionHandler:)]) { 76 | [self.delegate didReceiveAuthenticationChallenge:challenge forTask:nil completionHandler:completionHandler]; 77 | } else { 78 | completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); 79 | } 80 | } 81 | 82 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler 83 | { 84 | [self lock]; 85 | dispatch_queue_t delegateQueue = self.delegateQueues[@(task.taskIdentifier)]; 86 | [self unlock]; 87 | 88 | __weak typeof(self) weakSelf = self; 89 | dispatch_async(delegateQueue, ^{ 90 | typeof(self) strongSelf = weakSelf; 91 | if ([strongSelf.delegate respondsToSelector:@selector(didReceiveAuthenticationChallenge:forTask:completionHandler:)]) { 92 | [strongSelf.delegate didReceiveAuthenticationChallenge:challenge forTask:task completionHandler:completionHandler]; 93 | } else { 94 | completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); 95 | } 96 | }); 97 | } 98 | 99 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data 100 | { 101 | [self lock]; 102 | dispatch_queue_t delegateQueue = self.delegateQueues[@(dataTask.taskIdentifier)]; 103 | [self unlock]; 104 | 105 | __weak typeof(self) weakSelf = self; 106 | dispatch_async(delegateQueue, ^{ 107 | typeof(self) strongSelf = weakSelf; 108 | [strongSelf.delegate didReceiveData:data forTask:dataTask]; 109 | }); 110 | } 111 | 112 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 113 | { 114 | [self lock]; 115 | dispatch_queue_t delegateQueue = self.delegateQueues[@(task.taskIdentifier)]; 116 | [self unlock]; 117 | if (!error && [task.response isKindOfClass:[NSHTTPURLResponse class]] && [(NSHTTPURLResponse *)task.response statusCode] == 404) { 118 | error = [NSError errorWithDomain:NSURLErrorDomain 119 | code:NSURLErrorRedirectToNonExistentLocation 120 | userInfo:@{NSLocalizedDescriptionKey : @"The requested URL was not found on this server."}]; 121 | } 122 | __weak typeof(self) weakSelf = self; 123 | dispatch_async(delegateQueue, ^{ 124 | typeof(self) strongSelf = weakSelf; 125 | [strongSelf.delegate didCompleteTask:task withError:error]; 126 | 127 | [strongSelf lock]; 128 | void (^completionHandler)(NSURLResponse *, NSError *) = strongSelf.completions[@(task.taskIdentifier)]; 129 | [strongSelf.completions removeObjectForKey:@(task.taskIdentifier)]; 130 | [strongSelf.delegateQueues removeObjectForKey:@(task.taskIdentifier)]; 131 | [strongSelf unlock]; 132 | 133 | if (completionHandler) { 134 | completionHandler(task.response, error); 135 | } 136 | }); 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /Pods/PINRemoteImage/README.md: -------------------------------------------------------------------------------- 1 | # PINRemoteImage 2 | 3 | ## Fast, non-deadlocking parallel image downloader and cache for iOS 4 | 5 | [![CocoaPods compatible](https://img.shields.io/cocoapods/v/PINRemoteImage.svg?style=flat)](https://cocoapods.org/pods/PINRemoteImage) 6 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | [![Tavis CI build](https://img.shields.io/travis/pinterest/PINRemoteImage.svg?style=flat)](https://travis-ci.org/pinterest/PINRemoteImage) 8 | 9 | [PINRemoteImageManager](Pod/Classes/PINRemoteImageManager.h) is an image downloading, processing and caching manager. It uses the concept of download and processing tasks to ensure that even if multiple calls to download or process an image are made, it only occurs one time (unless an item is no longer in the cache). PINRemoteImageManager is backed by GCD and safe to access from multiple threads simultaneously. It ensures that images are decoded off the main thread so that animation performance isn't affected. None of its exposed methods allow for synchronous access. However, it is optimized to call completions on the calling thread if an item is in its memory cache. 10 | 11 | PINRemoteImage supports downloading many types of files. It, of course, supports both PNGs and JPGs. It also supports decoding WebP images if Google's library is available. It even supports returning [FLAnimatedImages](https://github.com/Flipboard/FLAnimatedImage) if it's compiled in (though this can be disabled). 12 | 13 | PINRemoteImage also has two methods to improve the experience of downloading images on slow network connections. The first is support for progressive JPGs. This isn't any old support for progressive JPGs though: PINRemoteImage adds an attractive blur to progressive scans before returning them. 14 | 15 | ![Progressive JPG with Blur](/progressive.gif "Looks better on device.") 16 | 17 | [PINRemoteImageCategoryManager](Pod/Classes/PINRemoteImageCategoryManager.h) defines a protocol which UIView subclasses can implement and provide easy access to 18 | PINRemoteImageManager's methods. There are built-in categories on UIImageView, FLAnimatedImageView and UIButton, and it's very easy to implement a new category. See [PINImageView+PINRemoteImage](/Pod/Classes/Image Categories/PINImageView+PINRemoteImage.h) of the existing categories for reference. 19 | 20 | 21 | Download an image and set it on an image view: 22 | 23 | ```objc 24 | UIImageView *imageView = [[UIImageView alloc] init]; 25 | [imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/kitten.jpg"]]; 26 | ``` 27 | 28 | Download a progressive jpeg and get attractive blurred updates: 29 | 30 | ```objc 31 | UIImageView *imageView = [[UIImageView alloc] init]; 32 | [imageView setPin_updateWithProgress:YES]; 33 | [imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/progressiveKitten.jpg"]]; 34 | ``` 35 | 36 | Download a WebP file 37 | 38 | ```objc 39 | UIImageView *imageView = [[UIImageView alloc] init]; 40 | [imageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/googleKitten.webp"]]; 41 | ``` 42 | 43 | Download a GIF and display with FLAnimatedImageView 44 | 45 | ```objc 46 | FLAnimatedImageView *animatedImageView = [[FLAnimatedImageView alloc] init]; 47 | [animatedImageView pin_setImageFromURL:[NSURL URLWithString:@"http://pinterest.com/flyingKitten.gif"]]; 48 | ``` 49 | 50 | Download and process an image 51 | 52 | ```objc 53 | UIImageView *imageView = [[UIImageView alloc] init]; 54 | [self.imageView pin_setImageFromURL:[NSURL URLWithString:@"https://s-media-cache-ak0.pinimg.com/736x/5b/c6/c5/5bc6c5387ff6f104fd642f2b375efba3.jpg"] processorKey:@"rounded" processor:^UIImage *(PINRemoteImageManagerResult *result, NSUInteger *cost) 55 | { 56 | CGSize targetSize = CGSizeMake(200, 300); 57 | CGRect imageRect = CGRectMake(0, 0, targetSize.width, targetSize.height); 58 | UIGraphicsBeginImageContext(imageRect.size); 59 | UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:7.0]; 60 | [bezierPath addClip]; 61 | 62 | CGFloat sizeMultiplier = MAX(targetSize.width / result.image.size.width, targetSize.height / result.image.size.height); 63 | 64 | CGRect drawRect = CGRectMake(0, 0, result.image.size.width * sizeMultiplier, result.image.size.height * sizeMultiplier); 65 | if (CGRectGetMaxX(drawRect) > CGRectGetMaxX(imageRect)) { 66 | drawRect.origin.x -= (CGRectGetMaxX(drawRect) - CGRectGetMaxX(imageRect)) / 2.0; 67 | } 68 | if (CGRectGetMaxY(drawRect) > CGRectGetMaxY(imageRect)) { 69 | drawRect.origin.y -= (CGRectGetMaxY(drawRect) - CGRectGetMaxY(imageRect)) / 2.0; 70 | } 71 | 72 | [result.image drawInRect:drawRect]; 73 | 74 | UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext(); 75 | UIGraphicsEndImageContext(); 76 | return processedImage; 77 | }]; 78 | ``` 79 | 80 | Handle Authentication 81 | ```objc 82 | [[PINRemoteImageManager sharedImageManager] setAuthenticationChallenge:^(NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, PINRemoteImageManagerAuthenticationChallengeCompletionHandler aCompletion) { 83 | aCompletion(NSURLSessionAuthChallengePerformDefaultHandling, nil)]; 84 | ``` 85 | 86 | ## Installation 87 | 88 | ### CocoaPods 89 | 90 | Add [PINRemoteImage](http://cocoapods.org/?q=name%3APINRemoteImage) to your `Podfile` and run `pod install`. 91 | 92 | 93 | ### Carthage 94 | 95 | Add `github "pinterest/PINRemoteImage"` to your Cartfile . See [Carthage's readme](https://github.com/Carthage/Carthage) for more information on integrating Carthage-built frameworks into your project. 96 | 97 | ### Manually 98 | 99 | [Download the latest tag](https://github.com/Pinterest/PINRemoteImage/tags) and drag the `Pod/Classes` folder into your Xcode project. You must also manually link against [PINCache](https://github.com/pinterest/PINCache). 100 | 101 | Install the docs by double clicking the `.docset` file under `docs/`, or view them online at [cocoadocs.org](http://cocoadocs.org/docsets/PINRemoteImage/) 102 | 103 | ### Git Submodule 104 | 105 | You can set up PINRemoteImage as a submodule of your repo instead of cloning and copying all the files into your repo. Add the submodule using the commands below and then follow the manual instructions above. 106 | 107 | git submodule add https://github.com/pinterest/PINRemoteImage.git 108 | git submodule update --init 109 | 110 | 111 | 112 | ## Requirements 113 | 114 | __PINRemoteImage__ requires iOS 7.0 or greater. 115 | 116 | ## Contact 117 | 118 | [Garrett Moon](mailto:garrett@pinterest.com) 119 | [@garrettmoon](https://twitter.com/garrettmoon) 120 | [Pinterest](https://www.pinterest.com/garrettlunar/) 121 | 122 | ## License 123 | 124 | Copyright 2015 Pinterest, Inc. 125 | 126 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 127 | 128 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. [See the License](LICENSE.txt) for the specific language governing permissions and limitations under the License. 129 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FLAnimatedImage/FLAnimatedImage-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_FLAnimatedImage : NSObject 3 | @end 4 | @implementation PodsDummy_FLAnimatedImage 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FLAnimatedImage/FLAnimatedImage-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FLAnimatedImage/FLAnimatedImage-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "FLAnimatedImage.h" 14 | #import "FLAnimatedImageView.h" 15 | 16 | FOUNDATION_EXPORT double FLAnimatedImageVersionNumber; 17 | FOUNDATION_EXPORT const unsigned char FLAnimatedImageVersionString[]; 18 | 19 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FLAnimatedImage/FLAnimatedImage.modulemap: -------------------------------------------------------------------------------- 1 | framework module FLAnimatedImage { 2 | umbrella header "FLAnimatedImage-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FLAnimatedImage/FLAnimatedImage.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/FLAnimatedImage 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_LDFLAGS = -framework "CoreGraphics" -framework "ImageIO" -framework "MobileCoreServices" -framework "QuartzCore" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FLAnimatedImage 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FLAnimatedImage/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.12 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINCache/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.3.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINCache/PINCache-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_PINCache : NSObject 3 | @end 4 | @implementation PodsDummy_PINCache 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINCache/PINCache-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #ifndef TARGET_OS_WATCH 14 | #define TARGET_OS_WATCH 0 15 | #endif 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINCache/PINCache-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "Nullability.h" 14 | #import "PINCache.h" 15 | #import "PINCacheObjectSubscripting.h" 16 | #import "PINDiskCache.h" 17 | #import "PINMemoryCache.h" 18 | 19 | FOUNDATION_EXPORT double PINCacheVersionNumber; 20 | FOUNDATION_EXPORT const unsigned char PINCacheVersionString[]; 21 | 22 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINCache/PINCache.modulemap: -------------------------------------------------------------------------------- 1 | framework module PINCache { 2 | umbrella header "PINCache-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINCache/PINCache.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/PINCache 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_LDFLAGS = -framework "Foundation" -weak_framework "UIKit" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINCache 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINRemoteImage/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.1.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINRemoteImage/PINRemoteImage-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_PINRemoteImage : NSObject 3 | @end 4 | @implementation PodsDummy_PINRemoteImage 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINRemoteImage/PINRemoteImage-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINRemoteImage/PINRemoteImage-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "NSData+ImageDetectors.h" 14 | #import "PINImage+DecodedImage.h" 15 | #import "PINImage+WebP.h" 16 | #import "PINButton+PINRemoteImage.h" 17 | #import "PINImageView+PINRemoteImage.h" 18 | #import "PINDataTaskOperation.h" 19 | #import "PINProgressiveImage.h" 20 | #import "PINRemoteImage.h" 21 | #import "PINRemoteImageCallbacks.h" 22 | #import "PINRemoteImageCategoryManager.h" 23 | #import "PINRemoteImageDownloadTask.h" 24 | #import "PINRemoteImageMacros.h" 25 | #import "PINRemoteImageManager.h" 26 | #import "PINRemoteImageManagerResult.h" 27 | #import "PINRemoteImageProcessorTask.h" 28 | #import "PINRemoteImageTask.h" 29 | #import "PINRemoteLock.h" 30 | #import "PINURLSessionManager.h" 31 | #import "FLAnimatedImageView+PINRemoteImage.h" 32 | 33 | FOUNDATION_EXPORT double PINRemoteImageVersionNumber; 34 | FOUNDATION_EXPORT const unsigned char PINRemoteImageVersionString[]; 35 | 36 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINRemoteImage/PINRemoteImage.modulemap: -------------------------------------------------------------------------------- 1 | framework module PINRemoteImage { 2 | umbrella header "PINRemoteImage-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PINRemoteImage/PINRemoteImage.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/PINRemoteImage 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FLAnimatedImage" "$PODS_CONFIGURATION_BUILD_DIR/PINCache" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 5 | OTHER_LDFLAGS = -framework "Accelerate" -framework "ImageIO" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINRemoteImage 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Pods-dojo-table-performance-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_dojo_table_performance : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_dojo_table_performance 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Pods-dojo-table-performance-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 63 | 64 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 65 | code_sign_cmd="$code_sign_cmd &" 66 | fi 67 | echo "$code_sign_cmd" 68 | eval "$code_sign_cmd" 69 | fi 70 | } 71 | 72 | # Strip invalid architectures 73 | strip_invalid_archs() { 74 | binary="$1" 75 | # Get architectures for current file 76 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 77 | stripped="" 78 | for arch in $archs; do 79 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 80 | # Strip non-valid architectures in-place 81 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 82 | stripped="$stripped $arch" 83 | fi 84 | done 85 | if [[ "$stripped" ]]; then 86 | echo "Stripped $binary of architectures:$stripped" 87 | fi 88 | } 89 | 90 | 91 | if [[ "$CONFIGURATION" == "Debug" ]]; then 92 | install_framework "$BUILT_PRODUCTS_DIR/FLAnimatedImage/FLAnimatedImage.framework" 93 | install_framework "$BUILT_PRODUCTS_DIR/PINCache/PINCache.framework" 94 | install_framework "$BUILT_PRODUCTS_DIR/PINRemoteImage/PINRemoteImage.framework" 95 | fi 96 | if [[ "$CONFIGURATION" == "Release" ]]; then 97 | install_framework "$BUILT_PRODUCTS_DIR/FLAnimatedImage/FLAnimatedImage.framework" 98 | install_framework "$BUILT_PRODUCTS_DIR/PINCache/PINCache.framework" 99 | install_framework "$BUILT_PRODUCTS_DIR/PINRemoteImage/PINRemoteImage.framework" 100 | fi 101 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 102 | wait 103 | fi 104 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Pods-dojo-table-performance-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | case "${TARGETED_DEVICE_FAMILY}" in 12 | 1,2) 13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 14 | ;; 15 | 1) 16 | TARGET_DEVICE_ARGS="--target-device iphone" 17 | ;; 18 | 2) 19 | TARGET_DEVICE_ARGS="--target-device ipad" 20 | ;; 21 | 3) 22 | TARGET_DEVICE_ARGS="--target-device tv" 23 | ;; 24 | *) 25 | TARGET_DEVICE_ARGS="--target-device mac" 26 | ;; 27 | esac 28 | 29 | install_resource() 30 | { 31 | if [[ "$1" = /* ]] ; then 32 | RESOURCE_PATH="$1" 33 | else 34 | RESOURCE_PATH="${PODS_ROOT}/$1" 35 | fi 36 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 37 | cat << EOM 38 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 39 | EOM 40 | exit 1 41 | fi 42 | case $RESOURCE_PATH in 43 | *.storyboard) 44 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 45 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 46 | ;; 47 | *.xib) 48 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 49 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 50 | ;; 51 | *.framework) 52 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 53 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 54 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 55 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 56 | ;; 57 | *.xcdatamodel) 58 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" 59 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 60 | ;; 61 | *.xcdatamodeld) 62 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" 63 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 64 | ;; 65 | *.xcmappingmodel) 66 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" 67 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 68 | ;; 69 | *.xcassets) 70 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 71 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 72 | ;; 73 | *) 74 | echo "$RESOURCE_PATH" 75 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 76 | ;; 77 | esac 78 | } 79 | 80 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 82 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 83 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 84 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 85 | fi 86 | rm -f "$RESOURCES_TO_COPY" 87 | 88 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 89 | then 90 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 91 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 92 | while read line; do 93 | if [[ $line != "${PODS_ROOT}*" ]]; then 94 | XCASSET_FILES+=("$line") 95 | fi 96 | done <<<"$OTHER_XCASSETS" 97 | 98 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | fi 100 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Pods-dojo-table-performance-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_dojo_table_performanceVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_dojo_table_performanceVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Pods-dojo-table-performance.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FLAnimatedImage" "$PODS_CONFIGURATION_BUILD_DIR/PINCache" "$PODS_CONFIGURATION_BUILD_DIR/PINRemoteImage" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FLAnimatedImage/FLAnimatedImage.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PINCache/PINCache.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PINRemoteImage/PINRemoteImage.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "FLAnimatedImage" -framework "PINCache" -framework "PINRemoteImage" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Pods-dojo-table-performance.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_dojo_table_performance { 2 | umbrella header "Pods-dojo-table-performance-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-dojo-table-performance/Pods-dojo-table-performance.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FLAnimatedImage" "$PODS_CONFIGURATION_BUILD_DIR/PINCache" "$PODS_CONFIGURATION_BUILD_DIR/PINRemoteImage" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/FLAnimatedImage/FLAnimatedImage.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PINCache/PINCache.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PINRemoteImage/PINRemoteImage.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "FLAnimatedImage" -framework "PINCache" -framework "PINRemoteImage" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Exploring ways to speed up a table 2 | 3 | #### Cocoapods 4 | Latest update introduced Cocoapods. Pods included here to prevent the headache of new versions dropping. 5 | 6 | #### Outdated Tutorial 7 | Sample project from the blog post at http://www.xmcgraw.com/10-actionable-performance-tips-to-speed-up-your-table-view/ 8 | -------------------------------------------------------------------------------- /dojo-table-performance.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dojo-table-performance.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /dojo-table-performance/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // dojo-table-performance 4 | // 5 | // Created by David McGraw on 1/4/15. 6 | // Copyright (c) 2015 David McGraw. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /dojo-table-performance/Dog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dog.swift 3 | // dojo-table-performance 4 | // 5 | // Created by David McGraw on 1/4/15. 6 | // Copyright (c) 2015 David McGraw. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class Dog: NSObject { 12 | 13 | var name: NSString? 14 | 15 | var title: NSString? 16 | 17 | var date: Int? 18 | 19 | var liked = false 20 | 21 | // Date using an NSDateFormatter object 22 | func randomFormatterDate() -> NSString { 23 | let date = randomUnixDate() 24 | let formatter = DateFormatter() 25 | formatter.dateStyle = DateFormatter.Style.long 26 | return formatter.string(from: date) as NSString 27 | } 28 | 29 | // Between Jan 1 2011 and Jan 1 2015 30 | func randomUnixDate() -> Date { 31 | let interval: TimeInterval = Double((arc4random() % UInt32((1420070400 - 1293840000)))) + 1293840000 32 | return Date(timeIntervalSince1970: interval) 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /dojo-table-performance/FeedTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FeedTableViewCell.swift 3 | // dojo-table-performance 4 | // 5 | // Created by David McGraw on 1/4/15. 6 | // Copyright (c) 2015 David McGraw. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import PINRemoteImage 11 | 12 | class FeedTableViewCell: UITableViewCell { 13 | 14 | // MARK: - IBOutlets 15 | 16 | @IBOutlet weak var dogPhoto: UIImageView! 17 | 18 | @IBOutlet weak var dogName: UILabel! 19 | 20 | @IBOutlet weak var title: UILabel! 21 | 22 | @IBOutlet weak var date: UILabel! 23 | 24 | @IBOutlet weak var likeAction: UIButton! 25 | 26 | 27 | // MARK: - Public Methods 28 | 29 | func updateWithRandomData() { 30 | 31 | // ***** 32 | // Photo 33 | // Try out various methods for loading a photo, from worst to best 34 | 35 | loadPhoto() 36 | 37 | // loadPhotoAsync() 38 | 39 | // loadPhotoWithCache() 40 | 41 | // **** 42 | // Date 43 | // Constantly initializing formatters may not show a negative impact 44 | // right away visually, but it will add up eventually. Also, look at 45 | // the memory. 46 | 47 | loadDate() 48 | 49 | // loadDataStaticFormatter() 50 | 51 | // **************** 52 | // Dog name & Title 53 | // Make sure you really need attributed strings 54 | 55 | loadAttributedText() 56 | 57 | // loadPlainText() 58 | 59 | } 60 | 61 | /** 62 | Loads a photo from a remote source 63 | */ 64 | func loadPhoto() { 65 | 66 | let r = (arc4random() % UInt32(20)) 67 | if let data = try? Data(contentsOf: URL(string: "http://www.xmcgraw.com/pets/jpg/siberian\(r).jpg")!) { 68 | dogPhoto.image = UIImage(data: data) 69 | } 70 | 71 | } 72 | 73 | /** 74 | Loads a photo on a background thread 75 | */ 76 | func loadPhotoAsync() { 77 | 78 | DispatchQueue.global(qos: .background).async { 79 | 80 | let r = (arc4random() % UInt32(20)) 81 | if let data = try? Data(contentsOf: URL(string: "http://www.xmcgraw.com/pets/jpg/siberian\(r).jpg")!) { 82 | DispatchQueue.main.async { 83 | self.dogPhoto.image = UIImage(data: data) 84 | } 85 | } 86 | 87 | } 88 | 89 | } 90 | 91 | /** 92 | Loads a photo from `PINRemoteImage` 93 | */ 94 | func loadPhotoWithCache() { 95 | 96 | let r = (arc4random() % UInt32(20)) 97 | if let url = URL(string: "http://www.xmcgraw.com/pets/jpg/siberian\(r).jpg") { 98 | dogPhoto.pin_setImage(from: url) 99 | } 100 | 101 | } 102 | 103 | /** 104 | Sets a date as MM-dd-yy leveraging a `DateFormatter` 105 | 106 | Warning: these are not threadsafe so you will need to create a static formatter 107 | on each thread 108 | */ 109 | func loadDate() { 110 | 111 | // Warning: these are not threadsafe so you need to create a static formatter 112 | // on each thread 113 | let formatter = DateFormatter() 114 | formatter.dateFormat = "MM-dd-yy" 115 | date.text = formatter.string(from: Date()) 116 | 117 | } 118 | 119 | /** 120 | Set date using a static formatter 121 | 122 | Warning: these are not threadsafe so you will need to create a static formatter 123 | on each thread 124 | */ 125 | func loadDataStaticFormatter() { 126 | date.text = FeedTableViewController.XMCDateFormatter.string(from: Date()) 127 | } 128 | 129 | /** 130 | Set the name and title using attributed strings 131 | */ 132 | func loadAttributedText() { 133 | 134 | var attributed = NSMutableAttributedString(string: "Calix") 135 | attributed.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 16.0), range: NSMakeRange(0, attributed.length)) 136 | dogName.attributedText = attributed 137 | 138 | attributed = NSMutableAttributedString(string: "Silly Dog") 139 | attributed.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 22.0), range: NSMakeRange(0, attributed.length)) 140 | title.attributedText = attributed 141 | 142 | } 143 | 144 | /** 145 | Set the name and title using plain text 146 | */ 147 | func loadPlainText() { 148 | 149 | dogName.text = "Calix" 150 | title.text = "Silly Dog" 151 | 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /dojo-table-performance/FeedTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FeedTableViewController.swift 3 | // dojo-table-performance 4 | // 5 | // Created by David McGraw on 1/4/15. 6 | // Copyright (c) 2015 David McGraw. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class FeedTableViewController: UITableViewController { 12 | 13 | class var XMCDateFormatter : DateFormatter { 14 | 15 | struct Static { 16 | 17 | static let instance: DateFormatter = { 18 | let formatter = DateFormatter() 19 | formatter.dateFormat = "MM-dd-yy" 20 | return formatter 21 | }() 22 | 23 | } 24 | return Static.instance 25 | 26 | } 27 | 28 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 29 | return 360 30 | } 31 | 32 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 33 | return 50 34 | } 35 | 36 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 37 | let cell: FeedTableViewCell = tableView.dequeueReusableCell(withIdentifier: "dogItemId") as! FeedTableViewCell 38 | 39 | cell.updateWithRandomData() 40 | 41 | return cell 42 | } 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "icon@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon@3x.png", 43 | "scale" : "3x" 44 | } 45 | ], 46 | "info" : { 47 | "version" : 1, 48 | "author" : "xcode" 49 | } 50 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/AppIcon.appiconset/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/AppIcon.appiconset/icon@2x.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/AppIcon.appiconset/icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/AppIcon.appiconset/icon@3x.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/development.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "filename" : "development@3x.png", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/development.imageset/development@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/development.imageset/development@3x.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "universal", 13 | "scale" : "3x" 14 | } 15 | ], 16 | "info" : { 17 | "version" : 1, 18 | "author" : "xcode" 19 | } 20 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/like.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "like@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "like@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/like.imageset/like@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/like.imageset/like@2x.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/like.imageset/like@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/like.imageset/like@3x.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/like256.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "like256.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/like256.imageset/like256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/like256.imageset/like256.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian0.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian0.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian0.imageset/siberian0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian0.imageset/siberian0.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian1.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian1.imageset/siberian1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian1.imageset/siberian1.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian10.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian10.imageset/siberian10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian10.imageset/siberian10.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian11.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian11.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian11.imageset/siberian11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian11.imageset/siberian11.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian12.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian12.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian12.imageset/siberian12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian12.imageset/siberian12.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian13.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian13.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian13.imageset/siberian13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian13.imageset/siberian13.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian14.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian14.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian14.imageset/siberian14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian14.imageset/siberian14.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian15.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian15.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian15.imageset/siberian15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian15.imageset/siberian15.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian16.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian16.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian16.imageset/siberian16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian16.imageset/siberian16.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian17.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian17.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian17.imageset/siberian17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian17.imageset/siberian17.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian18.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian18.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian18.imageset/siberian18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian18.imageset/siberian18.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian19.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian19.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian19.imageset/siberian19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian19.imageset/siberian19.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian2.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian2.imageset/siberian2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian2.imageset/siberian2.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian3.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian3.imageset/siberian3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian3.imageset/siberian3.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian4.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian4.imageset/siberian4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian4.imageset/siberian4.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian5.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian5.imageset/siberian5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian5.imageset/siberian5.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian6.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian6.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian6.imageset/siberian6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian6.imageset/siberian6.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian7.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian7.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian7.imageset/siberian7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian7.imageset/siberian7.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian8.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian8.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian8.imageset/siberian8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian8.imageset/siberian8.png -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian9.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "siberian9.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /dojo-table-performance/Images.xcassets/siberian9.imageset/siberian9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgraw/dojo-table-performance/be8c08204171f6a7f5d689e82357ec699a62d45a/dojo-table-performance/Images.xcassets/siberian9.imageset/siberian9.png -------------------------------------------------------------------------------- /dojo-table-performance/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 | UILaunchStoryboardName 31 | LaunchScreen_rank_3 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UIStatusBarHidden 39 | 40 | UISupportedInterfaceOrientations 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UIViewControllerBasedStatusBarAppearance 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /dojo-table-performance/LaunchScreen_rank_3.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 25 | 32 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | --------------------------------------------------------------------------------