Repository: hujewelz/HUPhotoBrowser Branch: master Commit: c7530436a646 Files: 189 Total size: 709.1 KB Directory structure: gitextract_ok1bowu5/ ├── .com.apple.timemachine.supported ├── .swift-version ├── Example/ │ ├── HUPhotoBrowser Demo/ │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.xib │ │ │ └── Main.storyboard │ │ ├── Images.xcassets/ │ │ │ └── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── PhotoCell.h │ │ ├── PhotoCell.m │ │ ├── ViewController.h │ │ ├── ViewController.m │ │ └── main.m │ ├── HUPhotoBrowser Demo.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── HUPhotoBrowser Demo.xccheckout │ │ └── xcuserdata/ │ │ ├── huluobo.xcuserdatad/ │ │ │ └── xcschemes/ │ │ │ └── xcschememanagement.plist │ │ ├── jewelz.xcuserdatad/ │ │ │ └── xcschemes/ │ │ │ ├── HUPhotoBrowser Demo.xcscheme │ │ │ └── xcschememanagement.plist │ │ └── mac.xcuserdatad/ │ │ ├── xcdebugger/ │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes/ │ │ ├── HUPhotoBrowser Demo.xcscheme │ │ └── xcschememanagement.plist │ ├── HUPhotoBrowser Demo.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata/ │ │ │ ├── HUPhotoBrowser Demo.xccheckout │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata/ │ │ ├── huluobo.xcuserdatad/ │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── xcdebugger/ │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── jewelz.xcuserdatad/ │ │ └── UserInterfaceState.xcuserstate │ ├── HUPhotoBrowser DemoTests/ │ │ ├── HUPhotoBrowser_DemoTests.m │ │ └── Info.plist │ ├── Podfile │ └── Pods/ │ ├── HUPhotoPicker/ │ │ ├── HUPhotoPicker/ │ │ │ ├── Assets/ │ │ │ │ └── HUAlbumCell.xib │ │ │ └── Classes/ │ │ │ ├── Asset.h │ │ │ ├── HUAlbumCell.h │ │ │ ├── HUAlbumCell.m │ │ │ ├── HUAlbumTableViewController.h │ │ │ ├── HUAlbumTableViewController.m │ │ │ ├── HUImageGridCell.h │ │ │ ├── HUImageGridCell.m │ │ │ ├── HUImageGridViewController.h │ │ │ ├── HUImageGridViewController.m │ │ │ ├── HUImagePickerViewController.h │ │ │ ├── HUImagePickerViewController.m │ │ │ ├── HUImageSelectModel.h │ │ │ ├── HUImageSelectModel.m │ │ │ ├── HUNavTitleView.h │ │ │ ├── HUNavTitleView.m │ │ │ ├── HUPHAuthorizationNotDeterminedView.h │ │ │ ├── HUPHAuthorizationNotDeterminedView.m │ │ │ ├── HUPHAuthorizationNotDeterminedViewController.h │ │ │ ├── HUPHAuthorizationNotDeterminedViewController.m │ │ │ ├── HUPhotoAlbum.h │ │ │ ├── HUPhotoAlbum.m │ │ │ ├── HUPhotoManager.h │ │ │ ├── HUPhotoManager.m │ │ │ ├── HUPhotoPicker.h │ │ │ ├── HUTakePhotoCell.h │ │ │ ├── HUTakePhotoCell.m │ │ │ ├── HUToast.h │ │ │ ├── HUToast.m │ │ │ ├── NSBundle+HUPicker.h │ │ │ ├── NSBundle+HUPicker.m │ │ │ ├── UIBarButtonItem+HUButton.h │ │ │ ├── UIBarButtonItem+HUButton.m │ │ │ ├── UIView+HUConstraint.h │ │ │ └── UIView+HUConstraint.m │ │ ├── LICENSE │ │ └── README.md │ ├── Local Podspecs/ │ │ └── HUPhotoBrowser.podspec.json │ ├── Pods.xcodeproj/ │ │ ├── project.pbxproj │ │ └── xcuserdata/ │ │ ├── huluobo.xcuserdatad/ │ │ │ └── xcschemes/ │ │ │ ├── HUPhotoBrowser.xcscheme │ │ │ ├── HUPhotoPicker-HUPhotoPicker.xcscheme │ │ │ ├── HUPhotoPicker.xcscheme │ │ │ ├── Pods-HUPhotoBrowser Demo.xcscheme │ │ │ ├── Pods-HUPhotoBrowser DemoTests.xcscheme │ │ │ ├── SDWebImage.xcscheme │ │ │ ├── SVProgressHUD.xcscheme │ │ │ └── xcschememanagement.plist │ │ └── jewelz.xcuserdatad/ │ │ └── xcschemes/ │ │ ├── HUPhotoBrowser.xcscheme │ │ ├── HUPhotoPicker-HUPhotoPicker.xcscheme │ │ ├── HUPhotoPicker.xcscheme │ │ ├── Pods-HUPhotoBrowser Demo.xcscheme │ │ ├── Pods-HUPhotoBrowser DemoTests.xcscheme │ │ ├── SDWebImage.xcscheme │ │ └── xcschememanagement.plist │ ├── SDWebImage/ │ │ ├── LICENSE │ │ ├── README.md │ │ └── SDWebImage/ │ │ ├── NSData+ImageContentType.h │ │ ├── NSData+ImageContentType.m │ │ ├── NSImage+WebCache.h │ │ ├── NSImage+WebCache.m │ │ ├── SDImageCache.h │ │ ├── SDImageCache.m │ │ ├── SDImageCacheConfig.h │ │ ├── SDImageCacheConfig.m │ │ ├── SDWebImageCompat.h │ │ ├── SDWebImageCompat.m │ │ ├── SDWebImageDecoder.h │ │ ├── SDWebImageDecoder.m │ │ ├── SDWebImageDownloader.h │ │ ├── SDWebImageDownloader.m │ │ ├── SDWebImageDownloaderOperation.h │ │ ├── SDWebImageDownloaderOperation.m │ │ ├── SDWebImageManager.h │ │ ├── SDWebImageManager.m │ │ ├── SDWebImageOperation.h │ │ ├── SDWebImagePrefetcher.h │ │ ├── SDWebImagePrefetcher.m │ │ ├── UIButton+WebCache.h │ │ ├── UIButton+WebCache.m │ │ ├── UIImage+GIF.h │ │ ├── UIImage+GIF.m │ │ ├── UIImage+MultiFormat.h │ │ ├── UIImage+MultiFormat.m │ │ ├── UIImageView+HighlightedWebCache.h │ │ ├── UIImageView+HighlightedWebCache.m │ │ ├── UIImageView+WebCache.h │ │ ├── UIImageView+WebCache.m │ │ ├── UIView+WebCache.h │ │ ├── UIView+WebCache.m │ │ ├── UIView+WebCacheOperation.h │ │ └── UIView+WebCacheOperation.m │ ├── SVProgressHUD/ │ │ ├── LICENSE.txt │ │ ├── README.md │ │ └── SVProgressHUD/ │ │ ├── SVIndefiniteAnimatedView.h │ │ ├── SVIndefiniteAnimatedView.m │ │ ├── SVProgressAnimatedView.h │ │ ├── SVProgressAnimatedView.m │ │ ├── SVProgressHUD.h │ │ ├── SVProgressHUD.m │ │ ├── SVRadialGradientLayer.h │ │ └── SVRadialGradientLayer.m │ └── Target Support Files/ │ ├── HUPhotoBrowser/ │ │ ├── HUPhotoBrowser-dummy.m │ │ ├── HUPhotoBrowser-prefix.pch │ │ └── HUPhotoBrowser.xcconfig │ ├── HUPhotoPicker/ │ │ ├── HUPhotoPicker-dummy.m │ │ ├── HUPhotoPicker-prefix.pch │ │ ├── HUPhotoPicker.xcconfig │ │ └── ResourceBundle-HUPhotoPicker-Info.plist │ ├── Pods-HUPhotoBrowser Demo/ │ │ ├── Pods-HUPhotoBrowser Demo-acknowledgements.markdown │ │ ├── Pods-HUPhotoBrowser Demo-acknowledgements.plist │ │ ├── Pods-HUPhotoBrowser Demo-dummy.m │ │ ├── Pods-HUPhotoBrowser Demo-frameworks.sh │ │ ├── Pods-HUPhotoBrowser Demo-resources.sh │ │ ├── Pods-HUPhotoBrowser Demo.debug.xcconfig │ │ └── Pods-HUPhotoBrowser Demo.release.xcconfig │ ├── Pods-HUPhotoBrowser DemoTests/ │ │ ├── Pods-HUPhotoBrowser DemoTests-acknowledgements.markdown │ │ ├── Pods-HUPhotoBrowser DemoTests-acknowledgements.plist │ │ ├── Pods-HUPhotoBrowser DemoTests-dummy.m │ │ ├── Pods-HUPhotoBrowser DemoTests-frameworks.sh │ │ ├── Pods-HUPhotoBrowser DemoTests-resources.sh │ │ ├── Pods-HUPhotoBrowser DemoTests.debug.xcconfig │ │ └── Pods-HUPhotoBrowser DemoTests.release.xcconfig │ ├── SDWebImage/ │ │ ├── SDWebImage-dummy.m │ │ ├── SDWebImage-prefix.pch │ │ └── SDWebImage.xcconfig │ └── SVProgressHUD/ │ ├── SVProgressHUD-dummy.m │ ├── SVProgressHUD-prefix.pch │ └── SVProgressHUD.xcconfig ├── HUPhotoBrowser/ │ ├── HUPhotoBrowser.h │ ├── HUPhotoBrowser.m │ ├── HUPhotoBrowserCell.h │ ├── HUPhotoBrowserCell.m │ ├── HUWebImageDownloader/ │ │ ├── HUWebImage.h │ │ ├── HUWebImageDownloadOperation.h │ │ ├── HUWebImageDownloadOperation.m │ │ ├── HUWebImageDownloader.h │ │ ├── HUWebImageDownloader.m │ │ ├── UIImage+HUExtension.h │ │ ├── UIImage+HUExtension.m │ │ ├── UIImageView+HUWebImage.h │ │ └── UIImageView+HUWebImage.m │ ├── UIView+frame.h │ ├── UIView+frame.m │ └── hu_const.h ├── HUPhotoBrowser.a ├── HUPhotoBrowser.podspec ├── HUPhotoBrowser.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata/ │ │ │ └── HUPhotoBrowser.xccheckout │ │ └── xcuserdata/ │ │ └── jewelz.xcuserdatad/ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata/ │ ├── jewelz.xcuserdatad/ │ │ └── xcschemes/ │ │ ├── HUPhotoBrowser.xcscheme │ │ └── xcschememanagement.plist │ └── mac.xcuserdatad/ │ ├── xcdebugger/ │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes/ │ ├── HUPhotoBrowser.xcscheme │ └── xcschememanagement.plist ├── HUPhotoBrowserTests/ │ └── Info.plist ├── LICENSE └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .com.apple.timemachine.supported ================================================ ================================================ FILE: .swift-version ================================================ 2.3 ================================================ FILE: Example/HUPhotoBrowser Demo/AppDelegate.h ================================================ // // AppDelegate.h // HUPhotoBrowser Demo // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Example/HUPhotoBrowser Demo/AppDelegate.m ================================================ // // AppDelegate.m // HUPhotoBrowser Demo // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: Example/HUPhotoBrowser Demo/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: Example/HUPhotoBrowser Demo/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Example/HUPhotoBrowser Demo/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/HUPhotoBrowser Demo/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight NSPhotoLibraryUsageDescription UIViewControllerBasedStatusBarAppearance ================================================ FILE: Example/HUPhotoBrowser Demo/PhotoCell.h ================================================ // // PhotoCell.h // HUPhotoBrowser Demo // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import @interface PhotoCell : UICollectionViewCell @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end ================================================ FILE: Example/HUPhotoBrowser Demo/PhotoCell.m ================================================ // // PhotoCell.m // HUPhotoBrowser Demo // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import "PhotoCell.h" @implementation PhotoCell @end ================================================ FILE: Example/HUPhotoBrowser Demo/ViewController.h ================================================ // // ViewController.h // HUPhotoBrowser Demo // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import @interface ViewController : UIViewController @end ================================================ FILE: Example/HUPhotoBrowser Demo/ViewController.m ================================================ // // ViewController.m // HUPhotoBrowser Demo // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import "ViewController.h" #import "PhotoCell.h" #import "HUPhotoBrowser.h" #import #import #import @interface ViewController () { BOOL _localImage; } @property (weak, nonatomic) IBOutlet UICollectionView *collectionView; @property (nonatomic, strong) NSArray *images; @property (nonatomic, strong) NSArray *originalImages; @property (nonatomic, strong) NSMutableArray *URLStrings; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"HUPhotoBrowser Demo"; _URLStrings = [NSMutableArray array]; // Do any additional setup after loading the view, typically from a nib. [self getWebImages]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark collection view data source - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return _localImage ? _images.count : _URLStrings.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PhotoCell" forIndexPath:indexPath]; if (_localImage) { cell.imageView.image = self.images[indexPath.row]; } else { [cell.imageView hu_setImageWithURL:[NSURL URLWithString:_URLStrings[indexPath.row]]]; } return cell; } #pragma mark - collection view delegate - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { PhotoCell *cell = (PhotoCell *)[collectionView cellForItemAtIndexPath:indexPath]; if (_localImage) { [HUPhotoBrowser showFromImageView:cell.imageView withImages:self.originalImages atIndex:indexPath.row]; } else { [HUPhotoBrowser showFromImageView:cell.imageView withURLStrings:_URLStrings placeholderImage:[UIImage imageNamed:@"placeholder"] atIndex:indexPath.row dismiss:nil]; } } #pragma mark - HUImagePickerViewControllerDelegate - (void)imagePickerViewController:(HUImagePickerViewController *)imagePickerViewController didFinishPickingImageWithImages:(NSArray *)images assets:(NSArray *)assets { [self dismissViewControllerAnimated:YES completion:nil]; _images = images; _originalImages = images; _localImage = YES; [self.collectionView reloadData]; } #pragma mark - IBAction - (IBAction)pickImage:(id)sender { HUImagePickerViewController *picker = [[HUImagePickerViewController alloc] init]; picker.delegate = self; [self presentViewController:picker animated:YES completion:nil]; } - (IBAction)refresh:(id)sender { [self getWebImages]; _localImage = NO; [self.collectionView reloadData]; } #pragma mark - private - (void)getWebImages { NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; NSURL *url = [NSURL URLWithString:@"https://pixabay.com/api/?key=4572819-33c1e1dcbac7521c915689a81&&image_type=photo"]; NSURLRequest *repuest = [NSURLRequest requestWithURL:url]; NSURLSessionDataTask *task = [session dataTaskWithRequest:repuest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSMutableArray *urlS = [NSMutableArray array]; for (NSDictionary *dict in result[@"hits"]) { NSString *linkurl = dict[@"webformatURL"]; [urlS addObject:linkurl]; } _URLStrings = urlS; dispatch_async(dispatch_get_main_queue(), ^{ [self.collectionView reloadData]; }); }]; [task resume]; } @end ================================================ FILE: Example/HUPhotoBrowser Demo/main.m ================================================ // // main.m // HUPhotoBrowser Demo // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 040623A31C7E9989005653C1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 040623A21C7E9989005653C1 /* main.m */; }; 040623A61C7E9989005653C1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 040623A51C7E9989005653C1 /* AppDelegate.m */; }; 040623A91C7E9989005653C1 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 040623A81C7E9989005653C1 /* ViewController.m */; }; 040623AC1C7E9989005653C1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 040623AA1C7E9989005653C1 /* Main.storyboard */; }; 040623AE1C7E9989005653C1 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 040623AD1C7E9989005653C1 /* Images.xcassets */; }; 040623B11C7E9989005653C1 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 040623AF1C7E9989005653C1 /* LaunchScreen.xib */; }; 040623BD1C7E9989005653C1 /* HUPhotoBrowser_DemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 040623BC1C7E9989005653C1 /* HUPhotoBrowser_DemoTests.m */; }; 040624021C7E9BB6005653C1 /* PhotoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 040624011C7E9BB6005653C1 /* PhotoCell.m */; }; 044D06501CD34623005BDFF2 /* placeholder.png in Resources */ = {isa = PBXBuildFile; fileRef = 044D064F1CD34623005BDFF2 /* placeholder.png */; }; BAE6B9A9C28D8D7FBAFBD61F /* libPods-HUPhotoBrowser DemoTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB702EF6466173C9049EA4E3 /* libPods-HUPhotoBrowser DemoTests.a */; }; C2CE112E20AE7956006DEB06 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = C2CE112B20AE7956006DEB06 /* README.md */; }; C2CE112F20AE7956006DEB06 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = C2CE112C20AE7956006DEB06 /* LICENSE */; }; C2CE113020AE7956006DEB06 /* HUPhotoBrowser.podspec in Resources */ = {isa = PBXBuildFile; fileRef = C2CE112D20AE7956006DEB06 /* HUPhotoBrowser.podspec */; }; F5D16FEE5AB714F5360AD713 /* libPods-HUPhotoBrowser Demo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B3405AA6738D3B753050B7C /* libPods-HUPhotoBrowser Demo.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 040623B71C7E9989005653C1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 040623951C7E9989005653C1 /* Project object */; proxyType = 1; remoteGlobalIDString = 0406239C1C7E9989005653C1; remoteInfo = "HUPhotoBrowser Demo"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 0406239D1C7E9989005653C1 /* HUPhotoBrowser Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "HUPhotoBrowser Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 040623A11C7E9989005653C1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 040623A21C7E9989005653C1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 040623A41C7E9989005653C1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 040623A51C7E9989005653C1 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 040623A71C7E9989005653C1 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 040623A81C7E9989005653C1 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 040623AB1C7E9989005653C1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 040623AD1C7E9989005653C1 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 040623B01C7E9989005653C1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 040623B61C7E9989005653C1 /* HUPhotoBrowser DemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "HUPhotoBrowser DemoTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 040623BB1C7E9989005653C1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 040623BC1C7E9989005653C1 /* HUPhotoBrowser_DemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HUPhotoBrowser_DemoTests.m; sourceTree = ""; }; 040624001C7E9BB6005653C1 /* PhotoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotoCell.h; sourceTree = ""; }; 040624011C7E9BB6005653C1 /* PhotoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhotoCell.m; sourceTree = ""; }; 044D064F1CD34623005BDFF2 /* placeholder.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = placeholder.png; sourceTree = ""; }; 0B3405AA6738D3B753050B7C /* libPods-HUPhotoBrowser Demo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HUPhotoBrowser Demo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3F903672B8A30024BEB85314 /* Pods-HUPhotoBrowser Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HUPhotoBrowser Demo.release.xcconfig"; path = "Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo.release.xcconfig"; sourceTree = ""; }; 5E779CEE89A1CB6936C03263 /* Pods-HUPhotoBrowser Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HUPhotoBrowser Demo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo.debug.xcconfig"; sourceTree = ""; }; C2CE112B20AE7956006DEB06 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = ""; }; C2CE112C20AE7956006DEB06 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../../LICENSE; sourceTree = ""; }; C2CE112D20AE7956006DEB06 /* HUPhotoBrowser.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = HUPhotoBrowser.podspec; path = ../../HUPhotoBrowser.podspec; sourceTree = ""; }; E46B2F0916D241B35A9BD18C /* Pods-HUPhotoBrowser DemoTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HUPhotoBrowser DemoTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests.release.xcconfig"; sourceTree = ""; }; F1491B717433294000E08563 /* Pods-HUPhotoBrowser DemoTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HUPhotoBrowser DemoTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests.debug.xcconfig"; sourceTree = ""; }; FB702EF6466173C9049EA4E3 /* libPods-HUPhotoBrowser DemoTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HUPhotoBrowser DemoTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0406239A1C7E9989005653C1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( F5D16FEE5AB714F5360AD713 /* libPods-HUPhotoBrowser Demo.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 040623B31C7E9989005653C1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( BAE6B9A9C28D8D7FBAFBD61F /* libPods-HUPhotoBrowser DemoTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 040623941C7E9989005653C1 = { isa = PBXGroup; children = ( C2CE112A20AE7939006DEB06 /* Podspec Metadata */, 0406239F1C7E9989005653C1 /* HUPhotoBrowser Demo */, 040623B91C7E9989005653C1 /* HUPhotoBrowser DemoTests */, 0406239E1C7E9989005653C1 /* Products */, AFAAEBF96020AD44718B49B4 /* Pods */, FAC6D30897335D2BCBFDD90B /* Frameworks */, ); sourceTree = ""; }; 0406239E1C7E9989005653C1 /* Products */ = { isa = PBXGroup; children = ( 0406239D1C7E9989005653C1 /* HUPhotoBrowser Demo.app */, 040623B61C7E9989005653C1 /* HUPhotoBrowser DemoTests.xctest */, ); name = Products; sourceTree = ""; }; 0406239F1C7E9989005653C1 /* HUPhotoBrowser Demo */ = { isa = PBXGroup; children = ( 040623A41C7E9989005653C1 /* AppDelegate.h */, 040623A51C7E9989005653C1 /* AppDelegate.m */, 040623A71C7E9989005653C1 /* ViewController.h */, 040623A81C7E9989005653C1 /* ViewController.m */, 040624001C7E9BB6005653C1 /* PhotoCell.h */, 040624011C7E9BB6005653C1 /* PhotoCell.m */, 040623AA1C7E9989005653C1 /* Main.storyboard */, 040623AD1C7E9989005653C1 /* Images.xcassets */, 040623AF1C7E9989005653C1 /* LaunchScreen.xib */, 040623A01C7E9989005653C1 /* Supporting Files */, ); path = "HUPhotoBrowser Demo"; sourceTree = ""; }; 040623A01C7E9989005653C1 /* Supporting Files */ = { isa = PBXGroup; children = ( 044D064F1CD34623005BDFF2 /* placeholder.png */, 040623A11C7E9989005653C1 /* Info.plist */, 040623A21C7E9989005653C1 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 040623B91C7E9989005653C1 /* HUPhotoBrowser DemoTests */ = { isa = PBXGroup; children = ( 040623BC1C7E9989005653C1 /* HUPhotoBrowser_DemoTests.m */, 040623BA1C7E9989005653C1 /* Supporting Files */, ); path = "HUPhotoBrowser DemoTests"; sourceTree = ""; }; 040623BA1C7E9989005653C1 /* Supporting Files */ = { isa = PBXGroup; children = ( 040623BB1C7E9989005653C1 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; AFAAEBF96020AD44718B49B4 /* Pods */ = { isa = PBXGroup; children = ( 5E779CEE89A1CB6936C03263 /* Pods-HUPhotoBrowser Demo.debug.xcconfig */, 3F903672B8A30024BEB85314 /* Pods-HUPhotoBrowser Demo.release.xcconfig */, F1491B717433294000E08563 /* Pods-HUPhotoBrowser DemoTests.debug.xcconfig */, E46B2F0916D241B35A9BD18C /* Pods-HUPhotoBrowser DemoTests.release.xcconfig */, ); name = Pods; sourceTree = ""; }; C2CE112A20AE7939006DEB06 /* Podspec Metadata */ = { isa = PBXGroup; children = ( C2CE112D20AE7956006DEB06 /* HUPhotoBrowser.podspec */, C2CE112C20AE7956006DEB06 /* LICENSE */, C2CE112B20AE7956006DEB06 /* README.md */, ); path = "Podspec Metadata"; sourceTree = ""; }; FAC6D30897335D2BCBFDD90B /* Frameworks */ = { isa = PBXGroup; children = ( 0B3405AA6738D3B753050B7C /* libPods-HUPhotoBrowser Demo.a */, FB702EF6466173C9049EA4E3 /* libPods-HUPhotoBrowser DemoTests.a */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 0406239C1C7E9989005653C1 /* HUPhotoBrowser Demo */ = { isa = PBXNativeTarget; buildConfigurationList = 040623C01C7E9989005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowser Demo" */; buildPhases = ( A962A2954A15437EEDEDD01C /* [CP] Check Pods Manifest.lock */, 040623991C7E9989005653C1 /* Sources */, 0406239A1C7E9989005653C1 /* Frameworks */, 0406239B1C7E9989005653C1 /* Resources */, B0E9B81CB19068F4E9174942 /* [CP] Embed Pods Frameworks */, 97981A438D22C17C60DAD2EE /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = "HUPhotoBrowser Demo"; productName = "HUPhotoBrowser Demo"; productReference = 0406239D1C7E9989005653C1 /* HUPhotoBrowser Demo.app */; productType = "com.apple.product-type.application"; }; 040623B51C7E9989005653C1 /* HUPhotoBrowser DemoTests */ = { isa = PBXNativeTarget; buildConfigurationList = 040623C31C7E9989005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowser DemoTests" */; buildPhases = ( E0F2C44E94EA75AA6F5357CA /* [CP] Check Pods Manifest.lock */, 040623B21C7E9989005653C1 /* Sources */, 040623B31C7E9989005653C1 /* Frameworks */, 040623B41C7E9989005653C1 /* Resources */, 65F7F3B05B67ECD82A8D70B0 /* [CP] Embed Pods Frameworks */, 4267A09C64DAB8DB54D72BE0 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( 040623B81C7E9989005653C1 /* PBXTargetDependency */, ); name = "HUPhotoBrowser DemoTests"; productName = "HUPhotoBrowser DemoTests"; productReference = 040623B61C7E9989005653C1 /* HUPhotoBrowser DemoTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 040623951C7E9989005653C1 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0730; ORGANIZATIONNAME = hujewelz; TargetAttributes = { 0406239C1C7E9989005653C1 = { CreatedOnToolsVersion = 6.4; DevelopmentTeam = 6E4KPH54E6; }; 040623B51C7E9989005653C1 = { CreatedOnToolsVersion = 6.4; TestTargetID = 0406239C1C7E9989005653C1; }; }; }; buildConfigurationList = 040623981C7E9989005653C1 /* Build configuration list for PBXProject "HUPhotoBrowser Demo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 040623941C7E9989005653C1; productRefGroup = 0406239E1C7E9989005653C1 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 0406239C1C7E9989005653C1 /* HUPhotoBrowser Demo */, 040623B51C7E9989005653C1 /* HUPhotoBrowser DemoTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 0406239B1C7E9989005653C1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( C2CE113020AE7956006DEB06 /* HUPhotoBrowser.podspec in Resources */, C2CE112F20AE7956006DEB06 /* LICENSE in Resources */, 044D06501CD34623005BDFF2 /* placeholder.png in Resources */, 040623AC1C7E9989005653C1 /* Main.storyboard in Resources */, C2CE112E20AE7956006DEB06 /* README.md in Resources */, 040623B11C7E9989005653C1 /* LaunchScreen.xib in Resources */, 040623AE1C7E9989005653C1 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 040623B41C7E9989005653C1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 4267A09C64DAB8DB54D72BE0 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; 65F7F3B05B67ECD82A8D70B0 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 97981A438D22C17C60DAD2EE /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-resources.sh", $PODS_CONFIGURATION_BUILD_DIR/HUPhotoPicker/HUPhotoPicker.bundle, "${PODS_ROOT}/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-resources.sh\"\n"; showEnvVarsInLog = 0; }; A962A2954A15437EEDEDD01C /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-HUPhotoBrowser Demo-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; B0E9B81CB19068F4E9174942 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; E0F2C44E94EA75AA6F5357CA /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-HUPhotoBrowser DemoTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 040623991C7E9989005653C1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 040624021C7E9BB6005653C1 /* PhotoCell.m in Sources */, 040623A91C7E9989005653C1 /* ViewController.m in Sources */, 040623A61C7E9989005653C1 /* AppDelegate.m in Sources */, 040623A31C7E9989005653C1 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 040623B21C7E9989005653C1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 040623BD1C7E9989005653C1 /* HUPhotoBrowser_DemoTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 040623B81C7E9989005653C1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0406239C1C7E9989005653C1 /* HUPhotoBrowser Demo */; targetProxy = 040623B71C7E9989005653C1 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 040623AA1C7E9989005653C1 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 040623AB1C7E9989005653C1 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 040623AF1C7E9989005653C1 /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( 040623B01C7E9989005653C1 /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 040623BE1C7E9989005653C1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 040623BF1C7E9989005653C1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.4; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 040623C11C7E9989005653C1 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 5E779CEE89A1CB6936C03263 /* Pods-HUPhotoBrowser Demo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEVELOPMENT_TEAM = 6E4KPH54E6; INFOPLIST_FILE = "HUPhotoBrowser Demo/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hujewelz.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; }; name = Debug; }; 040623C21C7E9989005653C1 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 3F903672B8A30024BEB85314 /* Pods-HUPhotoBrowser Demo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEVELOPMENT_TEAM = 6E4KPH54E6; INFOPLIST_FILE = "HUPhotoBrowser Demo/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hujewelz.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; }; name = Release; }; 040623C41C7E9989005653C1 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = F1491B717433294000E08563 /* Pods-HUPhotoBrowser DemoTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = "HUPhotoBrowser DemoTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hujewelz.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HUPhotoBrowser Demo.app/HUPhotoBrowser Demo"; }; name = Debug; }; 040623C51C7E9989005653C1 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = E46B2F0916D241B35A9BD18C /* Pods-HUPhotoBrowser DemoTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = "HUPhotoBrowser DemoTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hujewelz.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HUPhotoBrowser Demo.app/HUPhotoBrowser Demo"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 040623981C7E9989005653C1 /* Build configuration list for PBXProject "HUPhotoBrowser Demo" */ = { isa = XCConfigurationList; buildConfigurations = ( 040623BE1C7E9989005653C1 /* Debug */, 040623BF1C7E9989005653C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 040623C01C7E9989005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowser Demo" */ = { isa = XCConfigurationList; buildConfigurations = ( 040623C11C7E9989005653C1 /* Debug */, 040623C21C7E9989005653C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 040623C31C7E9989005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowser DemoTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 040623C41C7E9989005653C1 /* Debug */, 040623C51C7E9989005653C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 040623951C7E9989005653C1 /* Project object */; } ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/project.xcworkspace/xcshareddata/HUPhotoBrowser Demo.xccheckout ================================================ IDESourceControlProjectFavoriteDictionaryKey IDESourceControlProjectIdentifier CE29FB11-1DFE-4499-9106-1E1B43F85B28 IDESourceControlProjectName HUPhotoBrowser Demo IDESourceControlProjectOriginsDictionary 3E54BB6501640F2F1E4E23A6F020501F2858AB48 https://github.com/hujewelz/HUPhotoBrowser.git IDESourceControlProjectPath Example/HUPhotoBrowser Demo.xcodeproj IDESourceControlProjectRelativeInstallPathDictionary 3E54BB6501640F2F1E4E23A6F020501F2858AB48 ../../.. IDESourceControlProjectURL https://github.com/hujewelz/HUPhotoBrowser.git IDESourceControlProjectVersion 111 IDESourceControlProjectWCCIdentifier 3E54BB6501640F2F1E4E23A6F020501F2858AB48 IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey 3E54BB6501640F2F1E4E23A6F020501F2858AB48 IDESourceControlWCCName HUPhotoBrowser ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState HUPhotoBrowser Demo.xcscheme orderHint 7 ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/HUPhotoBrowser Demo.xcscheme ================================================ ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState HUPhotoBrowser Demo.xcscheme orderHint 0 SuppressBuildableAutocreation 0406239C1C7E9989005653C1 primary 040623B51C7E9989005653C1 primary ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/xcuserdata/mac.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist ================================================ ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/xcuserdata/mac.xcuserdatad/xcschemes/HUPhotoBrowser Demo.xcscheme ================================================ ================================================ FILE: Example/HUPhotoBrowser Demo.xcodeproj/xcuserdata/mac.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState HUPhotoBrowser Demo.xcscheme orderHint 0 SuppressBuildableAutocreation 0406239C1C7E9989005653C1 primary 040623B51C7E9989005653C1 primary ================================================ FILE: Example/HUPhotoBrowser Demo.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/HUPhotoBrowser Demo.xcworkspace/xcshareddata/HUPhotoBrowser Demo.xccheckout ================================================ IDESourceControlProjectFavoriteDictionaryKey IDESourceControlProjectIdentifier 06162301-A6AF-43BC-A098-A5C0AEEEF86B IDESourceControlProjectName HUPhotoBrowser Demo IDESourceControlProjectOriginsDictionary 3E54BB6501640F2F1E4E23A6F020501F2858AB48 https://github.com/hujewelz/HUPhotoBrowser.git IDESourceControlProjectPath Example/HUPhotoBrowser Demo.xcworkspace IDESourceControlProjectRelativeInstallPathDictionary 3E54BB6501640F2F1E4E23A6F020501F2858AB48 ../.. IDESourceControlProjectURL https://github.com/hujewelz/HUPhotoBrowser.git IDESourceControlProjectVersion 111 IDESourceControlProjectWCCIdentifier 3E54BB6501640F2F1E4E23A6F020501F2858AB48 IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey 3E54BB6501640F2F1E4E23A6F020501F2858AB48 IDESourceControlWCCName HUPhotoBrowser ================================================ FILE: Example/HUPhotoBrowser Demo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/HUPhotoBrowser Demo.xcworkspace/xcuserdata/huluobo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist ================================================ ================================================ FILE: Example/HUPhotoBrowser DemoTests/HUPhotoBrowser_DemoTests.m ================================================ // // HUPhotoBrowser_DemoTests.m // HUPhotoBrowser DemoTests // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import #import @interface HUPhotoBrowser_DemoTests : XCTestCase @end @implementation HUPhotoBrowser_DemoTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. XCTAssert(YES, @"Pass"); } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: Example/HUPhotoBrowser DemoTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Example/Podfile ================================================ # Uncomment this line to define a global platform for your project platform :ios, '8.0' # Uncomment this line if you're using Swift # use_frameworks! target 'HUPhotoBrowser Demo' do pod 'HUPhotoBrowser', :path => '../' pod 'SDWebImage' pod 'HUPhotoPicker', '~> 1.0.3' end target 'HUPhotoBrowser DemoTests' do end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Assets/HUAlbumCell.xib ================================================ ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/Asset.h ================================================ // // Asset.h // HUPhotoPicker // // Created by jewelz on 2017/7/28. // #ifndef Asset_h #define Asset_h #import "NSBundle+HUPicker.h" #define UIFontBoldMake(size) [UIFont boldSystemFontOfSize:(size)] #define UIFontMake(size) [UIFont systemFontOfSize:(size)] #define UIColorMake(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] #define UIImageMake(named) [NSBundle hu_imageNamed:(named)] #endif /* Asset_h */ ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUAlbumCell.h ================================================ // // BAAlbumCell.h // beautyAssistant // // Created by jewelz on 2017/6/26. // Copyright © 2017年 Service+. All rights reserved. // #import @interface HUAlbumCell : UITableViewCell + (UINib *)nib; + (NSString *)reuseIdentifier; @property (weak, nonatomic) IBOutlet UIImageView *album; @property (weak, nonatomic) IBOutlet UILabel *titleLabel; @property (weak, nonatomic) IBOutlet UILabel *countLabel; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUAlbumCell.m ================================================ // // BAAlbumCell.m // beautyAssistant // // Created by jewelz on 2017/6/26. // Copyright © 2017年 Service+. All rights reserved. // #import "HUAlbumCell.h" #import "NSBundle+HUPicker.h" #import "NSBundle+HUPicker.h" @implementation HUAlbumCell + (UINib *)nib { // NSBundle *podBundle = [NSBundle bundleForClass:[self class]]; return [UINib nibWithNibName:@"HUAlbumCell" bundle:[NSBundle hu_bundle]]; } + (NSString *)reuseIdentifier { return @"BAAlbumCell"; } - (void)awakeFromNib { [super awakeFromNib]; // Initialization code } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUAlbumTableViewController.h ================================================ // // BAAlbumTableViewController.h // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import @class PHFetchResult; @interface HUAlbumTableViewController : UITableViewController @property (nonatomic, copy) void (^didSelectedAlbum)(NSString *title, PHFetchResult *fetchResult); @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUAlbumTableViewController.m ================================================ // // BAAlbumTableViewController.m // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import "HUAlbumTableViewController.h" #import "HUImageGridViewController.h" #import #import "HUAlbumCell.h" #import "HUPhotoAlbum.h" @interface HUAlbumTableViewController () { PHFetchResult *_smartAlbums; PHFetchResult *_userCollectons; } @property (nonatomic, strong) PHFetchResult *allPhotos; //@property (nonatomic, strong) NSArray *smartAlbums; //@property (nonatomic, strong) NSArray *userCollectons; @property (nonatomic, strong) PHCachingImageManager *cachingImageManager; @property (nonatomic, strong) PHImageRequestOptions *options; @property (nonatomic, strong) NSArray *allAlbums; @end @implementation HUAlbumTableViewController - (void)viewDidLoad { [super viewDidLoad]; PHAuthorizationStatus author = [PHPhotoLibrary authorizationStatus]; if (author == PHAuthorizationStatusNotDetermined) { // 无权限 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusAuthorized) { [self setupData]; return ; } [self rightBarItemClicked]; }]; return; } if (author == PHAuthorizationStatusRestricted || author == PHAuthorizationStatusDenied) { [self rightBarItemClicked]; return; } [self setupData]; } - (void)dealloc { if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self]; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)rightBarItemClicked { [self.navigationController dismissViewControllerAnimated:YES completion:nil]; } #pragma mark - Table view data source //- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // return 2; //} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.allAlbums.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { PHAsset *asset = nil; HUAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:[HUAlbumCell reuseIdentifier] forIndexPath:indexPath]; HUPhotoAlbum *album = self.allAlbums[indexPath.row]; cell.titleLabel.text = album.title; cell.countLabel.text = [NSString stringWithFormat:@"%zd", album.assetCount]; PHFetchResult *results = [PHAsset fetchAssetsInAssetCollection:album.collection options:nil]; asset = [results firstObject]; [_cachingImageManager requestImageForAsset:asset targetSize:CGSizeMake(120, 120) contentMode:PHImageContentModeDefault options:_options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { // NSLog(@"result: %@", result); cell.album.image = result; }]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { HUPhotoAlbum *album = self.allAlbums[indexPath.row]; //HUImageGridViewController *vc = [[HUImageGridViewController alloc] init]; PHFetchOptions *options = [PHFetchOptions new]; options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]; PHFetchResult *results = [PHAsset fetchAssetsInAssetCollection:album.collection options:options]; // vc.title = album.title; // vc.fetchResult = results; // [self.navigationController pushViewController:vc animated:true]; if (_didSelectedAlbum) { _didSelectedAlbum(album.title, results); } } - (void)photoLibraryDidChange:(PHChange *)changeInstance { dispatch_sync(dispatch_get_main_queue(), ^{ PHFetchResultChangeDetails *all = [changeInstance changeDetailsForFetchResult:_allPhotos]; PHFetchResultChangeDetails *details = [changeInstance changeDetailsForFetchResult:_smartAlbums]; PHFetchResultChangeDetails *users = [changeInstance changeDetailsForFetchResult:_userCollectons]; if (all) { _allPhotos = [all fetchResultAfterChanges]; } if (details) { _smartAlbums = [details fetchResultAfterChanges]; } if (users) { _userCollectons = [users fetchResultAfterChanges]; } self.allAlbums = [self getPhotoAlbumsFromSmallAlbumsAndUserCollections]; [self.tableView reloadData]; }); } # pragma mark - Private - (void)setupData { self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(rightBarItemClicked)]; self.tableView.rowHeight = 80; [self.tableView registerNib:[HUAlbumCell nib] forCellReuseIdentifier:[HUAlbumCell reuseIdentifier]]; _cachingImageManager = [[PHCachingImageManager alloc] init]; PHFetchOptions *options = [PHFetchOptions new]; options.includeAssetSourceTypes = PHAssetResourceTypePhoto; _smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:options]; _userCollectons = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:options]; self.allAlbums = [self getPhotoAlbumsFromSmallAlbumsAndUserCollections]; options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]; _allPhotos = [PHAsset fetchAssetsWithOptions:options]; [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self]; } - (NSArray *)getPhotoAlbumsFromSmallAlbumsAndUserCollections { NSMutableArray *allAlums = [NSMutableArray array]; NSArray *smarts = [self getPhotoAlbumsWithPHAssetCollection:_smartAlbums]; [allAlums addObjectsFromArray:smarts]; NSArray *users = [self getPhotoAlbumsWithPHAssetCollection:_userCollectons]; [allAlums addObjectsFromArray:users]; return [allAlums copy]; } - (NSArray *)getPhotoAlbumsWithPHAssetCollection:(id)assetCollections { NSMutableArray *collections = [NSMutableArray array]; HUPhotoAlbum *album = nil; for (PHCollection *collection in assetCollections) { if ([collection isKindOfClass:[PHAssetCollection class]]) { PHFetchResult *results = [PHAsset fetchAssetsInAssetCollection:(PHAssetCollection *)collection options:nil]; if (results.count > 0) { album = [HUPhotoAlbum photoAlbumWithAssetCollection:(PHAssetCollection*)collection assetCount:results.count]; [collections addObject: album]; } } } return collections; } #pragma mark - getter & setter - (NSArray *)allAlbums { if (_allAlbums == nil) { _allAlbums = [NSArray array]; } return _allAlbums; } - (PHImageRequestOptions *)options { if (_options == nil) { _options = [PHImageRequestOptions new]; _options.resizeMode = PHImageRequestOptionsResizeModeFast; [_options setSynchronous:false]; [_options setNetworkAccessAllowed:false]; } return _options; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImageGridCell.h ================================================ // // BAImageGridCell.h // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import #import "HUImageSelectModel.h" @interface HUImageGridCell : UICollectionViewCell + (NSString *)reuseIdentifier; @property (nonatomic, strong) UIImageView *thumbnail; @property (nonatomic, strong) UIButton *degradedButton; @property (nonatomic, assign) BOOL isDegraded; @property (nonatomic, copy) NSString *representedAssetIdentifier; @property (nonatomic, strong) HUImageSelectModel *model; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImageGridCell.m ================================================ // // HUImageGridCell.m // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import "HUImageGridCell.h" #import "Asset.h" #import "UIView+HUConstraint.h" //#import "NSBundle+HUPicker.h" @interface HUImageGridCell () @property (nonatomic, strong) UIButton *checkButton; @end @implementation HUImageGridCell + (NSString *)reuseIdentifier { return @"HUImageGridCell"; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupView]; } return self; } - (void)setModel:(HUImageSelectModel *)model { _model = model; [_checkButton setSelected:model.isSelected]; if (model.isSelected) { NSString *title = [NSString stringWithFormat:@"%zd", model.index]; [_checkButton setTitle:title forState:UIControlStateSelected]; } } - (void)setIsDegraded:(BOOL)isDegraded { _isDegraded = isDegraded; self.degradedButton.hidden = !isDegraded; // NSLog(@"is degraded: %zd", isDegraded); } - (void)setupView { [self.contentView addSubview:self.thumbnail]; [self.contentView addConstraintsWithVisualFormat:@"H:|[v0]|" views:@[self.thumbnail]]; [self.contentView addConstraintsWithVisualFormat:@"V:|[v0]|" views:@[self.thumbnail]]; [self.contentView addSubview:self.checkButton]; [self.contentView addConstraintsWithVisualFormat:@"H:[v0(==22)]-2-|" views:@[self.checkButton]]; [self.contentView addConstraintsWithVisualFormat:@"V:|-2-[v0(==22)]" views:@[self.checkButton]]; [self.contentView addSubview:self.degradedButton]; [self.contentView addConstraintsWithVisualFormat:@"H:|[v0]|" views:@[self.degradedButton]]; [self.contentView addConstraintsWithVisualFormat:@"V:|[v0]|" views:@[self.degradedButton]]; } - (UIImageView *)thumbnail { if (_thumbnail == nil) { _thumbnail = [UIImageView new]; _thumbnail.contentMode = UIViewContentModeScaleAspectFill; _thumbnail.backgroundColor = [UIColor redColor]; _thumbnail.clipsToBounds = YES; } return _thumbnail; } - (UIButton *)checkButton { if (_checkButton == nil) { _checkButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_checkButton setBackgroundImage:UIImageMake(@"photo_button_normal") forState:UIControlStateNormal]; [_checkButton setBackgroundImage:UIImageMake(@"photo_button_selected") forState:UIControlStateSelected]; [_checkButton setTitle:nil forState:UIControlStateNormal]; _checkButton.adjustsImageWhenHighlighted = NO; _checkButton.userInteractionEnabled = NO; [_checkButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; _checkButton.titleLabel.font = [UIFont systemFontOfSize:13]; } return _checkButton; } - (UIButton *)degradedButton { if (_degradedButton == nil) { _degradedButton = [UIButton buttonWithType:UIButtonTypeCustom]; _degradedButton.adjustsImageWhenHighlighted = NO; //_degradedButton.backgroundColor = [UIColor redColor]; _degradedButton.backgroundColor = [UIColor colorWithWhite:1 alpha:0.5]; } return _degradedButton; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImageGridViewController.h ================================================ // // HUImageGridViewController.h // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import #import @interface HUImageGridViewController : UIViewController @property (nonatomic, strong) PHFetchResult *fetchResult; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImageGridViewController.m ================================================ // // HUImageGridViewController.m // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import "HUImageGridViewController.h" #import "HUImageGridCell.h" #import "HUTakePhotoCell.h" #import "HUNavTitleView.h" #import "HUImagePickerViewController.h" #import "HUImageSelectModel.h" #import "HUPHAuthorizationNotDeterminedView.h" #import "HUAlbumTableViewController.h" #import "Asset.h" #import "UIView+HUConstraint.m" #import "UIBarButtonItem+HUButton.h" #import "HUPhotoManager.h" #import "HUToast.h" @interface HUImageGridViewController () { NSInteger _cloumns; CGFloat _spacing; __weak HUAlbumTableViewController *_albumVC; } @property (nonatomic, strong) UICollectionView *collectionView; @property (nonatomic, strong) HUNavTitleView *navTitleView; @property (nonatomic, strong) PHCachingImageManager *cachingImageManager; @property (nonatomic, strong) PHImageRequestOptions *options; @property (nonatomic, assign) CGSize targetSize; @property (nonatomic, strong) NSMutableArray *selectModels; @property (nonatomic, strong) NSMutableArray *selectIndexPaths; @property (nonatomic, strong) NSMutableArray *images; @property (nonatomic, strong) HUPHAuthorizationNotDeterminedView *notDeterminedView; @property (nonatomic, strong) UIView *bgMask; @end @implementation HUImageGridViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.navigationController.interactivePopGestureRecognizer.delegate = self; //self.navigationItem.leftBarButtonItem = [UIBarButtonItem leftItemWithImage:UIImageMake(@"nav_back") target:self action:@selector(back)]; self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(dismiss)]; PHAuthorizationStatus author = [PHPhotoLibrary authorizationStatus]; if (author == PHAuthorizationStatusNotDetermined) { // 无权限 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusAuthorized) { dispatch_async(dispatch_get_main_queue(), ^{ [self setupData]; }); return ; } [self rightBarItemClicked]; }]; return; } [self setupData]; } - (void)dealloc { if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) { [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self]; } } #pragma mark - Collection view data source - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return _fetchResult.count + 1; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.item == 0) { HUTakePhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[HUTakePhotoCell reuseIdentifier] forIndexPath:indexPath]; return cell; } PHAsset *asset = _fetchResult[indexPath.item - 1]; HUImageGridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[HUImageGridCell reuseIdentifier] forIndexPath:indexPath]; cell.representedAssetIdentifier = asset.localIdentifier; cell.model = self.selectModels[indexPath.item-1]; [_cachingImageManager requestImageForAsset:asset targetSize:_targetSize contentMode:PHImageContentModeDefault options:_options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { BOOL isDegraded = [info[PHImageResultIsDegradedKey] boolValue]; if (result && [cell.representedAssetIdentifier isEqualToString: asset.localIdentifier]) { cell.thumbnail.image = result; cell.isDegraded = isDegraded; } }]; return cell; } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.item == 0) { [self takePhoto]; return; } PHAsset *asset = _fetchResult[indexPath.item-1]; if (asset.mediaType != PHAssetMediaTypeImage) { return; } HUImageSelectModel *model = self.selectModels[indexPath.item-1]; HUImagePickerViewController *pickVc = (HUImagePickerViewController *)self.navigationController; if (self.selectIndexPaths.count >= pickVc.maxCount && !model.isSelected) { NSString *title = [NSString stringWithFormat:@"你最多只能选择%zd张照片", pickVc.maxCount]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:nil delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil]; [alert show]; return; } if (!model.isSelected) { [[HUPhotoManager sharedInstance] checkPhotoIsAvaliableWithAsset:asset progress:^(double progress) { } completed:^(BOOL avaliable, UIImage * _Nonnull image) { if (avaliable) { model.isSelected = !model.isSelected; [self.selectIndexPaths addObject:indexPath]; model.index = self.selectIndexPaths.count; model.asset = _fetchResult[indexPath.item-1]; [collectionView reloadItemsAtIndexPaths:@[indexPath]]; [self resetRightBarButton]; } else { [HUToast makeToast:@"iCloud同步中" inView:self.view]; } }]; } else { model.isSelected = !model.isSelected; [self.selectIndexPaths removeObject:indexPath]; model.asset = nil; NSMutableArray *indexPaths = [NSMutableArray array]; [indexPaths addObject:indexPath]; for (HUImageSelectModel *obj in self.selectModels) { if (obj != model && obj.index > model.index) { obj.index -= 1; [indexPaths addObject:obj.indexPath]; } } [collectionView reloadItemsAtIndexPaths:indexPaths]; [self resetRightBarButton]; } // return; // // // HUImagePickerViewController *pickVc = (HUImagePickerViewController *)self.navigationController; // if (self.selectIndexPaths.count >= pickVc.maxCount && !model.isSelected) { // NSString *title = [NSString stringWithFormat:@"你最多只能选择%zd张照片", pickVc.maxCount]; // UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:nil delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil]; // [alert show]; // return; // } // // model.isSelected = !model.isSelected; // // if (model.isSelected) { // [self.selectIndexPaths addObject:indexPath]; // model.index = self.selectIndexPaths.count; // model.asset = _fetchResult[indexPath.item-1]; // [collectionView reloadItemsAtIndexPaths:@[indexPath]]; // } else { // [self.selectIndexPaths removeObject:indexPath]; // model.asset = nil; // NSMutableArray *indexPaths = [NSMutableArray array]; // [indexPaths addObject:indexPath]; // // for (HUImageSelectModel *obj in self.selectModels) { // if (obj != model && obj.index > model.index) { // obj.index -= 1; // [indexPaths addObject:obj.indexPath]; // } // } // // [collectionView reloadItemsAtIndexPaths:indexPaths]; // } // [self.uploadButton setTitle:[NSString stringWithFormat:@"上传(%zd)", self.selectIndexPaths.count] forState:UIControlStateNormal]; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { CGFloat space = _spacing * (_cloumns - 1); CGFloat wh = (self.view.frame.size.width - space) / _cloumns; return CGSizeMake(wh, wh); } #pragma mark - UIImagePickerControllerDelegate - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [picker dismissViewControllerAnimated:YES completion:nil]; } - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { [picker dismissViewControllerAnimated:YES completion:nil]; UIImage *image = info[UIImagePickerControllerOriginalImage]; HUImagePickerViewController *pickVc = (HUImagePickerViewController *)self.navigationController; if ([pickVc.delegate respondsToSelector:@selector(imagePickerViewController:didFinishPickingImageWithImages:assets:)]) { [pickVc.delegate imagePickerViewController:pickVc didFinishPickingImageWithImages:@[image] assets:nil]; } } #pragma mark - PHPhotoLibraryChangeObserver - (void)photoLibraryDidChange:(PHChange *)changeInstance { // dispatch_sync(dispatch_get_main_queue(), ^{ // // PHFetchResultChangeDetails *details = [changeInstance changeDetailsForFetchResult:_fetchResult]; // if (details) { // self.fetchResult = [details fetchResultAfterChanges]; //// [self.collectionView reloadData]; // } // // }); } #pragma mark - Action - (void)rightBarItemClicked { // [SVProgressHUD dismiss]; if (self.selectIndexPaths.count > 0) { [self fetchPhotos]; return; } if ([self.navigationController isKindOfClass:[HUImagePickerViewController class]]) { [self.navigationController dismissViewControllerAnimated:YES completion:nil]; } } - (void)fetchPhotos { NSMutableArray *assets = [NSMutableArray arrayWithCapacity:self.selectIndexPaths.count]; for (HUImageSelectModel *model in self.selectModels) { if (model.isSelected) { [assets addObject:model.asset]; } } if (assets.count == 0) { return; } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self fetchPhotoWithAsset:assets]; }); } - (void)selectPhotoAlbum:(UIButton *)sender { sender.selected = !sender.selected; if (sender.isSelected) { self.bgMask.hidden = NO; _albumVC.view.hidden = NO; [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.bgMask.alpha = 1; _albumVC.view.transform = CGAffineTransformMakeTranslation(0, CGRectGetHeight(self.view.frame)-200+64); } completion:^(BOOL finished) { }]; } else { [self dismissPhotoAlbum]; } } - (void)dismissPhotoAlbum { _navTitleView.selected = NO; [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{ self.bgMask.alpha = 0; _albumVC.view.transform = CGAffineTransformIdentity; } completion:^(BOOL finished) { self.bgMask.hidden = YES; _albumVC.view.hidden = YES; }]; } #pragma mark - Private - (void)fetchPhotoWithAsset:(NSArray *)assets { [[HUPhotoManager sharedInstance] fetchPhotosWithAssets:assets progress:nil completed:^(NSArray * _Nonnull images) { dispatch_async(dispatch_get_main_queue(), ^{ if (![self.navigationController isKindOfClass:[HUImagePickerViewController class]]) { return; } HUImagePickerViewController *pickVc = (HUImagePickerViewController *)self.navigationController; if ([pickVc.delegate respondsToSelector:@selector(imagePickerViewController:didFinishPickingImageWithImages:assets:)]) { [pickVc.delegate imagePickerViewController:pickVc didFinishPickingImageWithImages:images assets:assets]; } }); }]; } - (void)takePhoto { if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { [[[UIAlertView alloc] initWithTitle:@"您的设备不支持相机" message:nil delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil] show]; return; } UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypeCamera; [self presentViewController:picker animated:YES completion:nil]; } - (void)back { [self.navigationController popViewControllerAnimated:YES]; } - (void)dismiss { [self dismissViewControllerAnimated:YES completion:nil]; } - (void)resetRightBarButton { HUImagePickerViewController *pickVc = (HUImagePickerViewController *)self.navigationController; NSString *rightTitle = self.selectIndexPaths.count > 0 ? [NSString stringWithFormat:@"确定(%zd/%zd)", self.selectIndexPaths.count, pickVc.maxCount] : @"确定"; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:rightTitle style:UIBarButtonItemStylePlain target:self action:@selector(rightBarItemClicked)]; self.navigationItem.rightBarButtonItem.enabled = self.selectIndexPaths.count > 0; NSDictionary *attribute = @{NSForegroundColorAttributeName:UIColorMake(48, 144, 255), NSFontAttributeName:[UIFont systemFontOfSize:15]}; [self.navigationItem.rightBarButtonItem setTitleTextAttributes:attribute forState:UIControlStateNormal]; } #pragma mark - UIGestureRecognizerDelegate - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { return YES; } #pragma mark - getter - (void)setupView { self.automaticallyAdjustsScrollViewInsets = NO; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"确定" style:UIBarButtonItemStylePlain target:self action:@selector(rightBarItemClicked)]; self.navigationItem.rightBarButtonItem.enabled = NO; [self.view addSubview:self.collectionView]; [self.view addConstraintsWithVisualFormat:@"H:|[v0]|" views:@[self.collectionView]]; [self.view addConstraintsWithVisualFormat:@"V:|[v0]|" views:@[self.collectionView]]; self.navigationItem.titleView = self.navTitleView; //self.navTitleView.title = @"全部照片"; [self.view addSubview:self.bgMask]; [self.view addConstraintsWithVisualFormat:@"H:|[v0]|" views:@[self.bgMask]]; [self.view addConstraintsWithVisualFormat:@"V:|[v0]|" views:@[self.bgMask]]; CGFloat height = CGRectGetHeight(self.view.frame)-200; HUAlbumTableViewController *albumVC = [[HUAlbumTableViewController alloc] init]; albumVC.didSelectedAlbum = ^(NSString *title, PHFetchResult *fetchResult) { [self dismissPhotoAlbum]; self.navTitleView.title = title; self.fetchResult = fetchResult; }; albumVC.view.frame = CGRectMake(0, -height, CGRectGetWidth(self.view.frame), height); albumVC.view.hidden = YES; [self.view addSubview:albumVC.view]; [self addChildViewController:albumVC]; [albumVC didMoveToParentViewController:self]; _albumVC = albumVC; } - (void)setupData { HUImagePickerViewController *pickVc = (HUImagePickerViewController *)self.navigationController; _cloumns = pickVc.numberOfColumns; _spacing = pickVc.spacing; [[HUPhotoManager sharedInstance] setNetworkAccessAllowed:pickVc.isNetworkAccessAllowed]; [self setupView]; if (_fetchResult == nil) { PHFetchOptions *options = [PHFetchOptions new]; options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]]; self.fetchResult = [PHAsset fetchAssetsWithOptions:options]; } CGFloat space = _spacing * (_cloumns - 1); CGFloat width = ((self.view.frame.size.width - space) / _cloumns) * [UIScreen mainScreen].scale; _targetSize = CGSizeMake(width, width); _cachingImageManager = [[PHCachingImageManager alloc] init]; [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self]; } #pragma mark - getter & setter - (void)setFetchResult:(PHFetchResult *)fetchResult { _fetchResult = fetchResult; [self.selectModels removeAllObjects]; [self.selectIndexPaths removeAllObjects]; [self resetRightBarButton]; for (NSInteger i=0; i *)selectModels { if (_selectModels == nil) { _selectModels = [NSMutableArray array]; } return _selectModels; } - (NSMutableArray *)selectIndexPaths { if (_selectIndexPaths == nil) { _selectIndexPaths = [NSMutableArray array]; } return _selectIndexPaths; } - (NSMutableArray *)images { if (_images == nil) { _images = [NSMutableArray array]; } return _images; } - (HUPHAuthorizationNotDeterminedView *)notDeterminedView { if (_notDeterminedView == nil) { _notDeterminedView = [[HUPHAuthorizationNotDeterminedView alloc] initWithFrame:self.view.bounds]; } return _notDeterminedView; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImagePickerViewController.h ================================================ // // HUImagePickerViewController.h // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import @class HUImagePickerViewController, PHAsset; @protocol HUImagePickerViewControllerDelegate @optional - (void)imagePickerViewController:(nonnull HUImagePickerViewController *)imagePickerViewController didFinishPickingImageWithImages:(nonnull NSArray *)images assets:(nullable NSArray *)assets; - (void)imagePickerViewControllerDidBeginUploadImage:(nonnull HUImagePickerViewController *)imagePickerViewController; @end @interface HUImagePickerViewController : UINavigationController - (instancetype _Nonnull )initWithMaxCount:(NSInteger)maxCount numberOfColumns:(NSInteger)columns; @property (nonatomic, weak, nullable) id delegate; @property (nonatomic, assign) NSInteger maxCount; @property (nonatomic, assign) NSInteger numberOfColumns; @property (nonatomic, assign) CGFloat spacing; /// 是否允许通过网络下载iCloud图片,默认为 NO @property (nonatomic, assign, getter=isNetworkAccessAllowed) BOOL networkAccessAllowed; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImagePickerViewController.m ================================================ // // HUImagePickerViewController.m // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import "HUImagePickerViewController.h" #import "HUAlbumTableViewController.h" #import "HUImageGridViewController.h" #import "HUPHAuthorizationNotDeterminedView.h" #import "HUPHAuthorizationNotDeterminedViewController.h" #import "Asset.h" #import @interface HUImagePickerViewController () @end @implementation HUImagePickerViewController @synthesize delegate = _delegate; - (instancetype)initWithMaxCount:(NSInteger)maxCount numberOfColumns:(NSInteger)columns { UIViewController *rootVc = nil; PHAuthorizationStatus author = [PHPhotoLibrary authorizationStatus]; if (author == PHAuthorizationStatusRestricted || author == PHAuthorizationStatusDenied) { rootVc = [[HUPHAuthorizationNotDeterminedViewController alloc] init]; } else { rootVc = [[HUImageGridViewController alloc] init]; } self = [super initWithRootViewController:rootVc]; if (self) { _maxCount = maxCount; _numberOfColumns = columns; _spacing = 1.5; } return self; } - (instancetype)init { return [self initWithMaxCount:10 numberOfColumns:4]; } - (void)viewDidLoad { [super viewDidLoad]; [[UINavigationBar appearance] setTintColor:UIColorMake(30, 30, 30)]; NSDictionary *titleAttribute = @{NSForegroundColorAttributeName:UIColorMake(30, 30, 30), NSFontAttributeName:[UIFont systemFontOfSize:17]}; [[UINavigationBar appearance] setTitleTextAttributes:titleAttribute]; //设置正常状态 NSDictionary *attribute = @{NSForegroundColorAttributeName:UIColorMake(81, 88, 102), NSFontAttributeName:[UIFont systemFontOfSize:15]}; [[UIBarButtonItem appearance] setTitleTextAttributes:attribute forState:UIControlStateNormal]; //设置不可用状态 NSDictionary *disAttribute = @{NSForegroundColorAttributeName:UIColorMake(209, 209, 209), NSFontAttributeName:[UIFont systemFontOfSize:15]}; [[UIBarButtonItem appearance] setTitleTextAttributes:disAttribute forState:UIControlStateDisabled]; // PHAuthorizationStatus author = [PHPhotoLibrary authorizationStatus]; // if (author == PHAuthorizationStatusNotDetermined || author == PHAuthorizationStatusAuthorized) { // HUAlbumTableViewController *vc = [[HUAlbumTableViewController alloc] init]; // // [self pushViewController:vc animated:true]; // } } - (void)setDelegate:(id)delegate { _delegate = delegate; } - (id)delegate { return _delegate; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImageSelectModel.h ================================================ // // BAImageSelectModel.h // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import @class PHAsset; @interface HUImageSelectModel : NSObject @property (nonatomic, assign) BOOL isSelected; @property (nonatomic, assign) NSInteger index; @property (nonatomic, strong) PHAsset *asset; @property (nonatomic, strong) NSIndexPath *indexPath; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUImageSelectModel.m ================================================ // // BAImageSelectModel.m // beautyAssistant // // Created by jewelz on 2017/6/22. // Copyright © 2017年 Service+. All rights reserved. // #import "HUImageSelectModel.h" @implementation HUImageSelectModel @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUNavTitleView.h ================================================ // // NavTitleView.h // HUPhotoPicker // // Created by jewelz on 2017/9/27. // #import @interface HUNavTitleView : UIButton @property (nonatomic, copy) NSString *title; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUNavTitleView.m ================================================ // // NavTitleView.m // HUPhotoPicker // // Created by jewelz on 2017/9/27. // #import "HUNavTitleView.h" #import "NSBundle+HUPicker.h" @interface HUNavTitleView() @end @implementation HUNavTitleView - (void)setTitle:(NSString *)title { _title = [title copy]; [self setTitle:title forState:UIControlStateNormal]; [self setTitle:title forState:UIControlStateSelected]; [self setTitleEdgeInsets:UIEdgeInsetsMake(0, -self.imageView.image.size.width * 2 - 3, 0, 0)]; CGFloat titleWidth = [title sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}].width + 3; //CGFloat titleWidth = self.titleLabel.bounds.size.width; [self setImageEdgeInsets:UIEdgeInsetsMake(0, titleWidth, 0, -titleWidth)]; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedView.h ================================================ // // BAPHAuthorizationNotDeterminedView.h // beautyAssistant // // Created by jewelz on 2017/7/20. // Copyright © 2017年 Service+. All rights reserved. // #import @interface HUPHAuthorizationNotDeterminedView : UIView @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedView.m ================================================ // // BAPHAuthorizationNotDeterminedView.m // beautyAssistant // // Created by jewelz on 2017/7/20. // Copyright © 2017年 Service+. All rights reserved. // #import "HUPHAuthorizationNotDeterminedView.h" #import "Asset.h" #import "UIView+HUConstraint.h" @interface HUPHAuthorizationNotDeterminedView() @property (nonatomic, strong) UIImageView *imageView; @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *descLabel; @end @implementation HUPHAuthorizationNotDeterminedView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupView]; } return self; } - (void)setupView { [self addSubview:self.imageView]; [self centerXOffset:0 forView:self.imageView]; [self centerYOffset:-30 forView:self.imageView]; [self addSubview:self.titleLabel]; [self addConstraintsWithVisualFormat:@"V:[v0]-30-[v1]" views:@[self.imageView, self.titleLabel]]; [self centerXOffset:0 forView:self.titleLabel]; [self addSubview:self.descLabel]; [self centerXOffset:0 forView:self.descLabel]; [self addConstraintsWithVisualFormat:@"V:[v0]-8-[v1]" views:@[self.titleLabel, self.descLabel]]; } - (UIImageView *)imageView { if (_imageView == nil) { _imageView = [[UIImageView alloc] init]; _imageView.image = UIImageMake(@"Jurisdiction_icon"); } return _imageView; } - (UILabel *)titleLabel { if (_titleLabel == nil) { _titleLabel = [[UILabel alloc] init]; _titleLabel.font = UIFontBoldMake(17); _titleLabel.text = @"此应用没有权限访问您的照片或视频。"; _titleLabel.textColor = UIColorMake(98, 107, 122); } return _titleLabel; } - (UILabel *)descLabel { if (_descLabel == nil) { _descLabel = [[UILabel alloc] init]; _descLabel.font = UIFontMake(15); _descLabel.text = @"您可以在\"隐私设置\"中启用访问。"; _descLabel.textColor = [UIColor lightGrayColor]; } return _descLabel; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedViewController.h ================================================ // // BAPHAuthorizationNotDeterminedViewController.h // beautyAssistant // // Created by jewelz on 2017/7/20. // Copyright © 2017年 Service+. All rights reserved. // #import @interface HUPHAuthorizationNotDeterminedViewController : UIViewController @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedViewController.m ================================================ // // HUPHAuthorizationNotDeterminedViewController.m // beautyAssistant // // Created by jewelz on 2017/7/20. // Copyright © 2017年 Service+. All rights reserved. // #import "HUPHAuthorizationNotDeterminedViewController.h" #import "HUPHAuthorizationNotDeterminedView.h" #import "HUImagePickerViewController.h" @interface HUPHAuthorizationNotDeterminedViewController () @property (nonatomic, strong) HUPHAuthorizationNotDeterminedView *notDeterminedView; @end @implementation HUPHAuthorizationNotDeterminedViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(rightBarItemClicked)]; [self.view addSubview:self.notDeterminedView]; } #pragma mark - Action - (void)rightBarItemClicked { //[SVProgressHUD dismiss]; if ([self.navigationController isKindOfClass:[HUImagePickerViewController class]]) { [self.navigationController dismissViewControllerAnimated:YES completion:nil]; } } - (HUPHAuthorizationNotDeterminedView *)notDeterminedView { if (_notDeterminedView == nil) { _notDeterminedView = [[HUPHAuthorizationNotDeterminedView alloc] initWithFrame:self.view.bounds]; } return _notDeterminedView; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPhotoAlbum.h ================================================ // // HUPhotoAlbum.h // Pods // // Created by jewelz on 2017/9/15. // // #import @class PHAssetCollection; @interface HUPhotoAlbum : NSObject @property (nonatomic, copy) NSString *title; @property (nonatomic, assign) NSUInteger assetCount; @property (nonatomic, strong) PHAssetCollection *collection; + (instancetype)photoAlbumWithAssetCollection:(PHAssetCollection *)collection assetCount:(NSUInteger)count; - (instancetype)initWithAssetCollection:(PHAssetCollection *)collection assetCount:(NSUInteger)count; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPhotoAlbum.m ================================================ // // HUPhotoAlbum.m // Pods // // Created by jewelz on 2017/9/15. // // #import "HUPhotoAlbum.h" #import @implementation HUPhotoAlbum + (instancetype)photoAlbumWithAssetCollection:(PHAssetCollection *)collection assetCount:(NSUInteger)count { return [[self alloc] initWithAssetCollection:collection assetCount:count]; } - (instancetype)initWithAssetCollection:(PHAssetCollection *)collection assetCount:(NSUInteger)count { self = [super init]; if (self) { self.title = collection.localizedTitle; self.collection = collection; self.assetCount = count; } return self; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPhotoManager.h ================================================ // // HUPhotoHelper.h // Pods // // Created by jewelz on 2017/7/29. // // #import @class PHAsset; @interface HUPhotoManager : NSObject @property (nonatomic, assign, getter=isNetworkAccessAllowed) BOOL networkAccessAllowed; + (nonnull instancetype)sharedInstance; - (void)fetchPhotoWithAsset:(nonnull PHAsset *)asset progress:(nullable void(^)(double progress))progress completed:(nullable void(^)(BOOL success, UIImage * _Nonnull image))completed; - (void)fetchPhotosWithAssets:(nonnull NSArray *)assets progress:(nullable void(^)(double progress))progress completed:(nullable void(^)(NSArray * _Nonnull images))completed; - (void)cancelPhotoRequest; - (void)checkPhotoIsAvaliableWithAsset:(nonnull PHAsset *)asset progress:(nullable void(^)(double progress))progress completed:(nullable void(^)(BOOL avaliable, UIImage * _Nonnull image))completed; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPhotoManager.m ================================================ // // HUPhotoHelper.m // Pods // // Created by jewelz on 2017/7/29. // // #import "HUPhotoManager.h" #import @interface HUPhotoManager() @property (nonatomic, copy) NSMutableDictionary *imageCache; @property (nonatomic, copy) NSMutableDictionary * imageRequestIDs; @property (nonatomic, strong) PHImageRequestOptions *requestOptions; @end @implementation HUPhotoManager + (instancetype)sharedInstance { static HUPhotoManager *shared = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ shared = [[HUPhotoManager alloc] init]; }); return shared; } - (instancetype)init { if (self == [super init]) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearCache) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)fetchPhotosWithAssets:(nonnull NSArray *)assets progress:(nullable void(^)(double progress))progress completed:(nullable void(^)(NSArray * _Nonnull images))completed { __block NSMutableArray *downloadeds = [NSMutableArray array]; NSMutableArray *shouldDownlds = [NSMutableArray array]; for (PHAsset *asset in assets) { UIImage *cachedImage = [self.imageCache objectForKey:asset.localIdentifier]; if (cachedImage) { [downloadeds addObject:cachedImage]; } else { [shouldDownlds addObject:asset]; } } if (downloadeds.count >= assets.count) { if (progress) { progress(1); } if (completed) { completed(downloadeds); } return; } double count = shouldDownlds.count; for (PHAsset *asset in shouldDownlds) { [self fetchPhotoWithAsset:asset progress:^(double _progress) { if (progress) { dispatch_async(dispatch_get_main_queue(), ^{ progress(_progress / count); }); } } completed:^(BOOL success, UIImage * _Nullable image) { [downloadeds addObject:image]; if (downloadeds.count >= assets.count) { if (progress) { dispatch_async(dispatch_get_main_queue(), ^{ progress(1); }); } if (completed) { dispatch_async(dispatch_get_main_queue(), ^{ completed(downloadeds); }); } } }]; } } - (void)fetchPhotoWithAsset:(nonnull PHAsset *)asset progress:(nullable void(^)(double progress))progress completed:(nullable void(^)(BOOL avaliable, UIImage * _Nonnull image))completed { UIImage *cachedImage = [self.imageCache objectForKey:asset.localIdentifier]; if (cachedImage) { if (progress) { progress(1); } if (completed) { completed(YES, cachedImage); } return; } [self.requestOptions setProgressHandler: ^(double _progress, NSError *__nullable error, BOOL *stop, NSDictionary *__nullable info) { dispatch_async(dispatch_get_main_queue(), ^{ if (progress) { progress(_progress); } }); }]; PHImageRequestID requestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:self.requestOptions resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { if (result) { [self.imageCache setObject:result forKey:asset.localIdentifier]; } BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]; BOOL isInCloudKey = [[info objectForKey:PHImageResultIsInCloudKey] boolValue]; // 从iCloud下载图片 if (result && downloadFinined) { dispatch_async(dispatch_get_main_queue(), ^{ if (completed) { completed(YES, result); } }); } else if (isInCloudKey && !result) { UIImage *image = [self.imageCache objectForKey:asset.localIdentifier]; if (image) { dispatch_async(dispatch_get_main_queue(), ^{ if (completed) { completed(YES, image); } }); } } }]; [self.imageRequestIDs setObject:@(requestID) forKey:asset.localIdentifier]; } - (void)checkPhotoIsAvaliableWithAsset:(nonnull PHAsset *)asset progress:(nullable void(^)(double progress))progress completed:(nullable void(^)(BOOL avaliable, UIImage * _Nonnull image))completed { UIImage *cachedImage = [self.imageCache objectForKey:asset.localIdentifier]; if (cachedImage) { if (progress) { progress(1); } if (completed) { completed(YES, cachedImage); } return; } PHImageRequestOptions *options = [PHImageRequestOptions new]; [options setNetworkAccessAllowed:NO]; [options setSynchronous:YES]; [options setProgressHandler: ^(double _progress, NSError *__nullable error, BOOL *stop, NSDictionary *__nullable info) { dispatch_async(dispatch_get_main_queue(), ^{ if (progress) { progress(_progress); } }); }]; PHImageRequestID requestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { if (result) { [self.imageCache setObject:result forKey:asset.localIdentifier]; dispatch_async(dispatch_get_main_queue(), ^{ if (completed) { completed(YES, result); } }); } else { if (self.isNetworkAccessAllowed) { [self fetchPhotoWithAsset:asset progress:nil completed:nil]; } dispatch_async(dispatch_get_main_queue(), ^{ if (completed) { completed(NO, result); } }); } }]; [self.imageRequestIDs setObject:@(requestID) forKey:asset.localIdentifier]; } - (void)cancelPhotoRequest { for (NSNumber *obj in self.imageRequestIDs) { [[PHImageManager defaultManager] cancelImageRequest:obj.intValue]; } } - (BOOL)isPhotoDownloaded:(PHAsset *)asset { return true; } - (void)cancelPhotoRequestWithAsset:(PHAsset *)asset { NSNumber *idNumber = [self.imageRequestIDs objectForKey:asset.localIdentifier]; if (!idNumber) { return; } [[PHImageManager defaultManager] cancelImageRequest:idNumber.intValue]; } - (void)clearCache { [self.imageCache removeAllObjects]; [self.imageRequestIDs removeAllObjects]; } #pragma mark - getter - (NSMutableDictionary *)imageCache { if (_imageCache == nil) { _imageCache = [NSMutableDictionary dictionary]; } return _imageCache; } - (NSMutableDictionary *)imageRequestIDs { if (_imageRequestIDs == nil) { _imageRequestIDs = [NSMutableDictionary dictionary]; } return _imageRequestIDs; } - (PHImageRequestOptions *)requestOptions { if (_requestOptions == nil) { _requestOptions = [PHImageRequestOptions new]; [_requestOptions setNetworkAccessAllowed:YES]; } return _requestOptions; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUPhotoPicker.h ================================================ // // HUPhotoPicker.h // Pods // // Created by jewelz on 2017/7/28. // // #ifndef HUPhotoPicker_h #define HUPhotoPicker_h #import #import "HUImagePickerViewController.h" #endif /* HUPhotoPicker_h */ ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUTakePhotoCell.h ================================================ // // HUTakePhotoCell.h // Pods // // Created by jewelz on 2017/9/15. // // #import @interface HUTakePhotoCell : UICollectionViewCell + (NSString *)reuseIdentifier; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUTakePhotoCell.m ================================================ // // HUTakePhotoCell.m // Pods // // Created by jewelz on 2017/9/15. // // #import "HUTakePhotoCell.h" #import "UIView+HUConstraint.h" #import "Asset.h" @implementation HUTakePhotoCell - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupView]; } return self; } - (void)setupView { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.backgroundColor = [UIColor whiteColor]; [button setImage:UIImageMake(@"album_photograph_icon") forState:UIControlStateNormal]; button.userInteractionEnabled = NO; [self.contentView addSubview:button]; [self.contentView addConstraintsWithVisualFormat:@"H:|[v0]|" views:@[button]]; [self.contentView addConstraintsWithVisualFormat:@"V:|[v0]|" views:@[button]]; } + (NSString *)reuseIdentifier { return @"HUTakePhotoCell"; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUToast.h ================================================ // // Toast.h // Pods // // Created by jewelz on 2017/9/16. // // #import @interface HUToast : UIView + (void)makeToast:(NSString *)message inView:(UIView *)view; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/HUToast.m ================================================ // // Toast.m // Pods // // Created by jewelz on 2017/9/16. // // #import "HUToast.h" #import "UIView+HUConstraint.h" @interface HUToast () @property (nonatomic, strong) UILabel *messageLabel; @end @implementation HUToast + (instancetype)sharedInstance { static HUToast *toast = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ toast = [[self alloc] init]; }); return toast; } + (void)makeToast:(NSString *)message inView:(UIView *)view { [[HUToast sharedInstance] makeToast:message inView:view]; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:CGRectMake(0, 0, 160, 100)]; if (self) { [self setupView]; } return self; } - (void)layoutSubviews { [super layoutSubviews]; self.messageLabel.frame = self.bounds; } - (void)makeToast:(NSString *)message inView:(UIView *)view { if ([view.subviews containsObject:self]) { return; } self.alpha = 0; self.messageLabel.text = message; self.center = CGPointMake(view.frame.size.width/2, view.frame.size.height/2); [view addSubview:self]; [UIView animateWithDuration:0.25 animations:^{ self.alpha = 1; } completion:^(BOOL finished) { NSTimer *timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(hide:) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; }]; } - (void)hide:(NSTimer *)timer { [UIView animateWithDuration:0.25 animations:^{ self.alpha = 0; } completion:^(BOOL finished) { [self removeFromSuperview]; [timer invalidate]; }]; } - (void)setupView { self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.75]; self.layer.cornerRadius = 6; self.layer.masksToBounds = YES; [self addSubview:self.messageLabel]; } - (UILabel *)messageLabel { if (_messageLabel == nil) { _messageLabel = [[UILabel alloc] init]; _messageLabel.textColor = [UIColor whiteColor]; _messageLabel.font = [UIFont systemFontOfSize:15]; _messageLabel.numberOfLines = 0; _messageLabel.textAlignment = NSTextAlignmentCenter; } return _messageLabel; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/NSBundle+HUPicker.h ================================================ // // NSBundle+HUPicker.h // Pods // // Created by jewelz on 2017/7/28. // // #import @interface NSBundle (HUPicker) + (instancetype)hu_bundle; + (UIImage *)hu_imageNamed:(NSString *)name; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/NSBundle+HUPicker.m ================================================ // // NSBundle+HUPicker.m // Pods // // Created by jewelz on 2017/7/28. // // #import "NSBundle+HUPicker.h" #import "HUImagePickerViewController.h" @implementation NSBundle (HUPicker) + (instancetype)hu_bundle { static NSBundle *bundle = nil; if (bundle == nil) { NSBundle *podBundle = [NSBundle bundleForClass:[HUImagePickerViewController class]]; bundle = [NSBundle bundleWithPath:[podBundle pathForResource:@"HUPhotoPicker" ofType:@"bundle"]]; } return bundle; } + (UIImage *)hu_imageNamed:(NSString *)name { return [UIImage imageNamed:name inBundle:[self hu_bundle] compatibleWithTraitCollection:nil]; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/UIBarButtonItem+HUButton.h ================================================ // // UIBarButtonItem+HUButton.h // Pods // // Created by jewelz on 2017/7/29. // // #import @interface UIBarButtonItem (HUButton) + (instancetype)leftItemWithImage:(UIImage *)image target:(id)target action:(SEL)action; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/UIBarButtonItem+HUButton.m ================================================ // // UIBarButtonItem+HUButton.m // Pods // // Created by jewelz on 2017/7/29. // // #import "UIBarButtonItem+HUButton.h" @implementation UIBarButtonItem (HUButton) + (instancetype)leftItemWithImage:(UIImage *)image target:(id)target action:(SEL)action { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(0, 0, 60, 44); button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; [button setImage:image forState:UIControlStateNormal]; [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; return [[UIBarButtonItem alloc] initWithCustomView:button]; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/UIView+HUConstraint.h ================================================ // // UIView+Constraint.h // HUPhotoPicker // // Created by jewelz on 2017/7/28. // #import @interface UIView (HUConstraint) - (void)addConstraintsWithVisualFormat:(nonnull NSString *)formate views:(nonnull NSArray *)views; - (void)centerView:(nonnull UIView *)view; - (void)centerXOffset:(CGFloat)offsetX forView:(nonnull UIView *)view; - (void)centerYOffset:(CGFloat)offsetY forView:(nonnull UIView *)view; @end ================================================ FILE: Example/Pods/HUPhotoPicker/HUPhotoPicker/Classes/UIView+HUConstraint.m ================================================ // // UIView+Constraint.m // HUPhotoPicker // // Created by jewelz on 2017/7/28. // #import "UIView+HUConstraint.h" @implementation UIView (HUConstraint) - (void)addConstraintsWithVisualFormat:(nonnull NSString *)formate views:(nonnull NSArray *)views { if (views.count == 0) { return; } NSMutableDictionary *dict = [NSMutableDictionary dictionary]; __block NSString *key = @""; [views enumerateObjectsUsingBlock:^(UIView * _Nonnull view, NSUInteger idx, BOOL * _Nonnull stop) { view.translatesAutoresizingMaskIntoConstraints = NO; key = [NSString stringWithFormat:@"v%zd", idx]; [dict setObject:view forKey:key]; }]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:formate options:0 metrics:nil views:dict]]; } - (void)centerView:(nonnull UIView *)view { [self centerXOffset:0 forView:view]; [self centerYOffset:0 forView:view]; } - (void)centerXOffset:(CGFloat)offsetX forView:(nonnull UIView *)view { view.translatesAutoresizingMaskIntoConstraints = NO; [self addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:offsetX]]; } - (void)centerYOffset:(CGFloat)offsetY forView:(nonnull UIView *)view { [self addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:offsetY]]; } @end ================================================ FILE: Example/Pods/HUPhotoPicker/LICENSE ================================================ MIT License Copyright (c) 2017 Jewelz Hu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Example/Pods/HUPhotoPicker/README.md ================================================ # HUPhotoPicker [![CI Status](http://img.shields.io/travis/hujewelz/HUPhotoPicker.svg?style=flat)](https://travis-ci.org/hujewelz/HUPhotoPicker) [![Version](https://img.shields.io/cocoapods/v/HUPhotoPicker.svg?style=flat)](http://cocoapods.org/pods/HUPhotoPicker) [![License](https://img.shields.io/cocoapods/l/HUPhotoPicker.svg?style=flat)](http://cocoapods.org/pods/HUPhotoPicker) [![Platform](https://img.shields.io/cocoapods/p/HUPhotoPicker.svg?style=flat)](http://cocoapods.org/pods/HUPhotoPicker) ## Example To run the example project, clone the repo, and run `pod install` from the Example directory first. ## Requirements ## Installation HUPhotoPicker is available through [CocoaPods](http://cocoapods.org). To install it, simply add the following line to your Podfile: ```ruby pod "HUPhotoPicker" ``` ## Author Jewelz Hu, hujewelz@163.com ## License HUPhotoPicker is available under the MIT license. See the LICENSE file for more info. ================================================ FILE: Example/Pods/Local Podspecs/HUPhotoBrowser.podspec.json ================================================ { "name": "HUPhotoBrowser", "version": "1.3.0", "summary": "photo browser for ios, which can browse Photo library and web image", "homepage": "https://github.com/hujewelz/HUPhotoBrowser", "license": "MIT", "authors": { "Jewelz Hu": "https://github.com/hujewelz/HUPhotoBrowser" }, "platforms": { "ios": "7.0" }, "source": { "git": "https://github.com/hujewelz/HUPhotoBrowser.git", "tag": "1.3.0" }, "source_files": "HUPhotoBrowser/**/*.{h,m}", "requires_arc": true, "frameworks": [ "UIKit", "Photos", "AssetsLibrary" ], "public_header_files": [ "HUPhotoBrowser/HUPhotoBrowser.h", "HUPhotoBrowser/HUPhotoPicker/HUImagePickerViewController.h", "HUPhotoBrowser/HUWebImageDownloader/{UIImageView+HUWebImage,HUWebImageDownloader}.h" ], "dependencies": { "SVProgressHUD": [ ] } } ================================================ FILE: Example/Pods/Pods.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 02735D8436E3DB9E7EA79694C58BE6F4 /* UIImage+HUExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AE18F7ECC383B6860F958FFE3E22296 /* UIImage+HUExtension.m */; }; 053D329FAA96B749E2FD97CB6D096A85 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 00C800A6F02590F678225961616F0E14 /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0615F5F2ABF3C6D02B66F471EAEE37BA /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 441D9E0D8C2033CBCB8EBD66CB4EDC11 /* SDWebImageManager.m */; }; 0801E52B09E882BB1E2441347E566214 /* SVRadialGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = EBB4E8043E0015F89FDA55D0CA569CC4 /* SVRadialGradientLayer.m */; }; 086F8C085ABB04F9C8C5C422DFDF1412 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 545C51AB7AB0CB14DF4ECCA613BAFEA5 /* SDWebImageCompat.m */; }; 0A4BFCC90ABBFF825C70EFE9F9B7CD34 /* HUTakePhotoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D9EB29BC0DA93559B0D44D7C78426356 /* HUTakePhotoCell.m */; }; 0B674BD1EC01B2F2E5B86BC361C2032B /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A68BB2127299F79461E6F6B3AB52869 /* UIImage+MultiFormat.m */; }; 0CE6A5C6B62A9FD71E66BD0B202273A4 /* SVProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C51BE05478A10C56BD6FF53686494E7 /* SVProgressHUD.m */; }; 1241C92252F5500B6FA1782A66AF6432 /* HUPhotoBrowser-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A524D07B783D67E8F7BC7A33A47770AE /* HUPhotoBrowser-dummy.m */; }; 12B9BC6E6EC8792296CED4F0C56ED6E2 /* nav_back@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B6C41B0E78CD3F337D9DA8131A22914 /* nav_back@3x.png */; }; 13944C33461BCA0868BC17FC8D7E6252 /* NSImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 21F56FEF368B49D93D7E4F418AAE8296 /* NSImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 152BF7BE0AA241A5C6BE4F608CA9E6A0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */; }; 154E25C8A639BD2855EF6ED1CE1311D0 /* HUAlbumTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D9DC81E5EBE3E1913E938646E03C2E9 /* HUAlbumTableViewController.h */; settings = {ATTRIBUTES = (Project, ); }; }; 1B055DEC5A93B3430137EDFD63E1A62E /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F8305A2C6089188628736DDD2F370A /* ImageIO.framework */; }; 1C531B0E4A281E5F1CCFD426B5C59F50 /* HUWebImageDownloadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 91040B2B94B6447A1D4D9387C627B02A /* HUWebImageDownloadOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; 1D14675094EB2982854BBDE56D642F7F /* album_close_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3A7B323C6C7AA5954DD661A569FA77CD /* album_close_icon@2x.png */; }; 1DA19173FBBEE7D11EBFD489D002ECB3 /* HUPhotoAlbum.m in Sources */ = {isa = PBXBuildFile; fileRef = F527FE5669CA594E88CADC793838CDAF /* HUPhotoAlbum.m */; }; 1E766D1CE8821B1AA0F0BA3769BD750E /* HUImageGridViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AFDEF6B3F68ABAD646B955014670B32D /* HUImageGridViewController.m */; }; 1E868873A8CF56F277977C0F28D6D54D /* HUImageSelectModel.m in Sources */ = {isa = PBXBuildFile; fileRef = D2A1832C622E09402E5443E39EEB7C17 /* HUImageSelectModel.m */; }; 24AC460FDE1C0610A111CCF67FC835D8 /* image_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C137D78D8E705BFC3E79578F84BA3413 /* image_selected@2x.png */; }; 29CD90FDAAB316F204CEEAFB5564A5A7 /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B2BFA65B10054FC241F1C3ABB96E68B /* SDWebImageDownloader.m */; }; 2AC999D34D8A6DEECCC2D91261A67865 /* SVIndefiniteAnimatedView.h in Headers */ = {isa = PBXBuildFile; fileRef = 7787CCB41A739DF35AC7AF65005F5384 /* SVIndefiniteAnimatedView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2BD3489F5F1D3B0D47C57D3506A372F8 /* HUImageGridCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 13320B73B1EEDEC7054B6BA67D32D4EB /* HUImageGridCell.m */; }; 2C61EAC4DA7890F245FBD68AE417C4CA /* image_selected@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D68944CA5223A84064F95C057951163C /* image_selected@3x.png */; }; 2FFFCBCE6865FEDD745574FD47A69FD6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */; }; 35C11FA48B4F1C25AEC21C72FFDF51B5 /* nav_back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C3D0023A3AA419520B006770CC4B9FD4 /* nav_back@2x.png */; }; 35D8BA8171A586B59D48614BCBC18DDA /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = AF0D9B0557E593C2184912CC905AA5E1 /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 36081993A921C1EECB74335B1EE0F34C /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = F48C3A3A0784AB826CDC951A03656357 /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 384A9AAA97DAB3A480C1DD84170AD1A8 /* NSImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 919847A9F94E2FACD0E3E3CB08A71F90 /* NSImage+WebCache.m */; }; 3A7A90BB67EA1197192AC12C57CB9585 /* Jurisdiction_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0C2818BB53593BDAB01B9BE25C54FB07 /* Jurisdiction_icon@3x.png */; }; 3D9390CD8F716E217F034C87639ABBAD /* HUToast.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF559DE20B55C84DA7DE88F2DC3674F /* HUToast.m */; }; 3E845D3F5BC22756CFE33576ECF38EDF /* SVProgressAnimatedView.h in Headers */ = {isa = PBXBuildFile; fileRef = 865ECDF17E5F581EC036DA88C8EA5EC6 /* SVProgressAnimatedView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 400FEBC5B5E78F7BC76B9FB21DC02912 /* album_photograph_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 73B08799CBB6E6C520DFDC31692B4B3A /* album_photograph_icon@3x.png */; }; 41E3EC52537EB6280D7DE2DFEB19F369 /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 61CE96D2977D382BDBEF6EB6C360CAA5 /* SDImageCacheConfig.m */; }; 441F9F02296486E9F50BB59E0105966E /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 804666883EC6B1A30EE2C0C21974EA4E /* Photos.framework */; }; 44315C1D5AA06EC4516CC016F4505054 /* UIView+HUConstraint.m in Sources */ = {isa = PBXBuildFile; fileRef = F0DACE5743EF9203F95EDC4F0FF77FC3 /* UIView+HUConstraint.m */; }; 4B8779A43D1E81C6FFE4593B5F8D6288 /* NSBundle+HUPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = FB68DA04853D2044F150D9165DD4AD40 /* NSBundle+HUPicker.h */; settings = {ATTRIBUTES = (Project, ); }; }; 4DAB2E3EAFE5D4EF3806D2A76036F4FF /* photo_button_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 703F045B6E13F9E59046173B939701EC /* photo_button_selected@2x.png */; }; 527E140533AFB0472E5D59561053EDD2 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = DE8F32142A47511484566FE4535744C4 /* UIButton+WebCache.m */; }; 53A14922CA39A52C1926D0246C2BB1F0 /* HUAlbumCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E14F497E11E651AC49123BA06F5ED79 /* HUAlbumCell.h */; settings = {ATTRIBUTES = (Project, ); }; }; 580058559154D3B6A975DDAE7EFBA3C5 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0687350693844A2E9E522786088D90F3 /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 598BA4AEFD2B722B093B57F23D516DF1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */; }; 5A90BA62A73A14336AE2A28E5D320B0A /* HUImagePickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D6B30683558D738F4DE543582F7189B1 /* HUImagePickerViewController.m */; }; 5BA328FA29936FC6602FA2AC66CA7023 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */; }; 5D4A489B188F4BCA1B89DE0F17BB8FA7 /* HUWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = BBCE812D3697587EE47CA1B5C2F315CC /* HUWebImageDownloader.m */; }; 5DCEE92ACF66523B2A394A8FCD937EA5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE05B0A93E7AC961E35AFD6B72A43F53 /* UIKit.framework */; }; 605A413ED7A7834E43679FB47E2C1110 /* HUPhotoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DA652A6053BD21B7B631581A9AE77F8 /* HUPhotoManager.m */; }; 6169115EC8E6EFE24CFCEF5D1E02D736 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = F475A7C707C8FB377AC19C870CEAFFF2 /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 62E71CA9C06816E2FB7E729AF2283634 /* HUNavTitleView.h in Headers */ = {isa = PBXBuildFile; fileRef = A2D3BF58C096E8B3557DBD41DD70D03B /* HUNavTitleView.h */; settings = {ATTRIBUTES = (Project, ); }; }; 641BF2B026B2E09570949CEAAA1CEC79 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F0FBC46E4BB9737994EE2E35E6E07A4 /* SDWebImagePrefetcher.m */; }; 65B63AB881AA74C306596717363C5E0F /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 20FB595B908B4DA42B12C10B3B74A2FA /* UIImageView+WebCache.m */; }; 65CEECC1600B3EB655A0EB242D354A88 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */; }; 66025EBA8B6D98C392958C8520F6D7E5 /* HUPHAuthorizationNotDeterminedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C6EAE39BE0B78BD51FA0C8578DFC6215 /* HUPHAuthorizationNotDeterminedViewController.m */; }; 66DECE27B5EF416042C9FF26AD43EF00 /* HUToast.h in Headers */ = {isa = PBXBuildFile; fileRef = 9103C49F8D840C91E18ED85756AB0BBB /* HUToast.h */; settings = {ATTRIBUTES = (Project, ); }; }; 671D941A03C1E763513AAA4857DC51BD /* HUImageGridCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 69AED5B69BC460F980416E86560D5348 /* HUImageGridCell.h */; settings = {ATTRIBUTES = (Project, ); }; }; 694DC69113D8FC517034EC5FBC00950A /* HUImagePickerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E8491134C958BC38C9F082D5CE0C36B /* HUImagePickerViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6A2EE1939C21B95571A77B65094E505D /* album_close_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C86AB20D8D71D526A8202973E9A1F545 /* album_close_icon@3x.png */; }; 74302A6E58181E6596A1BB389365F43F /* HUAlbumTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C61601A866B0B6F3B1CC15879939A46 /* HUAlbumTableViewController.m */; }; 746F598854C3DB3E9DB0D0726148FD94 /* hu_const.h in Headers */ = {isa = PBXBuildFile; fileRef = F157F1452E6D4EAE236DA49C7C0E894B /* hu_const.h */; settings = {ATTRIBUTES = (Project, ); }; }; 768C9F5C502E68F2914072040FFA71E1 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = D4E456D947C1E3759C029BA645213B74 /* NSData+ImageContentType.m */; }; 78DBC6F454ABC5112579DF6275C4461A /* Jurisdiction_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C68E7235956D835ADFBE6514D8E96EFA /* Jurisdiction_icon@2x.png */; }; 79996630838668D04EA3BFB57560995E /* HUImageSelectModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CE6CBF80A2939FE6F1C7C149A1C1F4A /* HUImageSelectModel.h */; settings = {ATTRIBUTES = (Project, ); }; }; 7C3459B05690C13218F9F23C827FE21A /* UIView+frame.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FBCA5CAA0922972DB941FA957456C36 /* UIView+frame.m */; }; 7E071687325BF5B296A25A75974490C3 /* SVProgressHUD-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B72FB7B35A719AFAD18FAA1C4F6EDAC /* SVProgressHUD-dummy.m */; }; 7E813E032E1B31658FCF923F78B479B5 /* HUPHAuthorizationNotDeterminedView.h in Headers */ = {isa = PBXBuildFile; fileRef = 02090B8A152D8EA57D43A1D41FC3FAE1 /* HUPHAuthorizationNotDeterminedView.h */; settings = {ATTRIBUTES = (Project, ); }; }; 814F5D3D6EE077DCD1A25EDF6DB63CAA /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C796604D26CF43514817953954C5AF9 /* UIView+WebCache.m */; }; 822C18350931407D1EE15B2BB719E3F3 /* HUPhotoAlbum.h in Headers */ = {isa = PBXBuildFile; fileRef = 10F59DBE0AF6AAF69E10F159B417661A /* HUPhotoAlbum.h */; settings = {ATTRIBUTES = (Project, ); }; }; 8392C6FF89FEE6B0FB3042AA0925313D /* HUPhotoPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = D49449D610A39E04D4C2A121F5E4FD32 /* HUPhotoPicker.h */; settings = {ATTRIBUTES = (Public, ); }; }; 83C575C5E394FD4869BEAE2FE3FD5B02 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = F69008F697735A74BE8C45DDAEF29A41 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 841A407A7C5DC32F91DA0EB3D8014C2E /* SVProgressAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BFA6105989E1129CE256E52520269E1 /* SVProgressAnimatedView.m */; }; 86FB723DD88559EC1E288B9FA5B7EE4A /* HUPhotoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 13B5E72269741E51831AA307A834D172 /* HUPhotoManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 873C75AB9B12A76E90DAF9EAB44A991C /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4F9ECEA64607144F85BC468769B68C2 /* QuartzCore.framework */; }; 8A96738F5A80EDF3797B7716F8F12E63 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */; }; 8B6C609B4E035A892066DC53BBFB119E /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F5F8ED6AD15C8E85169BF85D772348 /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8BAB9550CAA0B5A7EA5F2F828130E136 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 45587FF486C1EEDF876807B8E8CC935E /* SDWebImageDownloaderOperation.m */; }; 8CFB4E2A821C8946F972B52F14E1EAB3 /* HUPHAuthorizationNotDeterminedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 56232916A8D191E1DEB3601409A09124 /* HUPHAuthorizationNotDeterminedView.m */; }; 8DC69158558D4AB7EE00575DA0CDD675 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9BF87558582615F2810E72AC339206 /* UIImageView+HighlightedWebCache.m */; }; 8E653B2F5B6D7E3A285833A5888AC3D6 /* HUAlbumCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51C9CC5C6680C06B24AEC9DF433CC87C /* HUAlbumCell.xib */; }; 909372963DBA08C68992835EB86061EA /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = D958A56255E71ADC24D80C094DAC1A7A /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; 91AB44B5B7DB95A7BA5B5B5D3DAF775D /* Asset.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A7056DF7B1C83091325D3DF07123CB6 /* Asset.h */; settings = {ATTRIBUTES = (Project, ); }; }; 91D498E3B268ECC94289A8EBE57FDB14 /* HUPhotoBrowserCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B6A27FBC85A69196B8297F1235D2027 /* HUPhotoBrowserCell.h */; settings = {ATTRIBUTES = (Project, ); }; }; 935F70349715265D86E8FD0597447AC5 /* SDWebImageDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 5440CAABC38EE84F75266A36CB50E346 /* SDWebImageDecoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 93E2D3CD516D98158E5D06EAD5EF4868 /* album_open_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A4D56D45B44D3173C51062AD8CE60193 /* album_open_icon@2x.png */; }; 97EB8C5178E22A872B36A788152AA571 /* SVProgressHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = 753A0AD8EE029D65DDC636A68F7A5D56 /* SVProgressHUD.h */; settings = {ATTRIBUTES = (Public, ); }; }; 98C136139F278CFA1281924A853F23F0 /* HUPhotoBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = F7A0250C4B3D552BA4CADE666439B13D /* HUPhotoBrowser.m */; }; 99B738B37205FF969C2BDB51627CD71A /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 08214ABFFF911AC79EAD4722979DDB29 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9BC35B29E439FAC7E11246F5898D0BD1 /* SDWebImage-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F057D640CB9E60D7D53423DD283C9A4B /* SDWebImage-dummy.m */; }; 9BDE24BE44A77B9E0CB09814CE3941E3 /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 286D66F5AAD3686AC8D9AB22677CBCE9 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9EA3B8E135E065F0914BEB70EDFE6775 /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 19064ABD4D32F1FA7743601441F135D1 /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; A0CC6C2D247E55AE7E6E4CE552C7B270 /* photo_button_normal@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = BDADDF678F3ECC6FEB0547730DB2AF2D /* photo_button_normal@3x.png */; }; A0DB532409564F8DF18924EA2CBB0929 /* SDWebImageDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E825E9268F7A21ED4A10CACA6DAC8C9 /* SDWebImageDecoder.m */; }; A2B42E2B533938834E83B3957FA83837 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F66A76856B26ADEC9C3296F0FE0B5A /* AssetsLibrary.framework */; }; A3E65E80FAA621CA37687E721E440540 /* album_photograph_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C28CA3BBDBA583094087A2890A7C7FE0 /* album_photograph_icon@2x.png */; }; A3F0B52FC22E648C3D8783934613B1BA /* photo_button_normal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6BCF7F14A2A289DFB89DA8D608C1796 /* photo_button_normal@2x.png */; }; A5D6462FB49CAFF292C5EDE70BD65784 /* Pods-HUPhotoBrowser Demo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A39260F4921A34460754C96BF086B62 /* Pods-HUPhotoBrowser Demo-dummy.m */; }; A60F3472AD558A5C66E269AD32F0A160 /* HUAlbumCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BAD901633A161CB4C35C1A9466869C3 /* HUAlbumCell.m */; }; A63D39295D405569DCE488454011DBAB /* HUTakePhotoCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1277B0BF2774C41E61B74F8F3F084D87 /* HUTakePhotoCell.h */; settings = {ATTRIBUTES = (Project, ); }; }; A7DB2E7B837586BE06497232D65B3BA8 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DCC6D86420229BFAB1F056871A12607 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; AA2B867A047A62006345CABCFC932C81 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F476C600975412D143CA6797F9B48AF /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; B45672895B70B90CBB854A69850A112F /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C6DFDC2D8A016511F4AED26F3544CF6 /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; B68A1F5A13355D589240D8E774D7F10D /* UIImageView+HUWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = C843E13541704A189B1DAD2DBC088F04 /* UIImageView+HUWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; BBAEBB6AF61E7D4AD565BBF9FF8A16DB /* HUPhotoPicker-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCCDDCFD3DA396C62681DC281319765 /* HUPhotoPicker-dummy.m */; }; BC0BFD421A71955FE7C83DC3EAC0BBCB /* HUWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 293ACC9890E0C871FC279737AA8EF8D3 /* HUWebImage.h */; settings = {ATTRIBUTES = (Project, ); }; }; BD16BBCD6291F236455D1FBC72D33281 /* UIImage+HUExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D96800D9444348C9EF862C9797663E8 /* UIImage+HUExtension.h */; settings = {ATTRIBUTES = (Project, ); }; }; C3518915CEB45A87EF5DCAFC9F93696E /* HUWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = C9B410728A89C72F649567CB946115D1 /* HUWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; C58B4014568B8705E8A620707CA28F51 /* UIImageView+HUWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0ACFB56952A75327CCF7A9D285F61319 /* UIImageView+HUWebImage.m */; }; C7CA5364C6A3B19A1590369A9FC85A65 /* HUImageGridViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = BE78CD177B2F07E683BFE658848BA2A0 /* HUImageGridViewController.h */; settings = {ATTRIBUTES = (Project, ); }; }; C86C2E7953283ED2B5B845B676B038AC /* album_open_icon@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = A316B140C3B1474605CDE6512EA540FA /* album_open_icon@3x.png */; }; C8FAE843C4BA0303449B6E4D579EDBED /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE05B0A93E7AC961E35AFD6B72A43F53 /* UIKit.framework */; }; CDBA2121509F504062E1BDF268CB6D58 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B38EF6EE351405BFF1A723C71A0CF97 /* UIImage+GIF.m */; }; CDC033EC56BCF03AB75E7DCB77B8AC39 /* HUPhotoBrowserCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A8EC596D9BEBB2A682737B6979B9945 /* HUPhotoBrowserCell.m */; }; D02959EAAE84300F7DFFF1EF28CD4C2B /* NSBundle+HUPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AE15A73A5C43C841A105D61C78AC511 /* NSBundle+HUPicker.m */; }; D6B3DEABE7F25211FF3923A5F2116532 /* HUPHAuthorizationNotDeterminedViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A6EFC2685278E2DF77BF2A0DDBE083 /* HUPHAuthorizationNotDeterminedViewController.h */; settings = {ATTRIBUTES = (Project, ); }; }; D779890F7370C5C5554D8094AA4C5A13 /* UIBarButtonItem+HUButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 94E349128851E2C8898702890C40F4F9 /* UIBarButtonItem+HUButton.m */; }; D9746CBC85CFFE20D7E72B131EB4F8D0 /* UIBarButtonItem+HUButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A9A3289CAC5E7F9A6A2E7A0833F5790 /* UIBarButtonItem+HUButton.h */; settings = {ATTRIBUTES = (Project, ); }; }; D9D4B596A996B4F4AC367E8CA9209AF8 /* UIView+HUConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC223C3C761C783185E1FFB1A7A05E3 /* UIView+HUConstraint.h */; settings = {ATTRIBUTES = (Project, ); }; }; DBC6A6834B7CA85141141A9FC59E08C7 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 804666883EC6B1A30EE2C0C21974EA4E /* Photos.framework */; }; DC5D856B421A8DF82260E61BF79F08E8 /* HUWebImageDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DDDEAEFD125C897C744D5C9F295F28 /* HUWebImageDownloadOperation.m */; }; DF3321CF3E41B83F87AAD7F08BC3C764 /* SVIndefiniteAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = A6872A62128DF0B9C337DD8EB551B99F /* SVIndefiniteAnimatedView.m */; }; E1A09732EB1D4DEE543E57BC9E75B181 /* UIView+frame.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EB976DB4DE69AA197DACE8A0AE44DEA /* UIView+frame.h */; settings = {ATTRIBUTES = (Project, ); }; }; E283E46931867F7EBF81F3B55978CE76 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D7387A90A4E52BF5ADF9DC82A56D31E2 /* SDImageCache.m */; }; E91D8B354A89AC323FFB8E81B00780ED /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = E31DD5A02B0033EA77659E77DFEDD15A /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; EA5C2EE172234721DA4FFBE1E3EFAA18 /* HUNavTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CA2109BCE58B9B9827024FE7D6C2905 /* HUNavTitleView.m */; }; EB3B763E8A293AC718BF7B221FCAF395 /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B7D74B34C33201DFB7105711BABE76 /* UIView+WebCacheOperation.m */; }; F22AFC90A1EA932CB3EB26F29B6181C5 /* photo_button_selected@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = E25CC34B1906BD764E3B6AF5807B0175 /* photo_button_selected@3x.png */; }; F7E2ED980B54D1F1209B33A72877F145 /* Pods-HUPhotoBrowser DemoTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 224779CFFFD95B16021CB8EA8C4F9BBD /* Pods-HUPhotoBrowser DemoTests-dummy.m */; }; FCB0CF77447303B45928AB44BA7B4973 /* HUPhotoBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A5EB8FFE503BA9B41DE8F099A20CC64 /* HUPhotoBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; }; FD49D93DB71B5A970FEE2A166A3D24D0 /* SVRadialGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = C1D4A6B3E3FA774837EEE83CCC78A605 /* SVRadialGradientLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; FDB4A416E19DF7AAF581FD0A2D0597A8 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FFA0F53632825CF88AB2EB6B22A7F07 /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 1DF3B04FD0110B3430E6B386516516E5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = E5C155FFDDFCD74237E4D301D504CD59; remoteInfo = SVProgressHUD; }; 790BB20FF7770EDCDBFB4B49BC5FB78B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = 156B947C8425573AB59F6FB4E33470DD; remoteInfo = SDWebImage; }; 951FFE9A507AEB3DD9B0AC20F7350526 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = E5C155FFDDFCD74237E4D301D504CD59; remoteInfo = SVProgressHUD; }; B3BDC557D51B9B0E3D9C0C7BDED7FF6F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = B006CA1FB9E74F505B0BC5CD2168B0BA; remoteInfo = HUPhotoPicker; }; DE2931CB4A9D219A88807CD989EBA434 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = 4772B77F4E0FA787DC9FD7562D377C5F; remoteInfo = "HUPhotoPicker-HUPhotoPicker"; }; EB5B8CC38E68E7B676CB7C254E06C558 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; proxyType = 1; remoteGlobalIDString = F61EABE2A50F74AE114AA3F4367121A8; remoteInfo = HUPhotoBrowser; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 00C800A6F02590F678225961616F0E14 /* SDWebImagePrefetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImagePrefetcher.h; path = SDWebImage/SDWebImagePrefetcher.h; sourceTree = ""; }; 02090B8A152D8EA57D43A1D41FC3FAE1 /* HUPHAuthorizationNotDeterminedView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUPHAuthorizationNotDeterminedView.h; path = HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedView.h; sourceTree = ""; }; 0687350693844A2E9E522786088D90F3 /* SDWebImageCompat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageCompat.h; path = SDWebImage/SDWebImageCompat.h; sourceTree = ""; }; 08214ABFFF911AC79EAD4722979DDB29 /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCacheOperation.h"; path = "SDWebImage/UIView+WebCacheOperation.h"; sourceTree = ""; }; 0ACFB56952A75327CCF7A9D285F61319 /* UIImageView+HUWebImage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+HUWebImage.m"; sourceTree = ""; }; 0AE18F7ECC383B6860F958FFE3E22296 /* UIImage+HUExtension.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "UIImage+HUExtension.m"; sourceTree = ""; }; 0C2818BB53593BDAB01B9BE25C54FB07 /* Jurisdiction_icon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "Jurisdiction_icon@3x.png"; path = "HUPhotoPicker/Assets/Jurisdiction_icon@3x.png"; sourceTree = ""; }; 0CECA8E62DF6B3D72EBDAB13B981D010 /* libHUPhotoBrowser.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libHUPhotoBrowser.a; path = libHUPhotoBrowser.a; sourceTree = BUILT_PRODUCTS_DIR; }; 0D54E71FD9E8FE32D095B20904DE434C /* SVProgressHUD.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SVProgressHUD.xcconfig; sourceTree = ""; }; 0DA652A6053BD21B7B631581A9AE77F8 /* HUPhotoManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUPhotoManager.m; path = HUPhotoPicker/Classes/HUPhotoManager.m; sourceTree = ""; }; 0F6B03278E85DE641CB5405289304121 /* libSVProgressHUD.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libSVProgressHUD.a; path = libSVProgressHUD.a; sourceTree = BUILT_PRODUCTS_DIR; }; 10F59DBE0AF6AAF69E10F159B417661A /* HUPhotoAlbum.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUPhotoAlbum.h; path = HUPhotoPicker/Classes/HUPhotoAlbum.h; sourceTree = ""; }; 1277B0BF2774C41E61B74F8F3F084D87 /* HUTakePhotoCell.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUTakePhotoCell.h; path = HUPhotoPicker/Classes/HUTakePhotoCell.h; sourceTree = ""; }; 13320B73B1EEDEC7054B6BA67D32D4EB /* HUImageGridCell.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUImageGridCell.m; path = HUPhotoPicker/Classes/HUImageGridCell.m; sourceTree = ""; }; 13917CA1D52B803DA4188D30BE4F189D /* Pods-HUPhotoBrowser DemoTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-HUPhotoBrowser DemoTests.release.xcconfig"; sourceTree = ""; }; 13B5E72269741E51831AA307A834D172 /* HUPhotoManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUPhotoManager.h; path = HUPhotoPicker/Classes/HUPhotoManager.h; sourceTree = ""; }; 14E9CC31888031CF04ADADBFC41C548F /* Pods-HUPhotoBrowser DemoTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-HUPhotoBrowser DemoTests-acknowledgements.markdown"; sourceTree = ""; }; 17F3D3D171070259473E37C17EC3308E /* HUPhotoPicker.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = HUPhotoPicker.bundle; path = HUPhotoPicker.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 17F5F8ED6AD15C8E85169BF85D772348 /* SDImageCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDImageCache.h; path = SDWebImage/SDImageCache.h; sourceTree = ""; }; 183AA6FF36B86D6F3D84C9F33EC0E537 /* Pods-HUPhotoBrowser DemoTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-HUPhotoBrowser DemoTests-acknowledgements.plist"; sourceTree = ""; }; 19064ABD4D32F1FA7743601441F135D1 /* SDImageCacheConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDImageCacheConfig.h; path = SDWebImage/SDImageCacheConfig.h; sourceTree = ""; }; 1A5EB8FFE503BA9B41DE8F099A20CC64 /* HUPhotoBrowser.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUPhotoBrowser.h; path = HUPhotoBrowser/HUPhotoBrowser.h; sourceTree = ""; }; 1B6A27FBC85A69196B8297F1235D2027 /* HUPhotoBrowserCell.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUPhotoBrowserCell.h; path = HUPhotoBrowser/HUPhotoBrowserCell.h; sourceTree = ""; }; 1C51BE05478A10C56BD6FF53686494E7 /* SVProgressHUD.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVProgressHUD.m; path = SVProgressHUD/SVProgressHUD.m; sourceTree = ""; }; 1D96800D9444348C9EF862C9797663E8 /* UIImage+HUExtension.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "UIImage+HUExtension.h"; sourceTree = ""; }; 1EB976DB4DE69AA197DACE8A0AE44DEA /* UIView+frame.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+frame.h"; path = "HUPhotoBrowser/UIView+frame.h"; sourceTree = ""; }; 20FB595B908B4DA42B12C10B3B74A2FA /* UIImageView+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+WebCache.m"; path = "SDWebImage/UIImageView+WebCache.m"; sourceTree = ""; }; 21F56FEF368B49D93D7E4F418AAE8296 /* NSImage+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSImage+WebCache.h"; path = "SDWebImage/NSImage+WebCache.h"; sourceTree = ""; }; 224779CFFFD95B16021CB8EA8C4F9BBD /* Pods-HUPhotoBrowser DemoTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-HUPhotoBrowser DemoTests-dummy.m"; sourceTree = ""; }; 286D66F5AAD3686AC8D9AB22677CBCE9 /* UIImageView+HighlightedWebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+HighlightedWebCache.h"; path = "SDWebImage/UIImageView+HighlightedWebCache.h"; sourceTree = ""; }; 293ACC9890E0C871FC279737AA8EF8D3 /* HUWebImage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = HUWebImage.h; sourceTree = ""; }; 2A39260F4921A34460754C96BF086B62 /* Pods-HUPhotoBrowser Demo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-HUPhotoBrowser Demo-dummy.m"; sourceTree = ""; }; 2A7056DF7B1C83091325D3DF07123CB6 /* Asset.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Asset.h; path = HUPhotoPicker/Classes/Asset.h; sourceTree = ""; }; 2B72FB7B35A719AFAD18FAA1C4F6EDAC /* SVProgressHUD-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SVProgressHUD-dummy.m"; sourceTree = ""; }; 2E14F497E11E651AC49123BA06F5ED79 /* HUAlbumCell.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUAlbumCell.h; path = HUPhotoPicker/Classes/HUAlbumCell.h; sourceTree = ""; }; 2F476C600975412D143CA6797F9B48AF /* UIImageView+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+WebCache.h"; path = "SDWebImage/UIImageView+WebCache.h"; sourceTree = ""; }; 33DFF64EE6E05602EBA5701E00859628 /* Pods-HUPhotoBrowser DemoTests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-HUPhotoBrowser DemoTests-frameworks.sh"; sourceTree = ""; }; 34B7D74B34C33201DFB7105711BABE76 /* UIView+WebCacheOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCacheOperation.m"; path = "SDWebImage/UIView+WebCacheOperation.m"; sourceTree = ""; }; 34F8305A2C6089188628736DDD2F370A /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/ImageIO.framework; sourceTree = DEVELOPER_DIR; }; 3999B1A812D487DC85FA889ED46EED0C /* SDWebImage-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SDWebImage-prefix.pch"; sourceTree = ""; }; 3A7B323C6C7AA5954DD661A569FA77CD /* album_close_icon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "album_close_icon@2x.png"; path = "HUPhotoPicker/Assets/album_close_icon@2x.png"; sourceTree = ""; }; 3AEF36E1AC343442B9AD72564C0B21A8 /* HUPhotoBrowser.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = HUPhotoBrowser.xcconfig; sourceTree = ""; }; 3BFA6105989E1129CE256E52520269E1 /* SVProgressAnimatedView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVProgressAnimatedView.m; path = SVProgressHUD/SVProgressAnimatedView.m; sourceTree = ""; }; 3C61601A866B0B6F3B1CC15879939A46 /* HUAlbumTableViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUAlbumTableViewController.m; path = HUPhotoPicker/Classes/HUAlbumTableViewController.m; sourceTree = ""; }; 3CA2109BCE58B9B9827024FE7D6C2905 /* HUNavTitleView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUNavTitleView.m; path = HUPhotoPicker/Classes/HUNavTitleView.m; sourceTree = ""; }; 3F0FBC46E4BB9737994EE2E35E6E07A4 /* SDWebImagePrefetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImagePrefetcher.m; path = SDWebImage/SDWebImagePrefetcher.m; sourceTree = ""; }; 441D9E0D8C2033CBCB8EBD66CB4EDC11 /* SDWebImageManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageManager.m; path = SDWebImage/SDWebImageManager.m; sourceTree = ""; }; 45587FF486C1EEDF876807B8E8CC935E /* SDWebImageDownloaderOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloaderOperation.m; path = SDWebImage/SDWebImageDownloaderOperation.m; sourceTree = ""; }; 49A6EFC2685278E2DF77BF2A0DDBE083 /* HUPHAuthorizationNotDeterminedViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUPHAuthorizationNotDeterminedViewController.h; path = HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedViewController.h; sourceTree = ""; }; 4A8EC596D9BEBB2A682737B6979B9945 /* HUPhotoBrowserCell.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUPhotoBrowserCell.m; path = HUPhotoBrowser/HUPhotoBrowserCell.m; sourceTree = ""; }; 4C6DFDC2D8A016511F4AED26F3544CF6 /* SDWebImageManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageManager.h; path = SDWebImage/SDWebImageManager.h; sourceTree = ""; }; 4C796604D26CF43514817953954C5AF9 /* UIView+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCache.m"; path = "SDWebImage/UIView+WebCache.m"; sourceTree = ""; }; 4D9DC81E5EBE3E1913E938646E03C2E9 /* HUAlbumTableViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUAlbumTableViewController.h; path = HUPhotoPicker/Classes/HUAlbumTableViewController.h; sourceTree = ""; }; 4E825E9268F7A21ED4A10CACA6DAC8C9 /* SDWebImageDecoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDecoder.m; path = SDWebImage/SDWebImageDecoder.m; sourceTree = ""; }; 4FF76196D9A0CB2559E6874B8EEF173B /* Pods-HUPhotoBrowser Demo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-HUPhotoBrowser Demo.debug.xcconfig"; sourceTree = ""; }; 51C9CC5C6680C06B24AEC9DF433CC87C /* HUAlbumCell.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; name = HUAlbumCell.xib; path = HUPhotoPicker/Assets/HUAlbumCell.xib; sourceTree = ""; }; 5440CAABC38EE84F75266A36CB50E346 /* SDWebImageDecoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDecoder.h; path = SDWebImage/SDWebImageDecoder.h; sourceTree = ""; }; 545C51AB7AB0CB14DF4ECCA613BAFEA5 /* SDWebImageCompat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCompat.m; path = SDWebImage/SDWebImageCompat.m; sourceTree = ""; }; 56232916A8D191E1DEB3601409A09124 /* HUPHAuthorizationNotDeterminedView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUPHAuthorizationNotDeterminedView.m; path = HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedView.m; sourceTree = ""; }; 5DCC6D86420229BFAB1F056871A12607 /* SDWebImageDownloaderOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloaderOperation.h; path = SDWebImage/SDWebImageDownloaderOperation.h; sourceTree = ""; }; 5FBCA5CAA0922972DB941FA957456C36 /* UIView+frame.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+frame.m"; path = "HUPhotoBrowser/UIView+frame.m"; sourceTree = ""; }; 5FFA0F53632825CF88AB2EB6B22A7F07 /* SDWebImageOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageOperation.h; path = SDWebImage/SDWebImageOperation.h; sourceTree = ""; }; 61CE96D2977D382BDBEF6EB6C360CAA5 /* SDImageCacheConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDImageCacheConfig.m; path = SDWebImage/SDImageCacheConfig.m; sourceTree = ""; }; 69AED5B69BC460F980416E86560D5348 /* HUImageGridCell.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUImageGridCell.h; path = HUPhotoPicker/Classes/HUImageGridCell.h; sourceTree = ""; }; 69B7717C3661262547C2C6D471CC6BAC /* Pods-HUPhotoBrowser Demo-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-HUPhotoBrowser Demo-resources.sh"; sourceTree = ""; }; 6DC223C3C761C783185E1FFB1A7A05E3 /* UIView+HUConstraint.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+HUConstraint.h"; path = "HUPhotoPicker/Classes/UIView+HUConstraint.h"; sourceTree = ""; }; 6E8491134C958BC38C9F082D5CE0C36B /* HUImagePickerViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUImagePickerViewController.h; path = HUPhotoPicker/Classes/HUImagePickerViewController.h; sourceTree = ""; }; 703F045B6E13F9E59046173B939701EC /* photo_button_selected@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "photo_button_selected@2x.png"; path = "HUPhotoPicker/Assets/photo_button_selected@2x.png"; sourceTree = ""; }; 73B08799CBB6E6C520DFDC31692B4B3A /* album_photograph_icon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "album_photograph_icon@3x.png"; path = "HUPhotoPicker/Assets/album_photograph_icon@3x.png"; sourceTree = ""; }; 753A0AD8EE029D65DDC636A68F7A5D56 /* SVProgressHUD.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVProgressHUD.h; path = SVProgressHUD/SVProgressHUD.h; sourceTree = ""; }; 77001B333D5BD6024B8AD5FA9543880D /* Pods-HUPhotoBrowser Demo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-HUPhotoBrowser Demo-acknowledgements.plist"; sourceTree = ""; }; 7787CCB41A739DF35AC7AF65005F5384 /* SVIndefiniteAnimatedView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVIndefiniteAnimatedView.h; path = SVProgressHUD/SVIndefiniteAnimatedView.h; sourceTree = ""; }; 78840C91637E1D69D68C079ABE539DF4 /* HUPhotoPicker.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = HUPhotoPicker.xcconfig; sourceTree = ""; }; 7A7709F2BB2881894A4943D95A289521 /* libPods-HUPhotoBrowser DemoTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-HUPhotoBrowser DemoTests.a"; path = "libPods-HUPhotoBrowser DemoTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7CE6CBF80A2939FE6F1C7C149A1C1F4A /* HUImageSelectModel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUImageSelectModel.h; path = HUPhotoPicker/Classes/HUImageSelectModel.h; sourceTree = ""; }; 7F8B57C69320D79163431A32CD7C2404 /* Pods-HUPhotoBrowser DemoTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-HUPhotoBrowser DemoTests.debug.xcconfig"; sourceTree = ""; }; 804666883EC6B1A30EE2C0C21974EA4E /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Photos.framework; sourceTree = DEVELOPER_DIR; }; 865ECDF17E5F581EC036DA88C8EA5EC6 /* SVProgressAnimatedView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVProgressAnimatedView.h; path = SVProgressHUD/SVProgressAnimatedView.h; sourceTree = ""; }; 86EB8878AB1588D8FA0267B6BE6C0FCC /* libSDWebImage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libSDWebImage.a; path = libSDWebImage.a; sourceTree = BUILT_PRODUCTS_DIR; }; 895A080761ACCC7F75D47125CB036CDD /* Pods-HUPhotoBrowser Demo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-HUPhotoBrowser Demo-acknowledgements.markdown"; sourceTree = ""; }; 8A9A3289CAC5E7F9A6A2E7A0833F5790 /* UIBarButtonItem+HUButton.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIBarButtonItem+HUButton.h"; path = "HUPhotoPicker/Classes/UIBarButtonItem+HUButton.h"; sourceTree = ""; }; 8AE15A73A5C43C841A105D61C78AC511 /* NSBundle+HUPicker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSBundle+HUPicker.m"; path = "HUPhotoPicker/Classes/NSBundle+HUPicker.m"; sourceTree = ""; }; 8B38EF6EE351405BFF1A723C71A0CF97 /* UIImage+GIF.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+GIF.m"; path = "SDWebImage/UIImage+GIF.m"; sourceTree = ""; }; 90B6845A1227E66671DC5581A96EB9F6 /* SVProgressHUD.bundle */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "wrapper.plug-in"; name = SVProgressHUD.bundle; path = SVProgressHUD/SVProgressHUD.bundle; sourceTree = ""; }; 9103C49F8D840C91E18ED85756AB0BBB /* HUToast.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUToast.h; path = HUPhotoPicker/Classes/HUToast.h; sourceTree = ""; }; 91040B2B94B6447A1D4D9387C627B02A /* HUWebImageDownloadOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = HUWebImageDownloadOperation.h; sourceTree = ""; }; 919847A9F94E2FACD0E3E3CB08A71F90 /* NSImage+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSImage+WebCache.m"; path = "SDWebImage/NSImage+WebCache.m"; sourceTree = ""; }; 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 94DDDEAEFD125C897C744D5C9F295F28 /* HUWebImageDownloadOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = HUWebImageDownloadOperation.m; sourceTree = ""; }; 94E349128851E2C8898702890C40F4F9 /* UIBarButtonItem+HUButton.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIBarButtonItem+HUButton.m"; path = "HUPhotoPicker/Classes/UIBarButtonItem+HUButton.m"; sourceTree = ""; }; 9A68BB2127299F79461E6F6B3AB52869 /* UIImage+MultiFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+MultiFormat.m"; path = "SDWebImage/UIImage+MultiFormat.m"; sourceTree = ""; }; 9B2BFA65B10054FC241F1C3ABB96E68B /* SDWebImageDownloader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloader.m; path = SDWebImage/SDWebImageDownloader.m; sourceTree = ""; }; 9B6C41B0E78CD3F337D9DA8131A22914 /* nav_back@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "nav_back@3x.png"; path = "HUPhotoPicker/Assets/nav_back@3x.png"; sourceTree = ""; }; 9B9BF87558582615F2810E72AC339206 /* UIImageView+HighlightedWebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+HighlightedWebCache.m"; path = "SDWebImage/UIImageView+HighlightedWebCache.m"; sourceTree = ""; }; 9BAD901633A161CB4C35C1A9466869C3 /* HUAlbumCell.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUAlbumCell.m; path = HUPhotoPicker/Classes/HUAlbumCell.m; sourceTree = ""; }; A2D3BF58C096E8B3557DBD41DD70D03B /* HUNavTitleView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUNavTitleView.h; path = HUPhotoPicker/Classes/HUNavTitleView.h; sourceTree = ""; }; A316B140C3B1474605CDE6512EA540FA /* album_open_icon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "album_open_icon@3x.png"; path = "HUPhotoPicker/Assets/album_open_icon@3x.png"; sourceTree = ""; }; A4D56D45B44D3173C51062AD8CE60193 /* album_open_icon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "album_open_icon@2x.png"; path = "HUPhotoPicker/Assets/album_open_icon@2x.png"; sourceTree = ""; }; A524D07B783D67E8F7BC7A33A47770AE /* HUPhotoBrowser-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "HUPhotoBrowser-dummy.m"; sourceTree = ""; }; A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; A6872A62128DF0B9C337DD8EB551B99F /* SVIndefiniteAnimatedView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVIndefiniteAnimatedView.m; path = SVProgressHUD/SVIndefiniteAnimatedView.m; sourceTree = ""; }; AEC8F5C50FA9C44CF017CDCDCBA68D75 /* SDWebImage.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SDWebImage.xcconfig; sourceTree = ""; }; AF0D9B0557E593C2184912CC905AA5E1 /* UIView+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = ""; }; AFDEF6B3F68ABAD646B955014670B32D /* HUImageGridViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUImageGridViewController.m; path = HUPhotoPicker/Classes/HUImageGridViewController.m; sourceTree = ""; }; B6BCF7F14A2A289DFB89DA8D608C1796 /* photo_button_normal@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "photo_button_normal@2x.png"; path = "HUPhotoPicker/Assets/photo_button_normal@2x.png"; sourceTree = ""; }; BBCE812D3697587EE47CA1B5C2F315CC /* HUWebImageDownloader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = HUWebImageDownloader.m; sourceTree = ""; }; BCDA6B8A731D286647BA9FE57E672D58 /* HUPhotoPicker-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "HUPhotoPicker-prefix.pch"; sourceTree = ""; }; BD226A51E4C093FE0AA6EB24430D4C53 /* ResourceBundle-HUPhotoPicker-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-HUPhotoPicker-Info.plist"; sourceTree = ""; }; BDADDF678F3ECC6FEB0547730DB2AF2D /* photo_button_normal@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "photo_button_normal@3x.png"; path = "HUPhotoPicker/Assets/photo_button_normal@3x.png"; sourceTree = ""; }; BE78CD177B2F07E683BFE658848BA2A0 /* HUImageGridViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUImageGridViewController.h; path = HUPhotoPicker/Classes/HUImageGridViewController.h; sourceTree = ""; }; BEF559DE20B55C84DA7DE88F2DC3674F /* HUToast.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUToast.m; path = HUPhotoPicker/Classes/HUToast.m; sourceTree = ""; }; C137D78D8E705BFC3E79578F84BA3413 /* image_selected@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "image_selected@2x.png"; path = "HUPhotoPicker/Assets/image_selected@2x.png"; sourceTree = ""; }; C1D4A6B3E3FA774837EEE83CCC78A605 /* SVRadialGradientLayer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVRadialGradientLayer.h; path = SVProgressHUD/SVRadialGradientLayer.h; sourceTree = ""; }; C28CA3BBDBA583094087A2890A7C7FE0 /* album_photograph_icon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "album_photograph_icon@2x.png"; path = "HUPhotoPicker/Assets/album_photograph_icon@2x.png"; sourceTree = ""; }; C3D0023A3AA419520B006770CC4B9FD4 /* nav_back@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "nav_back@2x.png"; path = "HUPhotoPicker/Assets/nav_back@2x.png"; sourceTree = ""; }; C4F9ECEA64607144F85BC468769B68C2 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; C68E7235956D835ADFBE6514D8E96EFA /* Jurisdiction_icon@2x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "Jurisdiction_icon@2x.png"; path = "HUPhotoPicker/Assets/Jurisdiction_icon@2x.png"; sourceTree = ""; }; C6EAE39BE0B78BD51FA0C8578DFC6215 /* HUPHAuthorizationNotDeterminedViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUPHAuthorizationNotDeterminedViewController.m; path = HUPhotoPicker/Classes/HUPHAuthorizationNotDeterminedViewController.m; sourceTree = ""; }; C843E13541704A189B1DAD2DBC088F04 /* UIImageView+HUWebImage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "UIImageView+HUWebImage.h"; sourceTree = ""; }; C86AB20D8D71D526A8202973E9A1F545 /* album_close_icon@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "album_close_icon@3x.png"; path = "HUPhotoPicker/Assets/album_close_icon@3x.png"; sourceTree = ""; }; C913A7B67CFC7768421A5A3DC7F2D166 /* SVProgressHUD-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SVProgressHUD-prefix.pch"; sourceTree = ""; }; C9B410728A89C72F649567CB946115D1 /* HUWebImageDownloader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = HUWebImageDownloader.h; sourceTree = ""; }; CA6CD145963CCB8E08499D36ECDCCB66 /* HUPhotoBrowser-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "HUPhotoBrowser-prefix.pch"; sourceTree = ""; }; CB4C960A4ED6443011407CED0D78F10A /* Pods-HUPhotoBrowser Demo-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-HUPhotoBrowser Demo-frameworks.sh"; sourceTree = ""; }; CEE283977FB59654D573A812CE050DE1 /* libHUPhotoPicker.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libHUPhotoPicker.a; path = libHUPhotoPicker.a; sourceTree = BUILT_PRODUCTS_DIR; }; D2A1832C622E09402E5443E39EEB7C17 /* HUImageSelectModel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUImageSelectModel.m; path = HUPhotoPicker/Classes/HUImageSelectModel.m; sourceTree = ""; }; D2F66A76856B26ADEC9C3296F0FE0B5A /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/AssetsLibrary.framework; sourceTree = DEVELOPER_DIR; }; D49449D610A39E04D4C2A121F5E4FD32 /* HUPhotoPicker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = HUPhotoPicker.h; path = HUPhotoPicker/Classes/HUPhotoPicker.h; sourceTree = ""; }; D4E456D947C1E3759C029BA645213B74 /* NSData+ImageContentType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+ImageContentType.m"; path = "SDWebImage/NSData+ImageContentType.m"; sourceTree = ""; }; D68944CA5223A84064F95C057951163C /* image_selected@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "image_selected@3x.png"; path = "HUPhotoPicker/Assets/image_selected@3x.png"; sourceTree = ""; }; D6B30683558D738F4DE543582F7189B1 /* HUImagePickerViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUImagePickerViewController.m; path = HUPhotoPicker/Classes/HUImagePickerViewController.m; sourceTree = ""; }; D7387A90A4E52BF5ADF9DC82A56D31E2 /* SDImageCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDImageCache.m; path = SDWebImage/SDImageCache.m; sourceTree = ""; }; D958A56255E71ADC24D80C094DAC1A7A /* NSData+ImageContentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+ImageContentType.h"; path = "SDWebImage/NSData+ImageContentType.h"; sourceTree = ""; }; D9EB29BC0DA93559B0D44D7C78426356 /* HUTakePhotoCell.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUTakePhotoCell.m; path = HUPhotoPicker/Classes/HUTakePhotoCell.m; sourceTree = ""; }; DB229E87D174F577903EA3558BBCFFE8 /* Pods-HUPhotoBrowser Demo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-HUPhotoBrowser Demo.release.xcconfig"; sourceTree = ""; }; DE8F32142A47511484566FE4535744C4 /* UIButton+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIButton+WebCache.m"; path = "SDWebImage/UIButton+WebCache.m"; sourceTree = ""; }; E25CC34B1906BD764E3B6AF5807B0175 /* photo_button_selected@3x.png */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.png; name = "photo_button_selected@3x.png"; path = "HUPhotoPicker/Assets/photo_button_selected@3x.png"; sourceTree = ""; }; E31DD5A02B0033EA77659E77DFEDD15A /* UIImage+GIF.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+GIF.h"; path = "SDWebImage/UIImage+GIF.h"; sourceTree = ""; }; EBB4E8043E0015F89FDA55D0CA569CC4 /* SVRadialGradientLayer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVRadialGradientLayer.m; path = SVProgressHUD/SVRadialGradientLayer.m; sourceTree = ""; }; EBCCDDCFD3DA396C62681DC281319765 /* HUPhotoPicker-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "HUPhotoPicker-dummy.m"; sourceTree = ""; }; EE05B0A93E7AC961E35AFD6B72A43F53 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; EF9E2A9B5D26C80D040D929EE90F0842 /* Pods-HUPhotoBrowser DemoTests-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-HUPhotoBrowser DemoTests-resources.sh"; sourceTree = ""; }; F057D640CB9E60D7D53423DD283C9A4B /* SDWebImage-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SDWebImage-dummy.m"; sourceTree = ""; }; F0DACE5743EF9203F95EDC4F0FF77FC3 /* UIView+HUConstraint.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+HUConstraint.m"; path = "HUPhotoPicker/Classes/UIView+HUConstraint.m"; sourceTree = ""; }; F157F1452E6D4EAE236DA49C7C0E894B /* hu_const.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = hu_const.h; path = HUPhotoBrowser/hu_const.h; sourceTree = ""; }; F40275D281978286F1EF17FFD2F1EE13 /* libPods-HUPhotoBrowser Demo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-HUPhotoBrowser Demo.a"; path = "libPods-HUPhotoBrowser Demo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F475A7C707C8FB377AC19C870CEAFFF2 /* SDWebImageDownloader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloader.h; path = SDWebImage/SDWebImageDownloader.h; sourceTree = ""; }; F48C3A3A0784AB826CDC951A03656357 /* UIButton+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIButton+WebCache.h"; path = "SDWebImage/UIButton+WebCache.h"; sourceTree = ""; }; F527FE5669CA594E88CADC793838CDAF /* HUPhotoAlbum.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUPhotoAlbum.m; path = HUPhotoPicker/Classes/HUPhotoAlbum.m; sourceTree = ""; }; F69008F697735A74BE8C45DDAEF29A41 /* UIImage+MultiFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+MultiFormat.h"; path = "SDWebImage/UIImage+MultiFormat.h"; sourceTree = ""; }; F7A0250C4B3D552BA4CADE666439B13D /* HUPhotoBrowser.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = HUPhotoBrowser.m; path = HUPhotoBrowser/HUPhotoBrowser.m; sourceTree = ""; }; FB68DA04853D2044F150D9165DD4AD40 /* NSBundle+HUPicker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSBundle+HUPicker.h"; path = "HUPhotoPicker/Classes/NSBundle+HUPicker.h"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 063B674068CF89B7BFAB7DAB46D19676 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5BA328FA29936FC6602FA2AC66CA7023 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 095D2746327D112F8F7CBD22F201924D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( A2B42E2B533938834E83B3957FA83837 /* AssetsLibrary.framework in Frameworks */, 65CEECC1600B3EB655A0EB242D354A88 /* Foundation.framework in Frameworks */, DBC6A6834B7CA85141141A9FC59E08C7 /* Photos.framework in Frameworks */, 5DCEE92ACF66523B2A394A8FCD937EA5 /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 41D0CC7A5EFB3510D6C83AC852997328 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 152BF7BE0AA241A5C6BE4F608CA9E6A0 /* Foundation.framework in Frameworks */, 1B055DEC5A93B3430137EDFD63E1A62E /* ImageIO.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 4263BA91AB5BCADF1771D24F8B500824 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 598BA4AEFD2B722B093B57F23D516DF1 /* Foundation.framework in Frameworks */, 441F9F02296486E9F50BB59E0105966E /* Photos.framework in Frameworks */, C8FAE843C4BA0303449B6E4D579EDBED /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 47B8E4B05887106AD2FABDF9FDB9A1DE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 2FFFCBCE6865FEDD745574FD47A69FD6 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 94C0498FB46DB156178D97C655D33798 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; F68052484B2C480C016CF638BDADF9B7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8A96738F5A80EDF3797B7716F8F12E63 /* Foundation.framework in Frameworks */, 873C75AB9B12A76E90DAF9EAB44A991C /* QuartzCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 0313090EF36336C32E2DBF682981D6E3 /* HUWebImageDownloader */ = { isa = PBXGroup; children = ( 293ACC9890E0C871FC279737AA8EF8D3 /* HUWebImage.h */, C9B410728A89C72F649567CB946115D1 /* HUWebImageDownloader.h */, BBCE812D3697587EE47CA1B5C2F315CC /* HUWebImageDownloader.m */, 91040B2B94B6447A1D4D9387C627B02A /* HUWebImageDownloadOperation.h */, 94DDDEAEFD125C897C744D5C9F295F28 /* HUWebImageDownloadOperation.m */, 1D96800D9444348C9EF862C9797663E8 /* UIImage+HUExtension.h */, 0AE18F7ECC383B6860F958FFE3E22296 /* UIImage+HUExtension.m */, C843E13541704A189B1DAD2DBC088F04 /* UIImageView+HUWebImage.h */, 0ACFB56952A75327CCF7A9D285F61319 /* UIImageView+HUWebImage.m */, ); name = HUWebImageDownloader; path = HUPhotoBrowser/HUWebImageDownloader; sourceTree = ""; }; 0F75DF6C7C5F002280EC53F48E80B587 /* Frameworks */ = { isa = PBXGroup; children = ( 19787ECAF53623DF874C61875B53D08D /* iOS */, ); name = Frameworks; sourceTree = ""; }; 171418DC06B5B64C6711C5E5FEFC5197 /* Core */ = { isa = PBXGroup; children = ( D958A56255E71ADC24D80C094DAC1A7A /* NSData+ImageContentType.h */, D4E456D947C1E3759C029BA645213B74 /* NSData+ImageContentType.m */, 21F56FEF368B49D93D7E4F418AAE8296 /* NSImage+WebCache.h */, 919847A9F94E2FACD0E3E3CB08A71F90 /* NSImage+WebCache.m */, 17F5F8ED6AD15C8E85169BF85D772348 /* SDImageCache.h */, D7387A90A4E52BF5ADF9DC82A56D31E2 /* SDImageCache.m */, 19064ABD4D32F1FA7743601441F135D1 /* SDImageCacheConfig.h */, 61CE96D2977D382BDBEF6EB6C360CAA5 /* SDImageCacheConfig.m */, 0687350693844A2E9E522786088D90F3 /* SDWebImageCompat.h */, 545C51AB7AB0CB14DF4ECCA613BAFEA5 /* SDWebImageCompat.m */, 5440CAABC38EE84F75266A36CB50E346 /* SDWebImageDecoder.h */, 4E825E9268F7A21ED4A10CACA6DAC8C9 /* SDWebImageDecoder.m */, F475A7C707C8FB377AC19C870CEAFFF2 /* SDWebImageDownloader.h */, 9B2BFA65B10054FC241F1C3ABB96E68B /* SDWebImageDownloader.m */, 5DCC6D86420229BFAB1F056871A12607 /* SDWebImageDownloaderOperation.h */, 45587FF486C1EEDF876807B8E8CC935E /* SDWebImageDownloaderOperation.m */, 4C6DFDC2D8A016511F4AED26F3544CF6 /* SDWebImageManager.h */, 441D9E0D8C2033CBCB8EBD66CB4EDC11 /* SDWebImageManager.m */, 5FFA0F53632825CF88AB2EB6B22A7F07 /* SDWebImageOperation.h */, 00C800A6F02590F678225961616F0E14 /* SDWebImagePrefetcher.h */, 3F0FBC46E4BB9737994EE2E35E6E07A4 /* SDWebImagePrefetcher.m */, F48C3A3A0784AB826CDC951A03656357 /* UIButton+WebCache.h */, DE8F32142A47511484566FE4535744C4 /* UIButton+WebCache.m */, E31DD5A02B0033EA77659E77DFEDD15A /* UIImage+GIF.h */, 8B38EF6EE351405BFF1A723C71A0CF97 /* UIImage+GIF.m */, F69008F697735A74BE8C45DDAEF29A41 /* UIImage+MultiFormat.h */, 9A68BB2127299F79461E6F6B3AB52869 /* UIImage+MultiFormat.m */, 286D66F5AAD3686AC8D9AB22677CBCE9 /* UIImageView+HighlightedWebCache.h */, 9B9BF87558582615F2810E72AC339206 /* UIImageView+HighlightedWebCache.m */, 2F476C600975412D143CA6797F9B48AF /* UIImageView+WebCache.h */, 20FB595B908B4DA42B12C10B3B74A2FA /* UIImageView+WebCache.m */, AF0D9B0557E593C2184912CC905AA5E1 /* UIView+WebCache.h */, 4C796604D26CF43514817953954C5AF9 /* UIView+WebCache.m */, 08214ABFFF911AC79EAD4722979DDB29 /* UIView+WebCacheOperation.h */, 34B7D74B34C33201DFB7105711BABE76 /* UIView+WebCacheOperation.m */, ); name = Core; sourceTree = ""; }; 19787ECAF53623DF874C61875B53D08D /* iOS */ = { isa = PBXGroup; children = ( D2F66A76856B26ADEC9C3296F0FE0B5A /* AssetsLibrary.framework */, A686FEEDCC01B1622154D0E4BEB71DAA /* Foundation.framework */, 34F8305A2C6089188628736DDD2F370A /* ImageIO.framework */, 804666883EC6B1A30EE2C0C21974EA4E /* Photos.framework */, C4F9ECEA64607144F85BC468769B68C2 /* QuartzCore.framework */, EE05B0A93E7AC961E35AFD6B72A43F53 /* UIKit.framework */, ); name = iOS; sourceTree = ""; }; 1E9E8D26106091BD0A1AF0E73CC18238 /* Pods */ = { isa = PBXGroup; children = ( 7A7A9D3DA9027E12C10548EB5B176F39 /* HUPhotoPicker */, C141E24DAE503BE8A1C686D6407C04DC /* SDWebImage */, 8563363B161204C619CD121C1456AD0E /* SVProgressHUD */, ); name = Pods; sourceTree = ""; }; 334FE9B6CB0E7FFB4B425A33D010C366 /* Support Files */ = { isa = PBXGroup; children = ( AEC8F5C50FA9C44CF017CDCDCBA68D75 /* SDWebImage.xcconfig */, F057D640CB9E60D7D53423DD283C9A4B /* SDWebImage-dummy.m */, 3999B1A812D487DC85FA889ED46EED0C /* SDWebImage-prefix.pch */, ); name = "Support Files"; path = "../Target Support Files/SDWebImage"; sourceTree = ""; }; 65B20E1911D3952C4690E2D9624E3A12 /* Resources */ = { isa = PBXGroup; children = ( 3A7B323C6C7AA5954DD661A569FA77CD /* album_close_icon@2x.png */, C86AB20D8D71D526A8202973E9A1F545 /* album_close_icon@3x.png */, A4D56D45B44D3173C51062AD8CE60193 /* album_open_icon@2x.png */, A316B140C3B1474605CDE6512EA540FA /* album_open_icon@3x.png */, C28CA3BBDBA583094087A2890A7C7FE0 /* album_photograph_icon@2x.png */, 73B08799CBB6E6C520DFDC31692B4B3A /* album_photograph_icon@3x.png */, 51C9CC5C6680C06B24AEC9DF433CC87C /* HUAlbumCell.xib */, C137D78D8E705BFC3E79578F84BA3413 /* image_selected@2x.png */, D68944CA5223A84064F95C057951163C /* image_selected@3x.png */, C68E7235956D835ADFBE6514D8E96EFA /* Jurisdiction_icon@2x.png */, 0C2818BB53593BDAB01B9BE25C54FB07 /* Jurisdiction_icon@3x.png */, C3D0023A3AA419520B006770CC4B9FD4 /* nav_back@2x.png */, 9B6C41B0E78CD3F337D9DA8131A22914 /* nav_back@3x.png */, B6BCF7F14A2A289DFB89DA8D608C1796 /* photo_button_normal@2x.png */, BDADDF678F3ECC6FEB0547730DB2AF2D /* photo_button_normal@3x.png */, 703F045B6E13F9E59046173B939701EC /* photo_button_selected@2x.png */, E25CC34B1906BD764E3B6AF5807B0175 /* photo_button_selected@3x.png */, ); name = Resources; sourceTree = ""; }; 687C06316E780C503C03DE72FFF157D8 /* Resources */ = { isa = PBXGroup; children = ( 90B6845A1227E66671DC5581A96EB9F6 /* SVProgressHUD.bundle */, ); name = Resources; sourceTree = ""; }; 72C0920D2EF08E5B40D7784A8BFE23D7 /* Development Pods */ = { isa = PBXGroup; children = ( F4206806B2C20A1252CCC9E9F647F909 /* HUPhotoBrowser */, ); name = "Development Pods"; sourceTree = ""; }; 7593731E7B5C3D86B3F569016D3EA381 /* Support Files */ = { isa = PBXGroup; children = ( 3AEF36E1AC343442B9AD72564C0B21A8 /* HUPhotoBrowser.xcconfig */, A524D07B783D67E8F7BC7A33A47770AE /* HUPhotoBrowser-dummy.m */, CA6CD145963CCB8E08499D36ECDCCB66 /* HUPhotoBrowser-prefix.pch */, ); name = "Support Files"; path = "Example/Pods/Target Support Files/HUPhotoBrowser"; sourceTree = ""; }; 7A7A9D3DA9027E12C10548EB5B176F39 /* HUPhotoPicker */ = { isa = PBXGroup; children = ( 2A7056DF7B1C83091325D3DF07123CB6 /* Asset.h */, 2E14F497E11E651AC49123BA06F5ED79 /* HUAlbumCell.h */, 9BAD901633A161CB4C35C1A9466869C3 /* HUAlbumCell.m */, 4D9DC81E5EBE3E1913E938646E03C2E9 /* HUAlbumTableViewController.h */, 3C61601A866B0B6F3B1CC15879939A46 /* HUAlbumTableViewController.m */, 69AED5B69BC460F980416E86560D5348 /* HUImageGridCell.h */, 13320B73B1EEDEC7054B6BA67D32D4EB /* HUImageGridCell.m */, BE78CD177B2F07E683BFE658848BA2A0 /* HUImageGridViewController.h */, AFDEF6B3F68ABAD646B955014670B32D /* HUImageGridViewController.m */, 6E8491134C958BC38C9F082D5CE0C36B /* HUImagePickerViewController.h */, D6B30683558D738F4DE543582F7189B1 /* HUImagePickerViewController.m */, 7CE6CBF80A2939FE6F1C7C149A1C1F4A /* HUImageSelectModel.h */, D2A1832C622E09402E5443E39EEB7C17 /* HUImageSelectModel.m */, A2D3BF58C096E8B3557DBD41DD70D03B /* HUNavTitleView.h */, 3CA2109BCE58B9B9827024FE7D6C2905 /* HUNavTitleView.m */, 02090B8A152D8EA57D43A1D41FC3FAE1 /* HUPHAuthorizationNotDeterminedView.h */, 56232916A8D191E1DEB3601409A09124 /* HUPHAuthorizationNotDeterminedView.m */, 49A6EFC2685278E2DF77BF2A0DDBE083 /* HUPHAuthorizationNotDeterminedViewController.h */, C6EAE39BE0B78BD51FA0C8578DFC6215 /* HUPHAuthorizationNotDeterminedViewController.m */, 10F59DBE0AF6AAF69E10F159B417661A /* HUPhotoAlbum.h */, F527FE5669CA594E88CADC793838CDAF /* HUPhotoAlbum.m */, 13B5E72269741E51831AA307A834D172 /* HUPhotoManager.h */, 0DA652A6053BD21B7B631581A9AE77F8 /* HUPhotoManager.m */, D49449D610A39E04D4C2A121F5E4FD32 /* HUPhotoPicker.h */, 1277B0BF2774C41E61B74F8F3F084D87 /* HUTakePhotoCell.h */, D9EB29BC0DA93559B0D44D7C78426356 /* HUTakePhotoCell.m */, 9103C49F8D840C91E18ED85756AB0BBB /* HUToast.h */, BEF559DE20B55C84DA7DE88F2DC3674F /* HUToast.m */, FB68DA04853D2044F150D9165DD4AD40 /* NSBundle+HUPicker.h */, 8AE15A73A5C43C841A105D61C78AC511 /* NSBundle+HUPicker.m */, 8A9A3289CAC5E7F9A6A2E7A0833F5790 /* UIBarButtonItem+HUButton.h */, 94E349128851E2C8898702890C40F4F9 /* UIBarButtonItem+HUButton.m */, 6DC223C3C761C783185E1FFB1A7A05E3 /* UIView+HUConstraint.h */, F0DACE5743EF9203F95EDC4F0FF77FC3 /* UIView+HUConstraint.m */, 65B20E1911D3952C4690E2D9624E3A12 /* Resources */, F682F651A42C817B34DE17ECE43BAAE0 /* Support Files */, ); name = HUPhotoPicker; path = HUPhotoPicker; sourceTree = ""; }; 7DB346D0F39D3F0E887471402A8071AB = { isa = PBXGroup; children = ( 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, 72C0920D2EF08E5B40D7784A8BFE23D7 /* Development Pods */, 0F75DF6C7C5F002280EC53F48E80B587 /* Frameworks */, 1E9E8D26106091BD0A1AF0E73CC18238 /* Pods */, B49F57C580B2CCB2292C58C91277F4A9 /* Products */, F248E4B88C8D370AF4CF4006577CE639 /* Targets Support Files */, ); sourceTree = ""; }; 8563363B161204C619CD121C1456AD0E /* SVProgressHUD */ = { isa = PBXGroup; children = ( 7787CCB41A739DF35AC7AF65005F5384 /* SVIndefiniteAnimatedView.h */, A6872A62128DF0B9C337DD8EB551B99F /* SVIndefiniteAnimatedView.m */, 865ECDF17E5F581EC036DA88C8EA5EC6 /* SVProgressAnimatedView.h */, 3BFA6105989E1129CE256E52520269E1 /* SVProgressAnimatedView.m */, 753A0AD8EE029D65DDC636A68F7A5D56 /* SVProgressHUD.h */, 1C51BE05478A10C56BD6FF53686494E7 /* SVProgressHUD.m */, C1D4A6B3E3FA774837EEE83CCC78A605 /* SVRadialGradientLayer.h */, EBB4E8043E0015F89FDA55D0CA569CC4 /* SVRadialGradientLayer.m */, 687C06316E780C503C03DE72FFF157D8 /* Resources */, C98B5D2FB360673444C19E9D0A391537 /* Support Files */, ); name = SVProgressHUD; path = SVProgressHUD; sourceTree = ""; }; B49F57C580B2CCB2292C58C91277F4A9 /* Products */ = { isa = PBXGroup; children = ( 17F3D3D171070259473E37C17EC3308E /* HUPhotoPicker.bundle */, 0CECA8E62DF6B3D72EBDAB13B981D010 /* libHUPhotoBrowser.a */, CEE283977FB59654D573A812CE050DE1 /* libHUPhotoPicker.a */, F40275D281978286F1EF17FFD2F1EE13 /* libPods-HUPhotoBrowser Demo.a */, 7A7709F2BB2881894A4943D95A289521 /* libPods-HUPhotoBrowser DemoTests.a */, 86EB8878AB1588D8FA0267B6BE6C0FCC /* libSDWebImage.a */, 0F6B03278E85DE641CB5405289304121 /* libSVProgressHUD.a */, ); name = Products; sourceTree = ""; }; C13FB43381584AC30D896899D52394C3 /* Pods-HUPhotoBrowser Demo */ = { isa = PBXGroup; children = ( 895A080761ACCC7F75D47125CB036CDD /* Pods-HUPhotoBrowser Demo-acknowledgements.markdown */, 77001B333D5BD6024B8AD5FA9543880D /* Pods-HUPhotoBrowser Demo-acknowledgements.plist */, 2A39260F4921A34460754C96BF086B62 /* Pods-HUPhotoBrowser Demo-dummy.m */, CB4C960A4ED6443011407CED0D78F10A /* Pods-HUPhotoBrowser Demo-frameworks.sh */, 69B7717C3661262547C2C6D471CC6BAC /* Pods-HUPhotoBrowser Demo-resources.sh */, 4FF76196D9A0CB2559E6874B8EEF173B /* Pods-HUPhotoBrowser Demo.debug.xcconfig */, DB229E87D174F577903EA3558BBCFFE8 /* Pods-HUPhotoBrowser Demo.release.xcconfig */, ); name = "Pods-HUPhotoBrowser Demo"; path = "Target Support Files/Pods-HUPhotoBrowser Demo"; sourceTree = ""; }; C141E24DAE503BE8A1C686D6407C04DC /* SDWebImage */ = { isa = PBXGroup; children = ( 171418DC06B5B64C6711C5E5FEFC5197 /* Core */, 334FE9B6CB0E7FFB4B425A33D010C366 /* Support Files */, ); name = SDWebImage; path = SDWebImage; sourceTree = ""; }; C98B5D2FB360673444C19E9D0A391537 /* Support Files */ = { isa = PBXGroup; children = ( 0D54E71FD9E8FE32D095B20904DE434C /* SVProgressHUD.xcconfig */, 2B72FB7B35A719AFAD18FAA1C4F6EDAC /* SVProgressHUD-dummy.m */, C913A7B67CFC7768421A5A3DC7F2D166 /* SVProgressHUD-prefix.pch */, ); name = "Support Files"; path = "../Target Support Files/SVProgressHUD"; sourceTree = ""; }; E7C2E1910DB4FFCA95881AED687FDB64 /* Pods-HUPhotoBrowser DemoTests */ = { isa = PBXGroup; children = ( 14E9CC31888031CF04ADADBFC41C548F /* Pods-HUPhotoBrowser DemoTests-acknowledgements.markdown */, 183AA6FF36B86D6F3D84C9F33EC0E537 /* Pods-HUPhotoBrowser DemoTests-acknowledgements.plist */, 224779CFFFD95B16021CB8EA8C4F9BBD /* Pods-HUPhotoBrowser DemoTests-dummy.m */, 33DFF64EE6E05602EBA5701E00859628 /* Pods-HUPhotoBrowser DemoTests-frameworks.sh */, EF9E2A9B5D26C80D040D929EE90F0842 /* Pods-HUPhotoBrowser DemoTests-resources.sh */, 7F8B57C69320D79163431A32CD7C2404 /* Pods-HUPhotoBrowser DemoTests.debug.xcconfig */, 13917CA1D52B803DA4188D30BE4F189D /* Pods-HUPhotoBrowser DemoTests.release.xcconfig */, ); name = "Pods-HUPhotoBrowser DemoTests"; path = "Target Support Files/Pods-HUPhotoBrowser DemoTests"; sourceTree = ""; }; F248E4B88C8D370AF4CF4006577CE639 /* Targets Support Files */ = { isa = PBXGroup; children = ( C13FB43381584AC30D896899D52394C3 /* Pods-HUPhotoBrowser Demo */, E7C2E1910DB4FFCA95881AED687FDB64 /* Pods-HUPhotoBrowser DemoTests */, ); name = "Targets Support Files"; sourceTree = ""; }; F4206806B2C20A1252CCC9E9F647F909 /* HUPhotoBrowser */ = { isa = PBXGroup; children = ( F157F1452E6D4EAE236DA49C7C0E894B /* hu_const.h */, 1A5EB8FFE503BA9B41DE8F099A20CC64 /* HUPhotoBrowser.h */, F7A0250C4B3D552BA4CADE666439B13D /* HUPhotoBrowser.m */, 1B6A27FBC85A69196B8297F1235D2027 /* HUPhotoBrowserCell.h */, 4A8EC596D9BEBB2A682737B6979B9945 /* HUPhotoBrowserCell.m */, 1EB976DB4DE69AA197DACE8A0AE44DEA /* UIView+frame.h */, 5FBCA5CAA0922972DB941FA957456C36 /* UIView+frame.m */, 0313090EF36336C32E2DBF682981D6E3 /* HUWebImageDownloader */, 7593731E7B5C3D86B3F569016D3EA381 /* Support Files */, ); name = HUPhotoBrowser; path = ../..; sourceTree = ""; }; F682F651A42C817B34DE17ECE43BAAE0 /* Support Files */ = { isa = PBXGroup; children = ( 78840C91637E1D69D68C079ABE539DF4 /* HUPhotoPicker.xcconfig */, EBCCDDCFD3DA396C62681DC281319765 /* HUPhotoPicker-dummy.m */, BCDA6B8A731D286647BA9FE57E672D58 /* HUPhotoPicker-prefix.pch */, BD226A51E4C093FE0AA6EB24430D4C53 /* ResourceBundle-HUPhotoPicker-Info.plist */, ); name = "Support Files"; path = "../Target Support Files/HUPhotoPicker"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ C833D1D1AEE942105B1A1C3FA5E85408 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 91AB44B5B7DB95A7BA5B5B5D3DAF775D /* Asset.h in Headers */, 53A14922CA39A52C1926D0246C2BB1F0 /* HUAlbumCell.h in Headers */, 154E25C8A639BD2855EF6ED1CE1311D0 /* HUAlbumTableViewController.h in Headers */, 671D941A03C1E763513AAA4857DC51BD /* HUImageGridCell.h in Headers */, C7CA5364C6A3B19A1590369A9FC85A65 /* HUImageGridViewController.h in Headers */, 694DC69113D8FC517034EC5FBC00950A /* HUImagePickerViewController.h in Headers */, 79996630838668D04EA3BFB57560995E /* HUImageSelectModel.h in Headers */, 62E71CA9C06816E2FB7E729AF2283634 /* HUNavTitleView.h in Headers */, 7E813E032E1B31658FCF923F78B479B5 /* HUPHAuthorizationNotDeterminedView.h in Headers */, D6B3DEABE7F25211FF3923A5F2116532 /* HUPHAuthorizationNotDeterminedViewController.h in Headers */, 822C18350931407D1EE15B2BB719E3F3 /* HUPhotoAlbum.h in Headers */, 86FB723DD88559EC1E288B9FA5B7EE4A /* HUPhotoManager.h in Headers */, 8392C6FF89FEE6B0FB3042AA0925313D /* HUPhotoPicker.h in Headers */, A63D39295D405569DCE488454011DBAB /* HUTakePhotoCell.h in Headers */, 66DECE27B5EF416042C9FF26AD43EF00 /* HUToast.h in Headers */, 4B8779A43D1E81C6FFE4593B5F8D6288 /* NSBundle+HUPicker.h in Headers */, D9746CBC85CFFE20D7E72B131EB4F8D0 /* UIBarButtonItem+HUButton.h in Headers */, D9D4B596A996B4F4AC367E8CA9209AF8 /* UIView+HUConstraint.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; E269ABD59815D8090277FDC9CB16E700 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 746F598854C3DB3E9DB0D0726148FD94 /* hu_const.h in Headers */, FCB0CF77447303B45928AB44BA7B4973 /* HUPhotoBrowser.h in Headers */, 91D498E3B268ECC94289A8EBE57FDB14 /* HUPhotoBrowserCell.h in Headers */, BC0BFD421A71955FE7C83DC3EAC0BBCB /* HUWebImage.h in Headers */, C3518915CEB45A87EF5DCAFC9F93696E /* HUWebImageDownloader.h in Headers */, 1C531B0E4A281E5F1CCFD426B5C59F50 /* HUWebImageDownloadOperation.h in Headers */, BD16BBCD6291F236455D1FBC72D33281 /* UIImage+HUExtension.h in Headers */, B68A1F5A13355D589240D8E774D7F10D /* UIImageView+HUWebImage.h in Headers */, E1A09732EB1D4DEE543E57BC9E75B181 /* UIView+frame.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; EEB07E5BA3422DDE3C45990A51895A12 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 909372963DBA08C68992835EB86061EA /* NSData+ImageContentType.h in Headers */, 13944C33461BCA0868BC17FC8D7E6252 /* NSImage+WebCache.h in Headers */, 8B6C609B4E035A892066DC53BBFB119E /* SDImageCache.h in Headers */, 9EA3B8E135E065F0914BEB70EDFE6775 /* SDImageCacheConfig.h in Headers */, 580058559154D3B6A975DDAE7EFBA3C5 /* SDWebImageCompat.h in Headers */, 935F70349715265D86E8FD0597447AC5 /* SDWebImageDecoder.h in Headers */, 6169115EC8E6EFE24CFCEF5D1E02D736 /* SDWebImageDownloader.h in Headers */, A7DB2E7B837586BE06497232D65B3BA8 /* SDWebImageDownloaderOperation.h in Headers */, B45672895B70B90CBB854A69850A112F /* SDWebImageManager.h in Headers */, FDB4A416E19DF7AAF581FD0A2D0597A8 /* SDWebImageOperation.h in Headers */, 053D329FAA96B749E2FD97CB6D096A85 /* SDWebImagePrefetcher.h in Headers */, 36081993A921C1EECB74335B1EE0F34C /* UIButton+WebCache.h in Headers */, E91D8B354A89AC323FFB8E81B00780ED /* UIImage+GIF.h in Headers */, 83C575C5E394FD4869BEAE2FE3FD5B02 /* UIImage+MultiFormat.h in Headers */, 9BDE24BE44A77B9E0CB09814CE3941E3 /* UIImageView+HighlightedWebCache.h in Headers */, AA2B867A047A62006345CABCFC932C81 /* UIImageView+WebCache.h in Headers */, 35D8BA8171A586B59D48614BCBC18DDA /* UIView+WebCache.h in Headers */, 99B738B37205FF969C2BDB51627CD71A /* UIView+WebCacheOperation.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; F8C0AAF3DC5EDAB41DD5F48225CEAD49 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 2AC999D34D8A6DEECCC2D91261A67865 /* SVIndefiniteAnimatedView.h in Headers */, 3E845D3F5BC22756CFE33576ECF38EDF /* SVProgressAnimatedView.h in Headers */, 97EB8C5178E22A872B36A788152AA571 /* SVProgressHUD.h in Headers */, FD49D93DB71B5A970FEE2A166A3D24D0 /* SVRadialGradientLayer.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 156B947C8425573AB59F6FB4E33470DD /* SDWebImage */ = { isa = PBXNativeTarget; buildConfigurationList = 1CFE1EF6C9D0CD7F16160CFEEF22DC0B /* Build configuration list for PBXNativeTarget "SDWebImage" */; buildPhases = ( AAD613155F792B1ADD908AC91B3E2D3B /* Sources */, 41D0CC7A5EFB3510D6C83AC852997328 /* Frameworks */, EEB07E5BA3422DDE3C45990A51895A12 /* Headers */, ); buildRules = ( ); dependencies = ( ); name = SDWebImage; productName = SDWebImage; productReference = 86EB8878AB1588D8FA0267B6BE6C0FCC /* libSDWebImage.a */; productType = "com.apple.product-type.library.static"; }; 4772B77F4E0FA787DC9FD7562D377C5F /* HUPhotoPicker-HUPhotoPicker */ = { isa = PBXNativeTarget; buildConfigurationList = 01A81BE7749D71E2120346BFA3BACEF7 /* Build configuration list for PBXNativeTarget "HUPhotoPicker-HUPhotoPicker" */; buildPhases = ( A513A3F7610B8DEE82E16BB9312A2C84 /* Sources */, 94C0498FB46DB156178D97C655D33798 /* Frameworks */, 97C9896AE3F6AD1770134355F813EDCD /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "HUPhotoPicker-HUPhotoPicker"; productName = "HUPhotoPicker-HUPhotoPicker"; productReference = 17F3D3D171070259473E37C17EC3308E /* HUPhotoPicker.bundle */; productType = "com.apple.product-type.bundle"; }; A967FC69F45B325EC7CF38A222A0F061 /* Pods-HUPhotoBrowser Demo */ = { isa = PBXNativeTarget; buildConfigurationList = 869C987873DBAD36D192B53483FD0EB2 /* Build configuration list for PBXNativeTarget "Pods-HUPhotoBrowser Demo" */; buildPhases = ( 8AA4BBF919CD430E8B00B1CA777D551D /* Sources */, 47B8E4B05887106AD2FABDF9FDB9A1DE /* Frameworks */, ); buildRules = ( ); dependencies = ( 1F651011E8A3C6EA78948E36FC5E84A2 /* PBXTargetDependency */, EC74BF93658F924EFF80CBC17CDFF3B2 /* PBXTargetDependency */, 0B15C14E27ABC4FA96416EA9A433CD13 /* PBXTargetDependency */, 417B3E9CF133B89A8FF2A217789AF193 /* PBXTargetDependency */, ); name = "Pods-HUPhotoBrowser Demo"; productName = "Pods-HUPhotoBrowser Demo"; productReference = F40275D281978286F1EF17FFD2F1EE13 /* libPods-HUPhotoBrowser Demo.a */; productType = "com.apple.product-type.library.static"; }; B006CA1FB9E74F505B0BC5CD2168B0BA /* HUPhotoPicker */ = { isa = PBXNativeTarget; buildConfigurationList = 0DD8A5F759F4079DEF53C494F2577FBD /* Build configuration list for PBXNativeTarget "HUPhotoPicker" */; buildPhases = ( 972D6D65117094EF26E3D25BD1A98931 /* Sources */, 4263BA91AB5BCADF1771D24F8B500824 /* Frameworks */, C833D1D1AEE942105B1A1C3FA5E85408 /* Headers */, ); buildRules = ( ); dependencies = ( 63C04A309F7DFEBC58DE1F156B1B0EA5 /* PBXTargetDependency */, ); name = HUPhotoPicker; productName = HUPhotoPicker; productReference = CEE283977FB59654D573A812CE050DE1 /* libHUPhotoPicker.a */; productType = "com.apple.product-type.library.static"; }; E5C155FFDDFCD74237E4D301D504CD59 /* SVProgressHUD */ = { isa = PBXNativeTarget; buildConfigurationList = 9003DDA5075FE3C75CA206B7E041DA44 /* Build configuration list for PBXNativeTarget "SVProgressHUD" */; buildPhases = ( 02B4C68DA2988726742D262656479F9E /* Sources */, F68052484B2C480C016CF638BDADF9B7 /* Frameworks */, F8C0AAF3DC5EDAB41DD5F48225CEAD49 /* Headers */, ); buildRules = ( ); dependencies = ( ); name = SVProgressHUD; productName = SVProgressHUD; productReference = 0F6B03278E85DE641CB5405289304121 /* libSVProgressHUD.a */; productType = "com.apple.product-type.library.static"; }; F04AE9B453427EDFA1DD604800D07CDB /* Pods-HUPhotoBrowser DemoTests */ = { isa = PBXNativeTarget; buildConfigurationList = 49D9422F3E6B2B15945506AC7A664D58 /* Build configuration list for PBXNativeTarget "Pods-HUPhotoBrowser DemoTests" */; buildPhases = ( 0F85E94F8C0D2A54EC51AF10F44D15F6 /* Sources */, 063B674068CF89B7BFAB7DAB46D19676 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = "Pods-HUPhotoBrowser DemoTests"; productName = "Pods-HUPhotoBrowser DemoTests"; productReference = 7A7709F2BB2881894A4943D95A289521 /* libPods-HUPhotoBrowser DemoTests.a */; productType = "com.apple.product-type.library.static"; }; F61EABE2A50F74AE114AA3F4367121A8 /* HUPhotoBrowser */ = { isa = PBXNativeTarget; buildConfigurationList = 9D555F1499957E226484E6F3D66A967C /* Build configuration list for PBXNativeTarget "HUPhotoBrowser" */; buildPhases = ( 54366A947FD33DEEBF300A7ACDB91720 /* Sources */, 095D2746327D112F8F7CBD22F201924D /* Frameworks */, E269ABD59815D8090277FDC9CB16E700 /* Headers */, ); buildRules = ( ); dependencies = ( ADBD3F6F55D7EE158445FD3E0B8D71AE /* PBXTargetDependency */, ); name = HUPhotoBrowser; productName = HUPhotoBrowser; productReference = 0CECA8E62DF6B3D72EBDAB13B981D010 /* libHUPhotoBrowser.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0830; LastUpgradeCheck = 0700; }; buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 7DB346D0F39D3F0E887471402A8071AB; productRefGroup = B49F57C580B2CCB2292C58C91277F4A9 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( F61EABE2A50F74AE114AA3F4367121A8 /* HUPhotoBrowser */, B006CA1FB9E74F505B0BC5CD2168B0BA /* HUPhotoPicker */, 4772B77F4E0FA787DC9FD7562D377C5F /* HUPhotoPicker-HUPhotoPicker */, A967FC69F45B325EC7CF38A222A0F061 /* Pods-HUPhotoBrowser Demo */, F04AE9B453427EDFA1DD604800D07CDB /* Pods-HUPhotoBrowser DemoTests */, 156B947C8425573AB59F6FB4E33470DD /* SDWebImage */, E5C155FFDDFCD74237E4D301D504CD59 /* SVProgressHUD */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 97C9896AE3F6AD1770134355F813EDCD /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 1D14675094EB2982854BBDE56D642F7F /* album_close_icon@2x.png in Resources */, 6A2EE1939C21B95571A77B65094E505D /* album_close_icon@3x.png in Resources */, 93E2D3CD516D98158E5D06EAD5EF4868 /* album_open_icon@2x.png in Resources */, C86C2E7953283ED2B5B845B676B038AC /* album_open_icon@3x.png in Resources */, A3E65E80FAA621CA37687E721E440540 /* album_photograph_icon@2x.png in Resources */, 400FEBC5B5E78F7BC76B9FB21DC02912 /* album_photograph_icon@3x.png in Resources */, 8E653B2F5B6D7E3A285833A5888AC3D6 /* HUAlbumCell.xib in Resources */, 24AC460FDE1C0610A111CCF67FC835D8 /* image_selected@2x.png in Resources */, 2C61EAC4DA7890F245FBD68AE417C4CA /* image_selected@3x.png in Resources */, 78DBC6F454ABC5112579DF6275C4461A /* Jurisdiction_icon@2x.png in Resources */, 3A7A90BB67EA1197192AC12C57CB9585 /* Jurisdiction_icon@3x.png in Resources */, 35C11FA48B4F1C25AEC21C72FFDF51B5 /* nav_back@2x.png in Resources */, 12B9BC6E6EC8792296CED4F0C56ED6E2 /* nav_back@3x.png in Resources */, A3F0B52FC22E648C3D8783934613B1BA /* photo_button_normal@2x.png in Resources */, A0CC6C2D247E55AE7E6E4CE552C7B270 /* photo_button_normal@3x.png in Resources */, 4DAB2E3EAFE5D4EF3806D2A76036F4FF /* photo_button_selected@2x.png in Resources */, F22AFC90A1EA932CB3EB26F29B6181C5 /* photo_button_selected@3x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 02B4C68DA2988726742D262656479F9E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DF3321CF3E41B83F87AAD7F08BC3C764 /* SVIndefiniteAnimatedView.m in Sources */, 841A407A7C5DC32F91DA0EB3D8014C2E /* SVProgressAnimatedView.m in Sources */, 7E071687325BF5B296A25A75974490C3 /* SVProgressHUD-dummy.m in Sources */, 0CE6A5C6B62A9FD71E66BD0B202273A4 /* SVProgressHUD.m in Sources */, 0801E52B09E882BB1E2441347E566214 /* SVRadialGradientLayer.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 0F85E94F8C0D2A54EC51AF10F44D15F6 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( F7E2ED980B54D1F1209B33A72877F145 /* Pods-HUPhotoBrowser DemoTests-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 54366A947FD33DEEBF300A7ACDB91720 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1241C92252F5500B6FA1782A66AF6432 /* HUPhotoBrowser-dummy.m in Sources */, 98C136139F278CFA1281924A853F23F0 /* HUPhotoBrowser.m in Sources */, CDC033EC56BCF03AB75E7DCB77B8AC39 /* HUPhotoBrowserCell.m in Sources */, 5D4A489B188F4BCA1B89DE0F17BB8FA7 /* HUWebImageDownloader.m in Sources */, DC5D856B421A8DF82260E61BF79F08E8 /* HUWebImageDownloadOperation.m in Sources */, 02735D8436E3DB9E7EA79694C58BE6F4 /* UIImage+HUExtension.m in Sources */, C58B4014568B8705E8A620707CA28F51 /* UIImageView+HUWebImage.m in Sources */, 7C3459B05690C13218F9F23C827FE21A /* UIView+frame.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 8AA4BBF919CD430E8B00B1CA777D551D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A5D6462FB49CAFF292C5EDE70BD65784 /* Pods-HUPhotoBrowser Demo-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 972D6D65117094EF26E3D25BD1A98931 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A60F3472AD558A5C66E269AD32F0A160 /* HUAlbumCell.m in Sources */, 74302A6E58181E6596A1BB389365F43F /* HUAlbumTableViewController.m in Sources */, 2BD3489F5F1D3B0D47C57D3506A372F8 /* HUImageGridCell.m in Sources */, 1E766D1CE8821B1AA0F0BA3769BD750E /* HUImageGridViewController.m in Sources */, 5A90BA62A73A14336AE2A28E5D320B0A /* HUImagePickerViewController.m in Sources */, 1E868873A8CF56F277977C0F28D6D54D /* HUImageSelectModel.m in Sources */, EA5C2EE172234721DA4FFBE1E3EFAA18 /* HUNavTitleView.m in Sources */, 8CFB4E2A821C8946F972B52F14E1EAB3 /* HUPHAuthorizationNotDeterminedView.m in Sources */, 66025EBA8B6D98C392958C8520F6D7E5 /* HUPHAuthorizationNotDeterminedViewController.m in Sources */, 1DA19173FBBEE7D11EBFD489D002ECB3 /* HUPhotoAlbum.m in Sources */, 605A413ED7A7834E43679FB47E2C1110 /* HUPhotoManager.m in Sources */, BBAEBB6AF61E7D4AD565BBF9FF8A16DB /* HUPhotoPicker-dummy.m in Sources */, 0A4BFCC90ABBFF825C70EFE9F9B7CD34 /* HUTakePhotoCell.m in Sources */, 3D9390CD8F716E217F034C87639ABBAD /* HUToast.m in Sources */, D02959EAAE84300F7DFFF1EF28CD4C2B /* NSBundle+HUPicker.m in Sources */, D779890F7370C5C5554D8094AA4C5A13 /* UIBarButtonItem+HUButton.m in Sources */, 44315C1D5AA06EC4516CC016F4505054 /* UIView+HUConstraint.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; A513A3F7610B8DEE82E16BB9312A2C84 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; AAD613155F792B1ADD908AC91B3E2D3B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 768C9F5C502E68F2914072040FFA71E1 /* NSData+ImageContentType.m in Sources */, 384A9AAA97DAB3A480C1DD84170AD1A8 /* NSImage+WebCache.m in Sources */, E283E46931867F7EBF81F3B55978CE76 /* SDImageCache.m in Sources */, 41E3EC52537EB6280D7DE2DFEB19F369 /* SDImageCacheConfig.m in Sources */, 9BC35B29E439FAC7E11246F5898D0BD1 /* SDWebImage-dummy.m in Sources */, 086F8C085ABB04F9C8C5C422DFDF1412 /* SDWebImageCompat.m in Sources */, A0DB532409564F8DF18924EA2CBB0929 /* SDWebImageDecoder.m in Sources */, 29CD90FDAAB316F204CEEAFB5564A5A7 /* SDWebImageDownloader.m in Sources */, 8BAB9550CAA0B5A7EA5F2F828130E136 /* SDWebImageDownloaderOperation.m in Sources */, 0615F5F2ABF3C6D02B66F471EAEE37BA /* SDWebImageManager.m in Sources */, 641BF2B026B2E09570949CEAAA1CEC79 /* SDWebImagePrefetcher.m in Sources */, 527E140533AFB0472E5D59561053EDD2 /* UIButton+WebCache.m in Sources */, CDBA2121509F504062E1BDF268CB6D58 /* UIImage+GIF.m in Sources */, 0B674BD1EC01B2F2E5B86BC361C2032B /* UIImage+MultiFormat.m in Sources */, 8DC69158558D4AB7EE00575DA0CDD675 /* UIImageView+HighlightedWebCache.m in Sources */, 65B63AB881AA74C306596717363C5E0F /* UIImageView+WebCache.m in Sources */, 814F5D3D6EE077DCD1A25EDF6DB63CAA /* UIView+WebCache.m in Sources */, EB3B763E8A293AC718BF7B221FCAF395 /* UIView+WebCacheOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 0B15C14E27ABC4FA96416EA9A433CD13 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = SDWebImage; target = 156B947C8425573AB59F6FB4E33470DD /* SDWebImage */; targetProxy = 790BB20FF7770EDCDBFB4B49BC5FB78B /* PBXContainerItemProxy */; }; 1F651011E8A3C6EA78948E36FC5E84A2 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = HUPhotoBrowser; target = F61EABE2A50F74AE114AA3F4367121A8 /* HUPhotoBrowser */; targetProxy = EB5B8CC38E68E7B676CB7C254E06C558 /* PBXContainerItemProxy */; }; 417B3E9CF133B89A8FF2A217789AF193 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = SVProgressHUD; target = E5C155FFDDFCD74237E4D301D504CD59 /* SVProgressHUD */; targetProxy = 951FFE9A507AEB3DD9B0AC20F7350526 /* PBXContainerItemProxy */; }; 63C04A309F7DFEBC58DE1F156B1B0EA5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "HUPhotoPicker-HUPhotoPicker"; target = 4772B77F4E0FA787DC9FD7562D377C5F /* HUPhotoPicker-HUPhotoPicker */; targetProxy = DE2931CB4A9D219A88807CD989EBA434 /* PBXContainerItemProxy */; }; ADBD3F6F55D7EE158445FD3E0B8D71AE /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = SVProgressHUD; target = E5C155FFDDFCD74237E4D301D504CD59 /* SVProgressHUD */; targetProxy = 1DF3B04FD0110B3430E6B386516516E5 /* PBXContainerItemProxy */; }; EC74BF93658F924EFF80CBC17CDFF3B2 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = HUPhotoPicker; target = B006CA1FB9E74F505B0BC5CD2168B0BA /* HUPhotoPicker */; targetProxy = B3BDC557D51B9B0E3D9C0C7BDED7FF6F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 0141343739AB373F60DF8691AFCD097C /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7F8B57C69320D79163431A32CD7C2404 /* Pods-HUPhotoBrowser DemoTests.debug.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACH_O_TYPE = staticlib; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 22377722B54CEA220B33075E180F68E1 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 3AEF36E1AC343442B9AD72564C0B21A8 /* HUPhotoBrowser.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/HUPhotoBrowser/HUPhotoBrowser-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 262ECDA72B399AD668790B59999BA38B /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 13917CA1D52B803DA4188D30BE4F189D /* Pods-HUPhotoBrowser DemoTests.release.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACH_O_TYPE = staticlib; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 3E3922C790F227CB9358C41F82E4A577 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 78840C91637E1D69D68C079ABE539DF4 /* HUPhotoPicker.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/HUPhotoPicker/HUPhotoPicker-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 414365BE408DDEB60DF35C2DA46DE1FD /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 0D54E71FD9E8FE32D095B20904DE434C /* SVProgressHUD.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/SVProgressHUD/SVProgressHUD-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 4A2DD3DF4606A726BA33D4F4139283C9 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = AEC8F5C50FA9C44CF017CDCDCBA68D75 /* SDWebImage.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/SDWebImage/SDWebImage-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 67458CA8CD34424F39F65F5F1FE37B8E /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = DB229E87D174F577903EA3558BBCFFE8 /* Pods-HUPhotoBrowser Demo.release.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACH_O_TYPE = staticlib; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 8EC6FD9EB1429A7D7F927F4FA1276BD6 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = AEC8F5C50FA9C44CF017CDCDCBA68D75 /* SDWebImage.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/SDWebImage/SDWebImage-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; A0E7D401EA4BB8DD9B7D7A69D231AA69 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 78840C91637E1D69D68C079ABE539DF4 /* HUPhotoPicker.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/HUPhotoPicker"; INFOPLIST_FILE = "Target Support Files/HUPhotoPicker/ResourceBundle-HUPhotoPicker-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = HUPhotoPicker; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = bundle; }; name = Debug; }; B254DAA6CF0CE39F4A3D11B90A7E059A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGNING_REQUIRED = NO; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "POD_CONFIGURATION_RELEASE=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; STRIP_INSTALLED_PRODUCT = NO; SYMROOT = "${SRCROOT}/../build"; }; name = Release; }; BE6108ECA88AFEC9B72003AF9E741D95 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 0D54E71FD9E8FE32D095B20904DE434C /* SVProgressHUD.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/SVProgressHUD/SVProgressHUD-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; C3E66C76BAB6746B5434D13F4C770C90 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 78840C91637E1D69D68C079ABE539DF4 /* HUPhotoPicker.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/HUPhotoPicker"; INFOPLIST_FILE = "Target Support Files/HUPhotoPicker/ResourceBundle-HUPhotoPicker-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = HUPhotoPicker; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = bundle; }; name = Release; }; D1E9C2E6BAC87B6C77F63447E0B40810 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 4FF76196D9A0CB2559E6874B8EEF173B /* Pods-HUPhotoBrowser Demo.debug.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACH_O_TYPE = staticlib; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; E4B68EE12B21C47CB798D9B1ECA6D7A7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGNING_REQUIRED = NO; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "POD_CONFIGURATION_DEBUG=1", "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; STRIP_INSTALLED_PRODUCT = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SYMROOT = "${SRCROOT}/../build"; }; name = Debug; }; F33E8CB424B79EF0CD0D55632F86B406 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 78840C91637E1D69D68C079ABE539DF4 /* HUPhotoPicker.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/HUPhotoPicker/HUPhotoPicker-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; F9CC67483B41520152C233D956FA092D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 3AEF36E1AC343442B9AD72564C0B21A8 /* HUPhotoBrowser.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; GCC_PREFIX_HEADER = "Target Support Files/HUPhotoBrowser/HUPhotoBrowser-prefix.pch"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PRIVATE_HEADERS_FOLDER_PATH = ""; PUBLIC_HEADERS_FOLDER_PATH = ""; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 01A81BE7749D71E2120346BFA3BACEF7 /* Build configuration list for PBXNativeTarget "HUPhotoPicker-HUPhotoPicker" */ = { isa = XCConfigurationList; buildConfigurations = ( A0E7D401EA4BB8DD9B7D7A69D231AA69 /* Debug */, C3E66C76BAB6746B5434D13F4C770C90 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0DD8A5F759F4079DEF53C494F2577FBD /* Build configuration list for PBXNativeTarget "HUPhotoPicker" */ = { isa = XCConfigurationList; buildConfigurations = ( F33E8CB424B79EF0CD0D55632F86B406 /* Debug */, 3E3922C790F227CB9358C41F82E4A577 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1CFE1EF6C9D0CD7F16160CFEEF22DC0B /* Build configuration list for PBXNativeTarget "SDWebImage" */ = { isa = XCConfigurationList; buildConfigurations = ( 8EC6FD9EB1429A7D7F927F4FA1276BD6 /* Debug */, 4A2DD3DF4606A726BA33D4F4139283C9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( E4B68EE12B21C47CB798D9B1ECA6D7A7 /* Debug */, B254DAA6CF0CE39F4A3D11B90A7E059A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 49D9422F3E6B2B15945506AC7A664D58 /* Build configuration list for PBXNativeTarget "Pods-HUPhotoBrowser DemoTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 0141343739AB373F60DF8691AFCD097C /* Debug */, 262ECDA72B399AD668790B59999BA38B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 869C987873DBAD36D192B53483FD0EB2 /* Build configuration list for PBXNativeTarget "Pods-HUPhotoBrowser Demo" */ = { isa = XCConfigurationList; buildConfigurations = ( D1E9C2E6BAC87B6C77F63447E0B40810 /* Debug */, 67458CA8CD34424F39F65F5F1FE37B8E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 9003DDA5075FE3C75CA206B7E041DA44 /* Build configuration list for PBXNativeTarget "SVProgressHUD" */ = { isa = XCConfigurationList; buildConfigurations = ( BE6108ECA88AFEC9B72003AF9E741D95 /* Debug */, 414365BE408DDEB60DF35C2DA46DE1FD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 9D555F1499957E226484E6F3D66A967C /* Build configuration list for PBXNativeTarget "HUPhotoBrowser" */ = { isa = XCConfigurationList; buildConfigurations = ( 22377722B54CEA220B33075E180F68E1 /* Debug */, F9CC67483B41520152C233D956FA092D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; } ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/HUPhotoBrowser.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/HUPhotoPicker-HUPhotoPicker.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/HUPhotoPicker.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/Pods-HUPhotoBrowser Demo.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/Pods-HUPhotoBrowser DemoTests.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/SDWebImage.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/SVProgressHUD.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/huluobo.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState HUPhotoBrowser.xcscheme isShown orderHint 0 HUPhotoPicker-HUPhotoPicker.xcscheme isShown orderHint 2 HUPhotoPicker.xcscheme isShown orderHint 1 Pods-HUPhotoBrowser Demo.xcscheme isShown orderHint 3 Pods-HUPhotoBrowser DemoTests.xcscheme isShown orderHint 4 SDWebImage.xcscheme isShown orderHint 5 SVProgressHUD.xcscheme isShown orderHint 6 SuppressBuildableAutocreation ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/HUPhotoBrowser.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/HUPhotoPicker-HUPhotoPicker.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/HUPhotoPicker.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/Pods-HUPhotoBrowser Demo.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/Pods-HUPhotoBrowser DemoTests.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/SDWebImage.xcscheme ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState HUPhotoBrowser.xcscheme isShown HUPhotoPicker-HUPhotoPicker.xcscheme isShown HUPhotoPicker.xcscheme isShown Pods-HUPhotoBrowser Demo.xcscheme isShown Pods-HUPhotoBrowser DemoTests.xcscheme isShown SDWebImage.xcscheme isShown SuppressBuildableAutocreation ================================================ FILE: Example/Pods/SDWebImage/LICENSE ================================================ Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Example/Pods/SDWebImage/README.md ================================================

[![Build Status](http://img.shields.io/travis/rs/SDWebImage/master.svg?style=flat)](https://travis-ci.org/rs/SDWebImage) [![Pod Version](http://img.shields.io/cocoapods/v/SDWebImage.svg?style=flat)](http://cocoadocs.org/docsets/SDWebImage/) [![Pod Platform](http://img.shields.io/cocoapods/p/SDWebImage.svg?style=flat)](http://cocoadocs.org/docsets/SDWebImage/) [![Pod License](http://img.shields.io/cocoapods/l/SDWebImage.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Dependency Status](https://www.versioneye.com/objective-c/sdwebimage/badge.svg?style=flat)](https://www.versioneye.com/objective-c/sdwebimage) [![Reference Status](https://www.versioneye.com/objective-c/sdwebimage/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/sdwebimage/references) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/rs/SDWebImage) [![codecov](https://codecov.io/gh/rs/SDWebImage/branch/master/graph/badge.svg)](https://codecov.io/gh/rs/SDWebImage) This library provides an async image downloader with cache support. For convenience, we added categories for UI elements like `UIImageView`, `UIButton`, `MKAnnotationView`. ## Features - [x] Categories for `UIImageView`, `UIButton`, `MKAnnotationView` adding web image and cache management - [x] An asynchronous image downloader - [x] An asynchronous memory + disk image caching with automatic cache expiration handling - [x] A background image decompression - [x] A guarantee that the same URL won't be downloaded several times - [x] A guarantee that bogus URLs won't be retried again and again - [x] A guarantee that main thread will never be blocked - [x] Performances! - [x] Use GCD and ARC ## Supported Image Formats - Image formats supported by UIImage (JPEG, PNG, ...), including GIF - WebP format, including animated WebP (use the `WebP` subspec) ## Requirements - iOS 7.0 or later - tvOS 9.0 or later - watchOS 2.0 or later - OS X 10.8 or later - Xcode 7.3 or later #### Backwards compatibility - For iOS 5 and 6, use [any 3.x version up to 3.7.6](https://github.com/rs/SDWebImage/tree/3.7.6) - For iOS < 5.0, please use the last [2.0 version](https://github.com/rs/SDWebImage/tree/2.0-compat). ## Getting Started - Read this Readme doc - Read the [How to use section](https://github.com/rs/SDWebImage#how-to-use) - Read the [documentation @ CocoaDocs](http://cocoadocs.org/docsets/SDWebImage/) - Read [How is SDWebImage better than X?](https://github.com/rs/SDWebImage/wiki/How-is-SDWebImage-better-than-X%3F) - Try the example by downloading the project from Github or even easier using CocoaPods try `pod try SDWebImage` - Get to the [installation steps](https://github.com/rs/SDWebImage#installation) - Read the [SDWebImage 4.0 Migration Guide](Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x ## Who Uses It - Find out [who uses SDWebImage](https://github.com/rs/SDWebImage/wiki/Who-Uses-SDWebImage) and add your app to the list. ## Communication - If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/sdwebimage). (Tag 'sdwebimage') - If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/sdwebimage). - If you **found a bug**, open an issue. - If you **have a feature request**, open an issue. - If you **want to contribute**, submit a pull request. ## How To Use ```objective-c Objective-C: #import ... [imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]]; ``` ```swift Swift: import SDWebImage imageView.sd_setImage(with: URL(string: "http://www.domain.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png")) ``` - For details about how to use the library and clear examples, see [The detailed How to use](Docs/HowToUse.md) ## Animated Images (GIF) support - Starting with the 4.0 version, we rely on [FLAnimatedImage](https://github.com/Flipboard/FLAnimatedImage) to take care of our animated images. - If you use cocoapods, add `pod 'SDWebImage/GIF'` to your podfile. - To use it, simply make sure you use `FLAnimatedImageView` instead of `UIImageView`. - **Note**: there is a backwards compatible feature, so if you are still trying to load a GIF into a `UIImageView`, it will only show the 1st frame as a static image. - **Important**: FLAnimatedImage only works on the iOS platform. For OS X, use `NSImageView` with `animates` set to `YES` to show the entire animated images and `NO` to only show the 1st frame. For all the other platforms (tvOS, watchOS) we will fallback to the backwards compatibility feature described above ## Common Problems ### Using dynamic image size with UITableViewCell UITableView determines the size of the image by the first image set for a cell. If your remote images don't have the same size as your placeholder image, you may experience strange anamorphic scaling issue. The following article gives a way to workaround this issue: [http://www.wrichards.com/blog/2011/11/sdwebimage-fixed-width-cell-images/](http://www.wrichards.com/blog/2011/11/sdwebimage-fixed-width-cell-images/) ### Handle image refresh SDWebImage does very aggressive caching by default. It ignores all kind of caching control header returned by the HTTP server and cache the returned images with no time restriction. It implies your images URLs are static URLs pointing to images that never change. If the pointed image happen to change, some parts of the URL should change accordingly. If you don't control the image server you're using, you may not be able to change the URL when its content is updated. This is the case for Facebook avatar URLs for instance. In such case, you may use the `SDWebImageRefreshCached` flag. This will slightly degrade the performance but will respect the HTTP caching control headers: ``` objective-c [imageView sd_setImageWithURL:[NSURL URLWithString:@"https://graph.facebook.com/olivier.poitrey/picture"] placeholderImage:[UIImage imageNamed:@"avatar-placeholder.png"] options:SDWebImageRefreshCached]; ``` ### Add a progress indicator Add these before you call ```sd_setImageWithURL``` ``` objective-c [imageView sd_setShowActivityIndicatorView:YES]; [imageView sd_setIndicatorStyle:UIActivityIndicatorViewStyleGray]; ``` ``` swift imageView.sd_setShowActivityIndicatorView(true) imageView.sd_setIndicatorStyle(.Gray) ``` ## Installation There are three ways to use SDWebImage in your project: - using CocoaPods - using Carthage - by cloning the project into your repository ### Installation with CocoaPods [CocoaPods](http://cocoapods.org/) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. See the [Get Started](http://cocoapods.org/#get_started) section for more details. #### Podfile ``` platform :ios, '7.0' pod 'SDWebImage', '~> 4.0' ``` If you are using Swift, be sure to add `use_frameworks!` and set your target to iOS 8+: ``` platform :ios, '8.0' use_frameworks! ``` #### Subspecs There are 4 subspecs available now: `Core`, `MapKit`, `GIF` and `WebP` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `WebP`, you need to specify it). Podfile example: ``` pod 'SDWebImage/WebP' ``` ### Installation with Carthage (iOS 8+) [Carthage](https://github.com/Carthage/Carthage) is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods. To install with carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage) #### Cartfile ``` github "rs/SDWebImage" ``` ### Installation by cloning the repository - see [Manual install](Docs/ManualInstallation.md) ### Import headers in your source files In the source files where you need to use the library, import the header file: ```objective-c #import ``` ### Build Project At this point your workspace should build without error. If you are having problem, post to the Issue and the community can help you solve it. ## Author - [Olivier Poitrey](https://github.com/rs) ## Collaborators - [Konstantinos K.](https://github.com/mythodeia) - [Bogdan Poplauschi](https://github.com/bpoplauschi) - [Chester Liu](https://github.com/skyline75489) - [DreamPiggy](https://github.com/dreampiggy) ## Licenses All source code is licensed under the [MIT License](https://raw.github.com/rs/SDWebImage/master/LICENSE). ## Architecture

================================================ FILE: Example/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * (c) Fabrice Aneche * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #import "SDWebImageCompat.h" typedef NS_ENUM(NSInteger, SDImageFormat) { SDImageFormatUndefined = -1, SDImageFormatJPEG = 0, SDImageFormatPNG, SDImageFormatGIF, SDImageFormatTIFF, SDImageFormatWebP }; @interface NSData (ImageContentType) /** * Return image format * * @param data the input image data * * @return the image format as `SDImageFormat` (enum) */ + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * (c) Fabrice Aneche * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "NSData+ImageContentType.h" @implementation NSData (ImageContentType) + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data { if (!data) { return SDImageFormatUndefined; } uint8_t c; [data getBytes:&c length:1]; switch (c) { case 0xFF: return SDImageFormatJPEG; case 0x89: return SDImageFormatPNG; case 0x47: return SDImageFormatGIF; case 0x49: case 0x4D: return SDImageFormatTIFF; case 0x52: // R as RIFF for WEBP if (data.length < 12) { return SDImageFormatUndefined; } NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { return SDImageFormatWebP; } } return SDImageFormatUndefined; } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/NSImage+WebCache.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #if SD_MAC #import @interface NSImage (WebCache) - (CGImageRef)CGImage; - (NSArray *)images; - (BOOL)isGIF; @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/NSImage+WebCache.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "NSImage+WebCache.h" #if SD_MAC @implementation NSImage (WebCache) - (CGImageRef)CGImage { NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil]; return cgImage; } - (NSArray *)images { return nil; } - (BOOL)isGIF { return NO; } @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDImageCache.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #import "SDWebImageCompat.h" #import "SDImageCacheConfig.h" typedef NS_ENUM(NSInteger, SDImageCacheType) { /** * The image wasn't available the SDWebImage caches, but was downloaded from the web. */ SDImageCacheTypeNone, /** * The image was obtained from the disk cache. */ SDImageCacheTypeDisk, /** * The image was obtained from the memory cache. */ SDImageCacheTypeMemory }; typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); /** * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed * asynchronous so it doesn’t add unnecessary latency to the UI. */ @interface SDImageCache : NSObject #pragma mark - Properties /** * Cache Config object - storing all kind of settings */ @property (nonatomic, nonnull, readonly) SDImageCacheConfig *config; /** * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. */ @property (assign, nonatomic) NSUInteger maxMemoryCost; /** * The maximum number of objects the cache should hold. */ @property (assign, nonatomic) NSUInteger maxMemoryCountLimit; #pragma mark - Singleton and initialization /** * Returns global shared cache instance * * @return SDImageCache global instance */ + (nonnull instancetype)sharedImageCache; /** * Init a new cache store with a specific namespace * * @param ns The namespace to use for this cache store */ - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns; /** * Init a new cache store with a specific namespace and directory * * @param ns The namespace to use for this cache store * @param directory Directory to cache disk images in */ - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory NS_DESIGNATED_INITIALIZER; #pragma mark - Cache paths - (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace; /** * Add a read-only cache path to search for images pre-cached by SDImageCache * Useful if you want to bundle pre-loaded images with your app * * @param path The path to use for this read-only cache path */ - (void)addReadOnlyCachePath:(nonnull NSString *)path; #pragma mark - Store Ops /** * Asynchronously store an image into memory and disk cache at the given key. * * @param image The image to store * @param key The unique image cache key, usually it's image absolute URL * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. * * @param image The image to store * @param key The unique image cache key, usually it's image absolute URL * @param toDisk Store the image to disk cache if YES * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Asynchronously store an image into memory and disk cache at the given key. * * @param image The image to store * @param imageData The image data as returned by the server, this representation will be used for disk storage * instead of converting the given image object into a storable/compressed image format in order * to save quality and CPU * @param key The unique image cache key, usually it's image absolute URL * @param toDisk Store the image to disk cache if YES * @param completionBlock A block executed after the operation is finished */ - (void)storeImage:(nullable UIImage *)image imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock; /** * Synchronously store image NSData into disk cache at the given key. * * @warning This method is synchronous, make sure to call it from the ioQueue * * @param imageData The image data to store * @param key The unique image cache key, usually it's image absolute URL */ - (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key; #pragma mark - Query and Retrieve Ops /** * Async check if image exists in disk cache already (does not load the image) * * @param key the key describing the url * @param completionBlock the block to be executed when the check is done. * @note the completion block will be always executed on the main queue */ - (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; /** * Operation that queries the cache asynchronously and call the completion when done. * * @param key The unique key used to store the wanted image * @param doneBlock The completion block. Will not get called if the operation is cancelled * * @return a NSOperation instance containing the cache op */ - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock; /** * Query the memory cache synchronously. * * @param key The unique key used to store the image */ - (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key; /** * Query the disk cache synchronously. * * @param key The unique key used to store the image */ - (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key; /** * Query the cache (memory and or disk) synchronously after checking the memory cache. * * @param key The unique key used to store the image */ - (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key; #pragma mark - Remove Ops /** * Remove the image from memory and disk cache asynchronously * * @param key The unique image cache key * @param completion A block that should be executed after the image has been removed (optional) */ - (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion; /** * Remove the image from memory and optionally disk cache asynchronously * * @param key The unique image cache key * @param fromDisk Also remove cache entry from disk if YES * @param completion A block that should be executed after the image has been removed (optional) */ - (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion; #pragma mark - Cache clean Ops /** * Clear all memory cached images */ - (void)clearMemory; /** * Async clear all disk cached images. Non-blocking method - returns immediately. * @param completion A block that should be executed after cache expiration completes (optional) */ - (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion; /** * Async remove all expired cached image from disk. Non-blocking method - returns immediately. * @param completionBlock A block that should be executed after cache expiration completes (optional) */ - (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock; #pragma mark - Cache Info /** * Get the size used by the disk cache */ - (NSUInteger)getSize; /** * Get the number of images in the disk cache */ - (NSUInteger)getDiskCount; /** * Asynchronously calculate the disk cache's size. */ - (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock; #pragma mark - Cache Paths /** * Get the cache path for a certain key (needs the cache path root folder) * * @param key the key (can be obtained from url using cacheKeyForURL) * @param path the cache path root folder * * @return the cache path */ - (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path; /** * Get the default cache path for a certain key * * @param key the key (can be obtained from url using cacheKeyForURL) * * @return the default cache path */ - (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDImageCache.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDImageCache.h" #import "SDWebImageDecoder.h" #import "UIImage+MultiFormat.h" #import #import "UIImage+GIF.h" #import "NSData+ImageContentType.h" #import "NSImage+WebCache.h" // See https://github.com/rs/SDWebImage/pull/1141 for discussion @interface AutoPurgeCache : NSCache @end @implementation AutoPurgeCache - (nonnull instancetype)init { self = [super init]; if (self) { #if SD_UIKIT [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif } return self; } - (void)dealloc { #if SD_UIKIT [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; #endif } @end FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { #if SD_MAC return image.size.height * image.size.width; #elif SD_UIKIT || SD_WATCH return image.size.height * image.size.width * image.scale * image.scale; #endif } @interface SDImageCache () #pragma mark - Properties @property (strong, nonatomic, nonnull) NSCache *memCache; @property (strong, nonatomic, nonnull) NSString *diskCachePath; @property (strong, nonatomic, nullable) NSMutableArray *customPaths; @property (SDDispatchQueueSetterSementics, nonatomic, nullable) dispatch_queue_t ioQueue; @end @implementation SDImageCache { NSFileManager *_fileManager; } #pragma mark - Singleton, init, dealloc + (nonnull instancetype)sharedImageCache { static dispatch_once_t once; static id instance; dispatch_once(&once, ^{ instance = [self new]; }); return instance; } - (instancetype)init { return [self initWithNamespace:@"default"]; } - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns { NSString *path = [self makeDiskCachePath:ns]; return [self initWithNamespace:ns diskCacheDirectory:path]; } - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory { if ((self = [super init])) { NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns]; // Create IO serial queue _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL); _config = [[SDImageCacheConfig alloc] init]; // Init the memory cache _memCache = [[AutoPurgeCache alloc] init]; _memCache.name = fullNamespace; // Init the disk cache if (directory != nil) { _diskCachePath = [directory stringByAppendingPathComponent:fullNamespace]; } else { NSString *path = [self makeDiskCachePath:ns]; _diskCachePath = path; } dispatch_sync(_ioQueue, ^{ _fileManager = [NSFileManager new]; }); #if SD_UIKIT // Subscribe to app events [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearMemory) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deleteOldFiles) name:UIApplicationWillTerminateNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundDeleteOldFiles) name:UIApplicationDidEnterBackgroundNotification object:nil]; #endif } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; SDDispatchQueueRelease(_ioQueue); } - (void)checkIfQueueIsIOQueue { const char *currentQueueLabel = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); const char *ioQueueLabel = dispatch_queue_get_label(self.ioQueue); if (strcmp(currentQueueLabel, ioQueueLabel) != 0) { NSLog(@"This method should be called from the ioQueue"); } } #pragma mark - Cache paths - (void)addReadOnlyCachePath:(nonnull NSString *)path { if (!self.customPaths) { self.customPaths = [NSMutableArray new]; } if (![self.customPaths containsObject:path]) { [self.customPaths addObject:path]; } } - (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path { NSString *filename = [self cachedFileNameForKey:key]; return [path stringByAppendingPathComponent:filename]; } - (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key { return [self cachePathForKey:key inPath:self.diskCachePath]; } - (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key { const char *str = key.UTF8String; if (str == NULL) { str = ""; } unsigned char r[CC_MD5_DIGEST_LENGTH]; CC_MD5(str, (CC_LONG)strlen(str), r); NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15], [key.pathExtension isEqualToString:@""] ? @"" : [NSString stringWithFormat:@".%@", key.pathExtension]]; return filename; } - (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); return [paths[0] stringByAppendingPathComponent:fullNamespace]; } #pragma mark - Store Ops - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key completion:(nullable SDWebImageNoParamsBlock)completionBlock { [self storeImage:image imageData:nil forKey:key toDisk:YES completion:completionBlock]; } - (void)storeImage:(nullable UIImage *)image forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock { [self storeImage:image imageData:nil forKey:key toDisk:toDisk completion:completionBlock]; } - (void)storeImage:(nullable UIImage *)image imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock { if (!image || !key) { if (completionBlock) { completionBlock(); } return; } // if memory cache is enabled if (self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDCacheCostForImage(image); [self.memCache setObject:image forKey:key cost:cost]; } if (toDisk) { dispatch_async(self.ioQueue, ^{ @autoreleasepool { NSData *data = imageData; if (!data && image) { SDImageFormat imageFormatFromData = [NSData sd_imageFormatForImageData:data]; data = [image sd_imageDataAsFormat:imageFormatFromData]; } [self storeImageDataToDisk:data forKey:key]; } if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(); }); } }); } else { if (completionBlock) { completionBlock(); } } } - (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key { if (!imageData || !key) { return; } [self checkIfQueueIsIOQueue]; if (![_fileManager fileExistsAtPath:_diskCachePath]) { [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; } // get cache Path for image key NSString *cachePathForKey = [self defaultCachePathForKey:key]; // transform to NSUrl NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; [_fileManager createFileAtPath:cachePathForKey contents:imageData attributes:nil]; // disable iCloud backup if (self.config.shouldDisableiCloud) { [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; } } #pragma mark - Query and Retrieve Ops - (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { dispatch_async(_ioQueue, ^{ BOOL exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key]]; // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name // checking the key with and without the extension if (!exists) { exists = [_fileManager fileExistsAtPath:[self defaultCachePathForKey:key].stringByDeletingPathExtension]; } if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(exists); }); } }); } - (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key { return [self.memCache objectForKey:key]; } - (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key { UIImage *diskImage = [self diskImageForKey:key]; if (diskImage && self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDCacheCostForImage(diskImage); [self.memCache setObject:diskImage forKey:key cost:cost]; } return diskImage; } - (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key { // First check the in-memory cache... UIImage *image = [self imageFromMemoryCacheForKey:key]; if (image) { return image; } // Second check the disk cache... image = [self imageFromDiskCacheForKey:key]; return image; } - (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key { NSString *defaultPath = [self defaultCachePathForKey:key]; NSData *data = [NSData dataWithContentsOfFile:defaultPath]; if (data) { return data; } // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name // checking the key with and without the extension data = [NSData dataWithContentsOfFile:defaultPath.stringByDeletingPathExtension]; if (data) { return data; } NSArray *customPaths = [self.customPaths copy]; for (NSString *path in customPaths) { NSString *filePath = [self cachePathForKey:key inPath:path]; NSData *imageData = [NSData dataWithContentsOfFile:filePath]; if (imageData) { return imageData; } // fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name // checking the key with and without the extension imageData = [NSData dataWithContentsOfFile:filePath.stringByDeletingPathExtension]; if (imageData) { return imageData; } } return nil; } - (nullable UIImage *)diskImageForKey:(nullable NSString *)key { NSData *data = [self diskImageDataBySearchingAllPathsForKey:key]; if (data) { UIImage *image = [UIImage sd_imageWithData:data]; image = [self scaledImageForKey:key image:image]; #ifdef SD_WEBP SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data]; if (imageFormat == SDImageFormatWebP) { return image; } #endif if (self.config.shouldDecompressImages) { image = [UIImage decodedImageWithImage:image]; } return image; } else { return nil; } } - (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { return SDScaledImageForKey(key, image); } - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock { if (!key) { if (doneBlock) { doneBlock(nil, nil, SDImageCacheTypeNone); } return nil; } // First check the in-memory cache... UIImage *image = [self imageFromMemoryCacheForKey:key]; if (image) { NSData *diskData = nil; if ([image isGIF]) { diskData = [self diskImageDataBySearchingAllPathsForKey:key]; } if (doneBlock) { doneBlock(image, diskData, SDImageCacheTypeMemory); } return nil; } NSOperation *operation = [NSOperation new]; dispatch_async(self.ioQueue, ^{ if (operation.isCancelled) { // do not call the completion if cancelled return; } @autoreleasepool { NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key]; UIImage *diskImage = [self diskImageForKey:key]; if (diskImage && self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDCacheCostForImage(diskImage); [self.memCache setObject:diskImage forKey:key cost:cost]; } if (doneBlock) { dispatch_async(dispatch_get_main_queue(), ^{ doneBlock(diskImage, diskData, SDImageCacheTypeDisk); }); } } }); return operation; } #pragma mark - Remove Ops - (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion { [self removeImageForKey:key fromDisk:YES withCompletion:completion]; } - (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion { if (key == nil) { return; } if (self.config.shouldCacheImagesInMemory) { [self.memCache removeObjectForKey:key]; } if (fromDisk) { dispatch_async(self.ioQueue, ^{ [_fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; if (completion) { dispatch_async(dispatch_get_main_queue(), ^{ completion(); }); } }); } else if (completion){ completion(); } } # pragma mark - Mem Cache settings - (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost { self.memCache.totalCostLimit = maxMemoryCost; } - (NSUInteger)maxMemoryCost { return self.memCache.totalCostLimit; } - (NSUInteger)maxMemoryCountLimit { return self.memCache.countLimit; } - (void)setMaxMemoryCountLimit:(NSUInteger)maxCountLimit { self.memCache.countLimit = maxCountLimit; } #pragma mark - Cache clean Ops - (void)clearMemory { [self.memCache removeAllObjects]; } - (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion { dispatch_async(self.ioQueue, ^{ [_fileManager removeItemAtPath:self.diskCachePath error:nil]; [_fileManager createDirectoryAtPath:self.diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; if (completion) { dispatch_async(dispatch_get_main_queue(), ^{ completion(); }); } }); } - (void)deleteOldFiles { [self deleteOldFilesWithCompletionBlock:nil]; } - (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock { dispatch_async(self.ioQueue, ^{ NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; NSArray *resourceKeys = @[NSURLIsDirectoryKey, NSURLContentModificationDateKey, NSURLTotalFileAllocatedSizeKey]; // This enumerator prefetches useful properties for our cache files. NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL includingPropertiesForKeys:resourceKeys options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:NULL]; NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; NSMutableDictionary *> *cacheFiles = [NSMutableDictionary dictionary]; NSUInteger currentCacheSize = 0; // Enumerate all of the files in the cache directory. This loop has two purposes: // // 1. Removing files that are older than the expiration date. // 2. Storing file attributes for the size-based cleanup pass. NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init]; for (NSURL *fileURL in fileEnumerator) { NSError *error; NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:&error]; // Skip directories and errors. if (error || !resourceValues || [resourceValues[NSURLIsDirectoryKey] boolValue]) { continue; } // Remove files that are older than the expiration date; NSDate *modificationDate = resourceValues[NSURLContentModificationDateKey]; if ([[modificationDate laterDate:expirationDate] isEqualToDate:expirationDate]) { [urlsToDelete addObject:fileURL]; continue; } // Store a reference to this file and account for its total size. NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; currentCacheSize += totalAllocatedSize.unsignedIntegerValue; cacheFiles[fileURL] = resourceValues; } for (NSURL *fileURL in urlsToDelete) { [_fileManager removeItemAtURL:fileURL error:nil]; } // If our remaining disk cache exceeds a configured maximum size, perform a second // size-based cleanup pass. We delete the oldest files first. if (self.config.maxCacheSize > 0 && currentCacheSize > self.config.maxCacheSize) { // Target half of our maximum cache size for this cleanup pass. const NSUInteger desiredCacheSize = self.config.maxCacheSize / 2; // Sort the remaining cache files by their last modification time (oldest first). NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent usingComparator:^NSComparisonResult(id obj1, id obj2) { return [obj1[NSURLContentModificationDateKey] compare:obj2[NSURLContentModificationDateKey]]; }]; // Delete files until we fall below our desired cache size. for (NSURL *fileURL in sortedFiles) { if ([_fileManager removeItemAtURL:fileURL error:nil]) { NSDictionary *resourceValues = cacheFiles[fileURL]; NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; currentCacheSize -= totalAllocatedSize.unsignedIntegerValue; if (currentCacheSize < desiredCacheSize) { break; } } } } if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(); }); } }); } #if SD_UIKIT - (void)backgroundDeleteOldFiles { Class UIApplicationClass = NSClassFromString(@"UIApplication"); if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) { return; } UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)]; __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ // Clean up any unfinished task business by marking where you // stopped or ending the task outright. [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; // Start the long-running task and return immediately. [self deleteOldFilesWithCompletionBlock:^{ [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; } #endif #pragma mark - Cache Info - (NSUInteger)getSize { __block NSUInteger size = 0; dispatch_sync(self.ioQueue, ^{ NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath]; for (NSString *fileName in fileEnumerator) { NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName]; NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; size += [attrs fileSize]; } }); return size; } - (NSUInteger)getDiskCount { __block NSUInteger count = 0; dispatch_sync(self.ioQueue, ^{ NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtPath:self.diskCachePath]; count = fileEnumerator.allObjects.count; }); return count; } - (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock { NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; dispatch_async(self.ioQueue, ^{ NSUInteger fileCount = 0; NSUInteger totalSize = 0; NSDirectoryEnumerator *fileEnumerator = [_fileManager enumeratorAtURL:diskCacheURL includingPropertiesForKeys:@[NSFileSize] options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:NULL]; for (NSURL *fileURL in fileEnumerator) { NSNumber *fileSize; [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL]; totalSize += fileSize.unsignedIntegerValue; fileCount += 1; } if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(fileCount, totalSize); }); } }); } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #import "SDWebImageCompat.h" @interface SDImageCacheConfig : NSObject /** * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. */ @property (assign, nonatomic) BOOL shouldDecompressImages; /** * disable iCloud backup [defaults to YES] */ @property (assign, nonatomic) BOOL shouldDisableiCloud; /** * use memory cache [defaults to YES] */ @property (assign, nonatomic) BOOL shouldCacheImagesInMemory; /** * The maximum length of time to keep an image in the cache, in seconds */ @property (assign, nonatomic) NSInteger maxCacheAge; /** * The maximum size of the cache, in bytes. */ @property (assign, nonatomic) NSUInteger maxCacheSize; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDImageCacheConfig.h" static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week @implementation SDImageCacheConfig - (instancetype)init { if (self = [super init]) { _shouldDecompressImages = YES; _shouldDisableiCloud = YES; _shouldCacheImagesInMemory = YES; _maxCacheAge = kDefaultCacheMaxCacheAge; _maxCacheSize = 0; } return self; } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageCompat.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * (c) Jamie Pinkham * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #ifdef __OBJC_GC__ #error SDWebImage does not support Objective-C Garbage Collection #endif // Apple's defines from TargetConditionals.h are a bit weird. // Seems like TARGET_OS_MAC is always defined (on all platforms). // To determine if we are running on OSX, we can only rely on TARGET_OS_IPHONE=0 and all the other platforms #if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH #define SD_MAC 1 #else #define SD_MAC 0 #endif // iOS and tvOS are very similar, UIKit exists on both platforms // Note: watchOS also has UIKit, but it's very limited #if TARGET_OS_IOS || TARGET_OS_TV #define SD_UIKIT 1 #else #define SD_UIKIT 0 #endif #if TARGET_OS_IOS #define SD_IOS 1 #else #define SD_IOS 0 #endif #if TARGET_OS_TV #define SD_TV 1 #else #define SD_TV 0 #endif #if TARGET_OS_WATCH #define SD_WATCH 1 #else #define SD_WATCH 0 #endif #if SD_MAC #import #ifndef UIImage #define UIImage NSImage #endif #ifndef UIImageView #define UIImageView NSImageView #endif #ifndef UIView #define UIView NSView #endif #else #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 #error SDWebImage doesn't support Deployment Target version < 5.0 #endif #if SD_UIKIT #import #endif #if SD_WATCH #import #endif #endif #ifndef NS_ENUM #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type #endif #ifndef NS_OPTIONS #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type #endif #if OS_OBJECT_USE_OBJC #undef SDDispatchQueueRelease #undef SDDispatchQueueSetterSementics #define SDDispatchQueueRelease(q) #define SDDispatchQueueSetterSementics strong #else #undef SDDispatchQueueRelease #undef SDDispatchQueueSetterSementics #define SDDispatchQueueRelease(q) (dispatch_release(q)) #define SDDispatchQueueSetterSementics assign #endif FOUNDATION_EXPORT UIImage *SDScaledImageForKey(NSString *key, UIImage *image); typedef void(^SDWebImageNoParamsBlock)(void); FOUNDATION_EXPORT NSString *const SDWebImageErrorDomain; #ifndef dispatch_main_async_safe #define dispatch_main_async_safe(block)\ if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\ block();\ } else {\ dispatch_async(dispatch_get_main_queue(), block);\ } #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageCompat.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #import "objc/runtime.h" #if !__has_feature(objc_arc) #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag #endif inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) { if (!image) { return nil; } #if SD_MAC return image; #elif SD_UIKIT || SD_WATCH if ((image.images).count > 0) { NSMutableArray *scaledImages = [NSMutableArray array]; for (UIImage *tempImage in image.images) { [scaledImages addObject:SDScaledImageForKey(key, tempImage)]; } UIImage *animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration]; #ifdef SD_WEBP if (animatedImage) { SEL sd_webpLoopCount = NSSelectorFromString(@"sd_webpLoopCount"); NSNumber *value = objc_getAssociatedObject(image, sd_webpLoopCount); NSInteger loopCount = value.integerValue; if (loopCount) { objc_setAssociatedObject(animatedImage, sd_webpLoopCount, @(loopCount), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } #endif return animatedImage; } else { #if SD_WATCH if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) { #elif SD_UIKIT if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { #endif CGFloat scale = 1; if (key.length >= 8) { NSRange range = [key rangeOfString:@"@2x."]; if (range.location != NSNotFound) { scale = 2.0; } range = [key rangeOfString:@"@3x."]; if (range.location != NSNotFound) { scale = 3.0; } } UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; image = scaledImage; } return image; } #endif } NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain"; ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * (c) james * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #import "SDWebImageCompat.h" @interface UIImage (ForceDecode) + (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image; + (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageDecoder.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * (c) james * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageDecoder.h" @implementation UIImage (ForceDecode) #if SD_UIKIT || SD_WATCH static const size_t kBytesPerPixel = 4; static const size_t kBitsPerComponent = 8; + (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image { if (![UIImage shouldDecodeImage:image]) { return image; } // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; @autoreleasepool{ CGImageRef imageRef = image.CGImage; CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:imageRef]; size_t width = CGImageGetWidth(imageRef); size_t height = CGImageGetHeight(imageRef); size_t bytesPerRow = kBytesPerPixel * width; // kCGImageAlphaNone is not supported in CGBitmapContextCreate. // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast // to create bitmap graphics contexts without alpha info. CGContextRef context = CGBitmapContextCreate(NULL, width, height, kBitsPerComponent, bytesPerRow, colorspaceRef, kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast); if (context == NULL) { return image; } // Draw the image into the context and retrieve the new bitmap image without alpha CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context); UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha scale:image.scale orientation:image.imageOrientation]; CGContextRelease(context); CGImageRelease(imageRefWithoutAlpha); return imageWithoutAlpha; } } /* * Defines the maximum size in MB of the decoded image when the flag `SDWebImageScaleDownLargeImages` is set * Suggested value for iPad1 and iPhone 3GS: 60. * Suggested value for iPad2 and iPhone 4: 120. * Suggested value for iPhone 3G and iPod 2 and earlier devices: 30. */ static const CGFloat kDestImageSizeMB = 60.0f; /* * Defines the maximum size in MB of a tile used to decode image when the flag `SDWebImageScaleDownLargeImages` is set * Suggested value for iPad1 and iPhone 3GS: 20. * Suggested value for iPad2 and iPhone 4: 40. * Suggested value for iPhone 3G and iPod 2 and earlier devices: 10. */ static const CGFloat kSourceImageTileSizeMB = 20.0f; static const CGFloat kBytesPerMB = 1024.0f * 1024.0f; static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel; static const CGFloat kDestTotalPixels = kDestImageSizeMB * kPixelsPerMB; static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB; static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to overlap the seems where tiles meet. + (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image { if (![UIImage shouldDecodeImage:image]) { return image; } if (![UIImage shouldScaleDownImage:image]) { return [UIImage decodedImageWithImage:image]; } CGContextRef destContext; // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; @autoreleasepool { CGImageRef sourceImageRef = image.CGImage; CGSize sourceResolution = CGSizeZero; sourceResolution.width = CGImageGetWidth(sourceImageRef); sourceResolution.height = CGImageGetHeight(sourceImageRef); float sourceTotalPixels = sourceResolution.width * sourceResolution.height; // Determine the scale ratio to apply to the input image // that results in an output image of the defined size. // see kDestImageSizeMB, and how it relates to destTotalPixels. float imageScale = kDestTotalPixels / sourceTotalPixels; CGSize destResolution = CGSizeZero; destResolution.width = (int)(sourceResolution.width*imageScale); destResolution.height = (int)(sourceResolution.height*imageScale); // current color space CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:sourceImageRef]; size_t bytesPerRow = kBytesPerPixel * destResolution.width; // kCGImageAlphaNone is not supported in CGBitmapContextCreate. // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast // to create bitmap graphics contexts without alpha info. destContext = CGBitmapContextCreate(NULL, destResolution.width, destResolution.height, kBitsPerComponent, bytesPerRow, colorspaceRef, kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast); if (destContext == NULL) { return image; } CGContextSetInterpolationQuality(destContext, kCGInterpolationHigh); // Now define the size of the rectangle to be used for the // incremental blits from the input image to the output image. // we use a source tile width equal to the width of the source // image due to the way that iOS retrieves image data from disk. // iOS must decode an image from disk in full width 'bands', even // if current graphics context is clipped to a subrect within that // band. Therefore we fully utilize all of the pixel data that results // from a decoding opertion by achnoring our tile size to the full // width of the input image. CGRect sourceTile = CGRectZero; sourceTile.size.width = sourceResolution.width; // The source tile height is dynamic. Since we specified the size // of the source tile in MB, see how many rows of pixels high it // can be given the input image width. sourceTile.size.height = (int)(kTileTotalPixels / sourceTile.size.width ); sourceTile.origin.x = 0.0f; // The output tile is the same proportions as the input tile, but // scaled to image scale. CGRect destTile; destTile.size.width = destResolution.width; destTile.size.height = sourceTile.size.height * imageScale; destTile.origin.x = 0.0f; // The source seem overlap is proportionate to the destination seem overlap. // this is the amount of pixels to overlap each tile as we assemble the ouput image. float sourceSeemOverlap = (int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height); CGImageRef sourceTileImageRef; // calculate the number of read/write operations required to assemble the // output image. int iterations = (int)( sourceResolution.height / sourceTile.size.height ); // If tile height doesn't divide the image height evenly, add another iteration // to account for the remaining pixels. int remainder = (int)sourceResolution.height % (int)sourceTile.size.height; if(remainder) { iterations++; } // Add seem overlaps to the tiles, but save the original tile height for y coordinate calculations. float sourceTileHeightMinusOverlap = sourceTile.size.height; sourceTile.size.height += sourceSeemOverlap; destTile.size.height += kDestSeemOverlap; for( int y = 0; y < iterations; ++y ) { @autoreleasepool { sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap; destTile.origin.y = destResolution.height - (( y + 1 ) * sourceTileHeightMinusOverlap * imageScale + kDestSeemOverlap); sourceTileImageRef = CGImageCreateWithImageInRect( sourceImageRef, sourceTile ); if( y == iterations - 1 && remainder ) { float dify = destTile.size.height; destTile.size.height = CGImageGetHeight( sourceTileImageRef ) * imageScale; dify -= destTile.size.height; destTile.origin.y += dify; } CGContextDrawImage( destContext, destTile, sourceTileImageRef ); CGImageRelease( sourceTileImageRef ); } } CGImageRef destImageRef = CGBitmapContextCreateImage(destContext); CGContextRelease(destContext); if (destImageRef == NULL) { return image; } UIImage *destImage = [UIImage imageWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation]; CGImageRelease(destImageRef); if (destImage == nil) { return image; } return destImage; } } + (BOOL)shouldDecodeImage:(nullable UIImage *)image { // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error if (image == nil) { return NO; } // do not decode animated images if (image.images != nil) { return NO; } CGImageRef imageRef = image.CGImage; CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef); BOOL anyAlpha = (alpha == kCGImageAlphaFirst || alpha == kCGImageAlphaLast || alpha == kCGImageAlphaPremultipliedFirst || alpha == kCGImageAlphaPremultipliedLast); // do not decode images with alpha if (anyAlpha) { return NO; } return YES; } + (BOOL)shouldScaleDownImage:(nonnull UIImage *)image { BOOL shouldScaleDown = YES; CGImageRef sourceImageRef = image.CGImage; CGSize sourceResolution = CGSizeZero; sourceResolution.width = CGImageGetWidth(sourceImageRef); sourceResolution.height = CGImageGetHeight(sourceImageRef); float sourceTotalPixels = sourceResolution.width * sourceResolution.height; float imageScale = kDestTotalPixels / sourceTotalPixels; if (imageScale < 1) { shouldScaleDown = YES; } else { shouldScaleDown = NO; } return shouldScaleDown; } + (CGColorSpaceRef)colorSpaceForImageRef:(CGImageRef)imageRef { // current CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef)); CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef); BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown || imageColorSpaceModel == kCGColorSpaceModelMonochrome || imageColorSpaceModel == kCGColorSpaceModelCMYK || imageColorSpaceModel == kCGColorSpaceModelIndexed); if (unsupportedColorSpace) { colorspaceRef = CGColorSpaceCreateDeviceRGB(); CFAutorelease(colorspaceRef); } return colorspaceRef; } #elif SD_MAC + (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image { return image; } + (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image { return image; } #endif @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #import "SDWebImageCompat.h" #import "SDWebImageOperation.h" typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { SDWebImageDownloaderLowPriority = 1 << 0, SDWebImageDownloaderProgressiveDownload = 1 << 1, /** * By default, request prevent the use of NSURLCache. With this flag, NSURLCache * is used with default policies. */ SDWebImageDownloaderUseNSURLCache = 1 << 2, /** * Call completion block with nil image/imageData if the image was read from NSURLCache * (to be combined with `SDWebImageDownloaderUseNSURLCache`). */ SDWebImageDownloaderIgnoreCachedResponse = 1 << 3, /** * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for * extra time in background to let the request finish. If the background task expires the operation will be cancelled. */ SDWebImageDownloaderContinueInBackground = 1 << 4, /** * Handles cookies stored in NSHTTPCookieStore by setting * NSMutableURLRequest.HTTPShouldHandleCookies = YES; */ SDWebImageDownloaderHandleCookies = 1 << 5, /** * Enable to allow untrusted SSL certificates. * Useful for testing purposes. Use with caution in production. */ SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6, /** * Put the image in the high priority queue. */ SDWebImageDownloaderHighPriority = 1 << 7, /** * Scale down the image */ SDWebImageDownloaderScaleDownLargeImages = 1 << 8, }; typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { /** * Default value. All download operations will execute in queue style (first-in-first-out). */ SDWebImageDownloaderFIFOExecutionOrder, /** * All download operations will execute in stack style (last-in-first-out). */ SDWebImageDownloaderLIFOExecutionOrder }; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); typedef NSDictionary SDHTTPHeadersDictionary; typedef NSMutableDictionary SDHTTPHeadersMutableDictionary; typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers); /** * A token associated with each download. Can be used to cancel a download */ @interface SDWebImageDownloadToken : NSObject @property (nonatomic, strong, nullable) NSURL *url; @property (nonatomic, strong, nullable) id downloadOperationCancelToken; @end /** * Asynchronous downloader dedicated and optimized for image loading. */ @interface SDWebImageDownloader : NSObject /** * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. */ @property (assign, nonatomic) BOOL shouldDecompressImages; /** * The maximum number of concurrent downloads */ @property (assign, nonatomic) NSInteger maxConcurrentDownloads; /** * Shows the current amount of downloads that still need to be downloaded */ @property (readonly, nonatomic) NSUInteger currentDownloadCount; /** * The timeout value (in seconds) for the download operation. Default: 15.0. */ @property (assign, nonatomic) NSTimeInterval downloadTimeout; /** * The configuration in use by the internal NSURLSession. * Mutating this object directly has no effect. * * @see createNewSessionWithConfiguration: */ @property (readonly, nonatomic, nonnull) NSURLSessionConfiguration *sessionConfiguration; /** * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. */ @property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder; /** * Singleton method, returns the shared instance * * @return global shared instance of downloader class */ + (nonnull instancetype)sharedDownloader; /** * Set the default URL credential to be set for request operations. */ @property (strong, nonatomic, nullable) NSURLCredential *urlCredential; /** * Set username */ @property (strong, nonatomic, nullable) NSString *username; /** * Set password */ @property (strong, nonatomic, nullable) NSString *password; /** * Set filter to pick headers for downloading image HTTP request. * * This block will be invoked for each downloading image request, returned * NSDictionary will be used as headers in corresponding HTTP request. */ @property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter; /** * Creates an instance of a downloader with specified session configuration. * *Note*: `timeoutIntervalForRequest` is going to be overwritten. * @return new instance of downloader class */ - (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER; /** * Set a value for a HTTP header to be appended to each download HTTP request. * * @param value The value for the header field. Use `nil` value to remove the header. * @param field The name of the header field to set. */ - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field; /** * Returns the value of the specified HTTP header field. * * @return The value associated with the header field field, or `nil` if there is no corresponding header field. */ - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field; /** * Sets a subclass of `SDWebImageDownloaderOperation` as the default * `NSOperation` to be used each time SDWebImage constructs a request * operation to download an image. * * @param operationClass The subclass of `SDWebImageDownloaderOperation` to set * as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. */ - (void)setOperationClass:(nullable Class)operationClass; /** * Creates a SDWebImageDownloader async downloader instance with a given URL * * The delegate will be informed when the image is finish downloaded or an error has happen. * * @see SDWebImageDownloaderDelegate * * @param url The URL to the image to download * @param options The options to be used for this download * @param progressBlock A block called repeatedly while the image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called once the download is completed. * If the download succeeded, the image parameter is set, in case of error, * error parameter is set with the error. The last parameter is always YES * if SDWebImageDownloaderProgressiveDownload isn't use. With the * SDWebImageDownloaderProgressiveDownload option, this block is called * repeatedly with the partial image object and the finished argument set to NO * before to be called a last time with the full image and finished argument * set to YES. In case of error, the finished argument is always YES. * * @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation */ - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; /** * Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed: * * @param token The token received from -downloadImageWithURL:options:progress:completed: that should be canceled. */ - (void)cancel:(nullable SDWebImageDownloadToken *)token; /** * Sets the download queue suspension state */ - (void)setSuspended:(BOOL)suspended; /** * Cancels all download operations in the queue */ - (void)cancelAllDownloads; /** * Forces SDWebImageDownloader to create and use a new NSURLSession that is * initialized with the given configuration. * *Note*: All existing download operations in the queue will be cancelled. * *Note*: `timeoutIntervalForRequest` is going to be overwritten. * * @param sessionConfiguration The configuration to use for the new NSURLSession */ - (void)createNewSessionWithConfiguration:(nonnull NSURLSessionConfiguration *)sessionConfiguration; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageDownloader.h" #import "SDWebImageDownloaderOperation.h" @implementation SDWebImageDownloadToken @end @interface SDWebImageDownloader () @property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; @property (weak, nonatomic, nullable) NSOperation *lastAddedOperation; @property (assign, nonatomic, nullable) Class operationClass; @property (strong, nonatomic, nonnull) NSMutableDictionary *URLOperations; @property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders; // This queue is used to serialize the handling of the network responses of all the download operation in a single queue @property (SDDispatchQueueSetterSementics, nonatomic, nullable) dispatch_queue_t barrierQueue; // The session in which data tasks will run @property (strong, nonatomic) NSURLSession *session; @end @implementation SDWebImageDownloader + (void)initialize { // Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator ) // To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import if (NSClassFromString(@"SDNetworkActivityIndicator")) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")]; #pragma clang diagnostic pop // Remove observer in case it was previously added. [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:activityIndicator selector:NSSelectorFromString(@"startActivity") name:SDWebImageDownloadStartNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:activityIndicator selector:NSSelectorFromString(@"stopActivity") name:SDWebImageDownloadStopNotification object:nil]; } } + (nonnull instancetype)sharedDownloader { static dispatch_once_t once; static id instance; dispatch_once(&once, ^{ instance = [self new]; }); return instance; } - (nonnull instancetype)init { return [self initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; } - (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration { if ((self = [super init])) { _operationClass = [SDWebImageDownloaderOperation class]; _shouldDecompressImages = YES; _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; _downloadQueue = [NSOperationQueue new]; _downloadQueue.maxConcurrentOperationCount = 6; _downloadQueue.name = @"com.hackemist.SDWebImageDownloader"; _URLOperations = [NSMutableDictionary new]; #ifdef SD_WEBP _HTTPHeaders = [@{@"Accept": @"image/webp,image/*;q=0.8"} mutableCopy]; #else _HTTPHeaders = [@{@"Accept": @"image/*;q=0.8"} mutableCopy]; #endif _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderBarrierQueue", DISPATCH_QUEUE_CONCURRENT); _downloadTimeout = 15.0; [self createNewSessionWithConfiguration:sessionConfiguration]; } return self; } - (void)createNewSessionWithConfiguration:(NSURLSessionConfiguration *)sessionConfiguration { [self cancelAllDownloads]; if (self.session) { [self.session invalidateAndCancel]; } sessionConfiguration.timeoutIntervalForRequest = self.downloadTimeout; /** * Create the session for this task * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate * method calls and completion handler calls. */ self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil]; } - (void)dealloc { [self.session invalidateAndCancel]; self.session = nil; [self.downloadQueue cancelAllOperations]; SDDispatchQueueRelease(_barrierQueue); } - (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field { if (value) { self.HTTPHeaders[field] = value; } else { [self.HTTPHeaders removeObjectForKey:field]; } } - (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field { return self.HTTPHeaders[field]; } - (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads { _downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads; } - (NSUInteger)currentDownloadCount { return _downloadQueue.operationCount; } - (NSInteger)maxConcurrentDownloads { return _downloadQueue.maxConcurrentOperationCount; } - (NSURLSessionConfiguration *)sessionConfiguration { return self.session.configuration; } - (void)setOperationClass:(nullable Class)operationClass { if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperationInterface)]) { _operationClass = operationClass; } else { _operationClass = [SDWebImageDownloaderOperation class]; } } - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url options:(SDWebImageDownloaderOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { __weak SDWebImageDownloader *wself = self; return [self addProgressCallback:progressBlock completedBlock:completedBlock forURL:url createCallback:^SDWebImageDownloaderOperation *{ __strong __typeof (wself) sself = wself; NSTimeInterval timeoutInterval = sself.downloadTimeout; if (timeoutInterval == 0.0) { timeoutInterval = 15.0; } // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise NSURLRequestCachePolicy cachePolicy = options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy timeoutInterval:timeoutInterval]; request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); request.HTTPShouldUsePipelining = YES; if (sself.headersFilter) { request.allHTTPHeaderFields = sself.headersFilter(url, [sself.HTTPHeaders copy]); } else { request.allHTTPHeaderFields = sself.HTTPHeaders; } SDWebImageDownloaderOperation *operation = [[sself.operationClass alloc] initWithRequest:request inSession:sself.session options:options]; operation.shouldDecompressImages = sself.shouldDecompressImages; if (sself.urlCredential) { operation.credential = sself.urlCredential; } else if (sself.username && sself.password) { operation.credential = [NSURLCredential credentialWithUser:sself.username password:sself.password persistence:NSURLCredentialPersistenceForSession]; } if (options & SDWebImageDownloaderHighPriority) { operation.queuePriority = NSOperationQueuePriorityHigh; } else if (options & SDWebImageDownloaderLowPriority) { operation.queuePriority = NSOperationQueuePriorityLow; } [sself.downloadQueue addOperation:operation]; if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) { // Emulate LIFO execution order by systematically adding new operations as last operation's dependency [sself.lastAddedOperation addDependency:operation]; sself.lastAddedOperation = operation; } return operation; }]; } - (void)cancel:(nullable SDWebImageDownloadToken *)token { dispatch_barrier_async(self.barrierQueue, ^{ SDWebImageDownloaderOperation *operation = self.URLOperations[token.url]; BOOL canceled = [operation cancel:token.downloadOperationCancelToken]; if (canceled) { [self.URLOperations removeObjectForKey:token.url]; } }); } - (nullable SDWebImageDownloadToken *)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(nullable NSURL *)url createCallback:(SDWebImageDownloaderOperation *(^)(void))createCallback { // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data. if (url == nil) { if (completedBlock != nil) { completedBlock(nil, nil, nil, NO); } return nil; } __block SDWebImageDownloadToken *token = nil; dispatch_barrier_sync(self.barrierQueue, ^{ SDWebImageDownloaderOperation *operation = self.URLOperations[url]; if (!operation) { operation = createCallback(); self.URLOperations[url] = operation; __weak SDWebImageDownloaderOperation *woperation = operation; operation.completionBlock = ^{ dispatch_barrier_sync(self.barrierQueue, ^{ SDWebImageDownloaderOperation *soperation = woperation; if (!soperation) return; if (self.URLOperations[url] == soperation) { [self.URLOperations removeObjectForKey:url]; }; }); }; } id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock]; token = [SDWebImageDownloadToken new]; token.url = url; token.downloadOperationCancelToken = downloadOperationCancelToken; }); return token; } - (void)setSuspended:(BOOL)suspended { self.downloadQueue.suspended = suspended; } - (void)cancelAllDownloads { [self.downloadQueue cancelAllOperations]; } #pragma mark Helper methods - (SDWebImageDownloaderOperation *)operationWithTask:(NSURLSessionTask *)task { SDWebImageDownloaderOperation *returnOperation = nil; for (SDWebImageDownloaderOperation *operation in self.downloadQueue.operations) { if (operation.dataTask.taskIdentifier == task.taskIdentifier) { returnOperation = operation; break; } } return returnOperation; } #pragma mark NSURLSessionDataDelegate - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { // Identify the operation that runs this task and pass it the delegate method SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask]; [dataOperation URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler]; } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // Identify the operation that runs this task and pass it the delegate method SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask]; [dataOperation URLSession:session dataTask:dataTask didReceiveData:data]; } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { // Identify the operation that runs this task and pass it the delegate method SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:dataTask]; [dataOperation URLSession:session dataTask:dataTask willCacheResponse:proposedResponse completionHandler:completionHandler]; } #pragma mark NSURLSessionTaskDelegate - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { // Identify the operation that runs this task and pass it the delegate method SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task]; [dataOperation URLSession:session task:task didCompleteWithError:error]; } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler { completionHandler(request); } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { // Identify the operation that runs this task and pass it the delegate method SDWebImageDownloaderOperation *dataOperation = [self operationWithTask:task]; [dataOperation URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler]; } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #import "SDWebImageDownloader.h" #import "SDWebImageOperation.h" FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadReceiveResponseNotification; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification; /** Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol */ @protocol SDWebImageDownloaderOperationInterface - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request inSession:(nullable NSURLSession *)session options:(SDWebImageDownloaderOptions)options; - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; - (BOOL)shouldDecompressImages; - (void)setShouldDecompressImages:(BOOL)value; - (nullable NSURLCredential *)credential; - (void)setCredential:(nullable NSURLCredential *)value; @end @interface SDWebImageDownloaderOperation : NSOperation /** * The request used by the operation's task. */ @property (strong, nonatomic, readonly, nullable) NSURLRequest *request; /** * The operation's task */ @property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask; @property (assign, nonatomic) BOOL shouldDecompressImages; /** * Was used to determine whether the URL connection should consult the credential storage for authenticating the connection. * @deprecated Not used for a couple of versions */ @property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility"); /** * The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. * * This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. */ @property (nonatomic, strong, nullable) NSURLCredential *credential; /** * The SDWebImageDownloaderOptions for the receiver. */ @property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options; /** * The expected size of data. */ @property (assign, nonatomic) NSInteger expectedSize; /** * The response returned by the operation's connection. */ @property (strong, nonatomic, nullable) NSURLResponse *response; /** * Initializes a `SDWebImageDownloaderOperation` object * * @see SDWebImageDownloaderOperation * * @param request the URL request * @param session the URL session in which this operation will run * @param options downloader options * * @return the initialized instance */ - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request inSession:(nullable NSURLSession *)session options:(SDWebImageDownloaderOptions)options NS_DESIGNATED_INITIALIZER; /** * Adds handlers for progress and completion. Returns a tokent that can be passed to -cancel: to cancel this set of * callbacks. * * @param progressBlock the block executed when a new chunk of data arrives. * @note the progress block is executed on a background queue * @param completedBlock the block executed when the download is done. * @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue * * @return the token to use to cancel this set of handlers */ - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; /** * Cancels a set of callbacks. Once all callbacks are canceled, the operation is cancelled. * * @param token the token representing a set of callbacks to cancel * * @return YES if the operation was stopped because this was the last token to be canceled. NO otherwise. */ - (BOOL)cancel:(nullable id)token; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageDecoder.h" #import "UIImage+MultiFormat.h" #import #import "SDWebImageManager.h" #import "NSImage+WebCache.h" NSString *const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification"; NSString *const SDWebImageDownloadReceiveResponseNotification = @"SDWebImageDownloadReceiveResponseNotification"; NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNotification"; NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinishNotification"; static NSString *const kProgressCallbackKey = @"progress"; static NSString *const kCompletedCallbackKey = @"completed"; typedef NSMutableDictionary SDCallbacksDictionary; @interface SDWebImageDownloaderOperation () @property (strong, nonatomic, nonnull) NSMutableArray *callbackBlocks; @property (assign, nonatomic, getter = isExecuting) BOOL executing; @property (assign, nonatomic, getter = isFinished) BOOL finished; @property (strong, nonatomic, nullable) NSMutableData *imageData; @property (copy, nonatomic, nullable) NSData *cachedData; // This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run // the task associated with this operation @property (weak, nonatomic, nullable) NSURLSession *unownedSession; // This is set if we're using not using an injected NSURLSession. We're responsible of invalidating this one @property (strong, nonatomic, nullable) NSURLSession *ownedSession; @property (strong, nonatomic, readwrite, nullable) NSURLSessionTask *dataTask; @property (SDDispatchQueueSetterSementics, nonatomic, nullable) dispatch_queue_t barrierQueue; #if SD_UIKIT @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId; #endif @end @implementation SDWebImageDownloaderOperation { size_t _width, _height; #if SD_UIKIT || SD_WATCH UIImageOrientation _orientation; #endif CGImageSourceRef _imageSource; } @synthesize executing = _executing; @synthesize finished = _finished; - (nonnull instancetype)init { return [self initWithRequest:nil inSession:nil options:0]; } - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request inSession:(nullable NSURLSession *)session options:(SDWebImageDownloaderOptions)options { if ((self = [super init])) { _request = [request copy]; _shouldDecompressImages = YES; _options = options; _callbackBlocks = [NSMutableArray new]; _executing = NO; _finished = NO; _expectedSize = 0; _unownedSession = session; _barrierQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderOperationBarrierQueue", DISPATCH_QUEUE_CONCURRENT); } return self; } - (void)dealloc { SDDispatchQueueRelease(_barrierQueue); if (_imageSource) { CFRelease(_imageSource); _imageSource = NULL; } } - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { SDCallbacksDictionary *callbacks = [NSMutableDictionary new]; if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy]; if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy]; dispatch_barrier_async(self.barrierQueue, ^{ [self.callbackBlocks addObject:callbacks]; }); return callbacks; } - (nullable NSArray *)callbacksForKey:(NSString *)key { __block NSMutableArray *callbacks = nil; dispatch_sync(self.barrierQueue, ^{ // We need to remove [NSNull null] because there might not always be a progress block for each callback callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy]; [callbacks removeObjectIdenticalTo:[NSNull null]]; }); return [callbacks copy]; // strip mutability here } - (BOOL)cancel:(nullable id)token { __block BOOL shouldCancel = NO; dispatch_barrier_sync(self.barrierQueue, ^{ [self.callbackBlocks removeObjectIdenticalTo:token]; if (self.callbackBlocks.count == 0) { shouldCancel = YES; } }); if (shouldCancel) { [self cancel]; } return shouldCancel; } - (void)start { @synchronized (self) { if (self.isCancelled) { self.finished = YES; [self reset]; return; } #if SD_UIKIT Class UIApplicationClass = NSClassFromString(@"UIApplication"); BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)]; if (hasApplication && [self shouldContinueWhenAppEntersBackground]) { __weak __typeof__ (self) wself = self; UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)]; self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ __strong __typeof (wself) sself = wself; if (sself) { [sself cancel]; [app endBackgroundTask:sself.backgroundTaskId]; sself.backgroundTaskId = UIBackgroundTaskInvalid; } }]; } #endif if (self.options & SDWebImageDownloaderIgnoreCachedResponse) { // Grab the cached data for later check NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request]; if (cachedResponse) { self.cachedData = cachedResponse.data; } } NSURLSession *session = self.unownedSession; if (!self.unownedSession) { NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; sessionConfig.timeoutIntervalForRequest = 15; /** * Create the session for this task * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate * method calls and completion handler calls. */ self.ownedSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; session = self.ownedSession; } self.dataTask = [session dataTaskWithRequest:self.request]; self.executing = YES; } [self.dataTask resume]; if (self.dataTask) { for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { progressBlock(0, NSURLResponseUnknownLength, self.request.URL); } __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:weakSelf]; }); } else { [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}]]; } #if SD_UIKIT Class UIApplicationClass = NSClassFromString(@"UIApplication"); if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) { return; } if (self.backgroundTaskId != UIBackgroundTaskInvalid) { UIApplication * app = [UIApplication performSelector:@selector(sharedApplication)]; [app endBackgroundTask:self.backgroundTaskId]; self.backgroundTaskId = UIBackgroundTaskInvalid; } #endif } - (void)cancel { @synchronized (self) { [self cancelInternal]; } } - (void)cancelInternal { if (self.isFinished) return; [super cancel]; if (self.dataTask) { [self.dataTask cancel]; __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf]; }); // As we cancelled the connection, its callback won't be called and thus won't // maintain the isFinished and isExecuting flags. if (self.isExecuting) self.executing = NO; if (!self.isFinished) self.finished = YES; } [self reset]; } - (void)done { self.finished = YES; self.executing = NO; [self reset]; } - (void)reset { __weak typeof(self) weakSelf = self; dispatch_barrier_async(self.barrierQueue, ^{ [weakSelf.callbackBlocks removeAllObjects]; }); self.dataTask = nil; NSOperationQueue *delegateQueue; if (self.unownedSession) { delegateQueue = self.unownedSession.delegateQueue; } else { delegateQueue = self.ownedSession.delegateQueue; } if (delegateQueue) { NSAssert(delegateQueue.maxConcurrentOperationCount == 1, @"NSURLSession delegate queue should be a serial queue"); [delegateQueue addOperationWithBlock:^{ weakSelf.imageData = nil; }]; } if (self.ownedSession) { [self.ownedSession invalidateAndCancel]; self.ownedSession = nil; } } - (void)setFinished:(BOOL)finished { [self willChangeValueForKey:@"isFinished"]; _finished = finished; [self didChangeValueForKey:@"isFinished"]; } - (void)setExecuting:(BOOL)executing { [self willChangeValueForKey:@"isExecuting"]; _executing = executing; [self didChangeValueForKey:@"isExecuting"]; } - (BOOL)isConcurrent { return YES; } #pragma mark NSURLSessionDataDelegate - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { //'304 Not Modified' is an exceptional one if (![response respondsToSelector:@selector(statusCode)] || (((NSHTTPURLResponse *)response).statusCode < 400 && ((NSHTTPURLResponse *)response).statusCode != 304)) { NSInteger expected = (NSInteger)response.expectedContentLength; expected = expected > 0 ? expected : 0; self.expectedSize = expected; for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { progressBlock(0, expected, self.request.URL); } self.imageData = [[NSMutableData alloc] initWithCapacity:expected]; self.response = response; __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadReceiveResponseNotification object:weakSelf]; }); } else { NSUInteger code = ((NSHTTPURLResponse *)response).statusCode; //This is the case when server returns '304 Not Modified'. It means that remote image is not changed. //In case of 304 we need just cancel the operation and return cached image from the cache. if (code == 304) { [self cancelInternal]; } else { [self.dataTask cancel]; } __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf]; }); [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:((NSHTTPURLResponse *)response).statusCode userInfo:nil]]; [self done]; } if (completionHandler) { completionHandler(NSURLSessionResponseAllow); } } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { [self.imageData appendData:data]; if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) { // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ // Thanks to the author @Nyx0uf // Get the image data NSData *imageData = [self.imageData copy]; // Get the total bytes downloaded const NSInteger totalSize = imageData.length; // Get the finish status BOOL finished = (totalSize >= self.expectedSize); if (!_imageSource) { _imageSource = CGImageSourceCreateIncremental(NULL); } // Update the data source, we must pass ALL the data, not just the new bytes CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)imageData, finished); if (_width + _height == 0) { CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL); if (properties) { NSInteger orientationValue = -1; CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); if (val) CFNumberGetValue(val, kCFNumberLongType, &_height); val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); if (val) CFNumberGetValue(val, kCFNumberLongType, &_width); val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue); CFRelease(properties); // When we draw to Core Graphics, we lose orientation information, // which means the image below born of initWithCGIImage will be // oriented incorrectly sometimes. (Unlike the image born of initWithData // in didCompleteWithError.) So save it here and pass it on later. #if SD_UIKIT || SD_WATCH _orientation = [[self class] orientationFromPropertyValue:(orientationValue == -1 ? 1 : orientationValue)]; #endif } } if (_width + _height > 0 && !finished) { // Create the image CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); #if SD_UIKIT || SD_WATCH // Workaround for iOS anamorphic image if (partialImageRef) { const size_t partialHeight = CGImageGetHeight(partialImageRef); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef bmContext = CGBitmapContextCreate(NULL, _width, _height, 8, _width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); CGColorSpaceRelease(colorSpace); if (bmContext) { CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = _width, .size.height = partialHeight}, partialImageRef); CGImageRelease(partialImageRef); partialImageRef = CGBitmapContextCreateImage(bmContext); CGContextRelease(bmContext); } else { CGImageRelease(partialImageRef); partialImageRef = nil; } } #endif if (partialImageRef) { #if SD_UIKIT || SD_WATCH UIImage *image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:_orientation]; #elif SD_MAC UIImage *image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; #endif CGImageRelease(partialImageRef); NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; UIImage *scaledImage = [self scaledImageForKey:key image:image]; if (self.shouldDecompressImages) { image = [UIImage decodedImageWithImage:scaledImage]; } else { image = scaledImage; } [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; } } if (finished) { if (_imageSource) { CFRelease(_imageSource); _imageSource = NULL; } } } for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { progressBlock(self.imageData.length, self.expectedSize, self.request.URL); } } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { NSCachedURLResponse *cachedResponse = proposedResponse; if (self.request.cachePolicy == NSURLRequestReloadIgnoringLocalCacheData) { // Prevents caching of responses cachedResponse = nil; } if (completionHandler) { completionHandler(cachedResponse); } } #pragma mark NSURLSessionTaskDelegate - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { @synchronized(self) { self.dataTask = nil; __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf]; if (!error) { [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadFinishNotification object:weakSelf]; } }); } if (error) { [self callCompletionBlocksWithError:error]; } else { if ([self callbacksForKey:kCompletedCallbackKey].count > 0) { /** * If you specified to use `NSURLCache`, then the response you get here is what you need. */ NSData *imageData = [self.imageData copy]; if (imageData) { UIImage *image = [UIImage sd_imageWithData:imageData]; /** if you specified to only use cached data via `SDWebImageDownloaderIgnoreCachedResponse`, * then we should check if the cached data is equal to image data */ if (self.options & SDWebImageDownloaderIgnoreCachedResponse && [self.cachedData isEqualToData:imageData]) { // call completion block with nil [self callCompletionBlocksWithImage:nil imageData:nil error:nil finished:YES]; } else { NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; image = [self scaledImageForKey:key image:image]; BOOL shouldDecode = YES; // Do not force decoding animated GIFs and WebPs if (image.images) { shouldDecode = NO; } else { #ifdef SD_WEBP SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:imageData]; if (imageFormat == SDImageFormatWebP) { shouldDecode = NO; } #endif } if (shouldDecode) { if (self.shouldDecompressImages) { if (self.options & SDWebImageDownloaderScaleDownLargeImages) { #if SD_UIKIT || SD_WATCH image = [UIImage decodedAndScaledDownImageWithImage:image]; imageData = UIImagePNGRepresentation(image); #endif } else { image = [UIImage decodedImageWithImage:image]; } } } if (CGSizeEqualToSize(image.size, CGSizeZero)) { [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; } else { [self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES]; } } } else { [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]]; } } } [self done]; } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __block NSURLCredential *credential = nil; if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if (!(self.options & SDWebImageDownloaderAllowInvalidSSLCertificates)) { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } else { credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; disposition = NSURLSessionAuthChallengeUseCredential; } } else { if (challenge.previousFailureCount == 0) { if (self.credential) { credential = self.credential; disposition = NSURLSessionAuthChallengeUseCredential; } else { disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } } else { disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } } if (completionHandler) { completionHandler(disposition, credential); } } #pragma mark Helper methods #if SD_UIKIT || SD_WATCH + (UIImageOrientation)orientationFromPropertyValue:(NSInteger)value { switch (value) { case 1: return UIImageOrientationUp; case 3: return UIImageOrientationDown; case 8: return UIImageOrientationLeft; case 6: return UIImageOrientationRight; case 2: return UIImageOrientationUpMirrored; case 4: return UIImageOrientationDownMirrored; case 5: return UIImageOrientationLeftMirrored; case 7: return UIImageOrientationRightMirrored; default: return UIImageOrientationUp; } } #endif - (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { return SDScaledImageForKey(key, image); } - (BOOL)shouldContinueWhenAppEntersBackground { return self.options & SDWebImageDownloaderContinueInBackground; } - (void)callCompletionBlocksWithError:(nullable NSError *)error { [self callCompletionBlocksWithImage:nil imageData:nil error:error finished:YES]; } - (void)callCompletionBlocksWithImage:(nullable UIImage *)image imageData:(nullable NSData *)imageData error:(nullable NSError *)error finished:(BOOL)finished { NSArray *completionBlocks = [self callbacksForKey:kCompletedCallbackKey]; dispatch_main_async_safe(^{ for (SDWebImageDownloaderCompletedBlock completedBlock in completionBlocks) { completedBlock(image, imageData, error, finished); } }); } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageManager.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #import "SDWebImageOperation.h" #import "SDWebImageDownloader.h" #import "SDImageCache.h" typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { /** * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying. * This flag disable this blacklisting. */ SDWebImageRetryFailed = 1 << 0, /** * By default, image downloads are started during UI interactions, this flags disable this feature, * leading to delayed download on UIScrollView deceleration for instance. */ SDWebImageLowPriority = 1 << 1, /** * This flag disables on-disk caching */ SDWebImageCacheMemoryOnly = 1 << 2, /** * This flag enables progressive download, the image is displayed progressively during download as a browser would do. * By default, the image is only displayed once completely downloaded. */ SDWebImageProgressiveDownload = 1 << 3, /** * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed. * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation. * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics. * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image. * * Use this flag only if you can't make your URLs static with embedded cache busting parameter. */ SDWebImageRefreshCached = 1 << 4, /** * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for * extra time in background to let the request finish. If the background task expires the operation will be cancelled. */ SDWebImageContinueInBackground = 1 << 5, /** * Handles cookies stored in NSHTTPCookieStore by setting * NSMutableURLRequest.HTTPShouldHandleCookies = YES; */ SDWebImageHandleCookies = 1 << 6, /** * Enable to allow untrusted SSL certificates. * Useful for testing purposes. Use with caution in production. */ SDWebImageAllowInvalidSSLCertificates = 1 << 7, /** * By default, images are loaded in the order in which they were queued. This flag moves them to * the front of the queue. */ SDWebImageHighPriority = 1 << 8, /** * By default, placeholder images are loaded while the image is loading. This flag will delay the loading * of the placeholder image until after the image has finished loading. */ SDWebImageDelayPlaceholder = 1 << 9, /** * We usually don't call transformDownloadedImage delegate method on animated images, * as most transformation code would mangle it. * Use this flag to transform them anyway. */ SDWebImageTransformAnimatedImage = 1 << 10, /** * By default, image is added to the imageView after download. But in some cases, we want to * have the hand before setting the image (apply a filter or add it with cross-fade animation for instance) * Use this flag if you want to manually set the image in the completion when success */ SDWebImageAvoidAutoSetImage = 1 << 11, /** * By default, images are decoded respecting their original size. On iOS, this flag will scale down the * images to a size compatible with the constrained memory of devices. * If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated. */ SDWebImageScaleDownLargeImages = 1 << 12 }; typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); typedef NSString * _Nullable (^SDWebImageCacheKeyFilterBlock)(NSURL * _Nullable url); @class SDWebImageManager; @protocol SDWebImageManagerDelegate @optional /** * Controls which image should be downloaded when the image is not found in the cache. * * @param imageManager The current `SDWebImageManager` * @param imageURL The url of the image to be downloaded * * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied. */ - (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nullable NSURL *)imageURL; /** * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory. * NOTE: This method is called from a global queue in order to not to block the main thread. * * @param imageManager The current `SDWebImageManager` * @param image The image to transform * @param imageURL The url of the image to transform * * @return The transformed image object. */ - (nullable UIImage *)imageManager:(nonnull SDWebImageManager *)imageManager transformDownloadedImage:(nullable UIImage *)image withURL:(nullable NSURL *)imageURL; @end /** * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes. * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache). * You can use this class directly to benefit from web image downloading with caching in another context than * a UIView. * * Here is a simple example of how to use SDWebImageManager: * * @code SDWebImageManager *manager = [SDWebImageManager sharedManager]; [manager loadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (image) { // do something with image } }]; * @endcode */ @interface SDWebImageManager : NSObject @property (weak, nonatomic, nullable) id delegate; @property (strong, nonatomic, readonly, nullable) SDImageCache *imageCache; @property (strong, nonatomic, readonly, nullable) SDWebImageDownloader *imageDownloader; /** * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can * be used to remove dynamic part of an image URL. * * The following example sets a filter in the application delegate that will remove any query-string from the * URL before to use it as a cache key: * * @code [[SDWebImageManager sharedManager] setCacheKeyFilter:^(NSURL *url) { url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path]; return [url absoluteString]; }]; * @endcode */ @property (nonatomic, copy, nullable) SDWebImageCacheKeyFilterBlock cacheKeyFilter; /** * Returns global SDWebImageManager instance. * * @return SDWebImageManager shared instance */ + (nonnull instancetype)sharedManager; /** * Allows to specify instance of cache and image downloader used with image manager. * @return new instance of `SDWebImageManager` with specified cache and downloader. */ - (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER; /** * Downloads the image at the given URL if not present in cache or return the cached version otherwise. * * @param url The URL to the image * @param options A mask to specify options to use for this request * @param progressBlock A block called while image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called when operation has been completed. * * This parameter is required. * * This block has no return value and takes the requested UIImage as first parameter and the NSData representation as second parameter. * In case of error the image parameter is nil and the third parameter may contain an NSError. * * The forth parameter is an `SDImageCacheType` enum indicating if the image was retrieved from the local cache * or from the memory cache or from the network. * * The fith parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is * downloading. This block is thus called repeatedly with a partial image. When image is fully downloaded, the * block is called a last time with the full image and the last parameter set to YES. * * The last parameter is the original image URL * * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation */ - (nullable id )loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock; /** * Saves image to cache for given URL * * @param image The image to cache * @param url The URL to the image * */ - (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url; /** * Cancel all current operations */ - (void)cancelAll; /** * Check one or more operations running */ - (BOOL)isRunning; /** * Async check if image has already been cached * * @param url image url * @param completionBlock the block to be executed when the check is finished * * @note the completion block is always executed on the main queue */ - (void)cachedImageExistsForURL:(nullable NSURL *)url completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; /** * Async check if image has already been cached on disk only * * @param url image url * @param completionBlock the block to be executed when the check is finished * * @note the completion block is always executed on the main queue */ - (void)diskImageExistsForURL:(nullable NSURL *)url completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; /** *Return the cache key for a given URL */ - (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageManager.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageManager.h" #import #import "NSImage+WebCache.h" @interface SDWebImageCombinedOperation : NSObject @property (assign, nonatomic, getter = isCancelled) BOOL cancelled; @property (copy, nonatomic, nullable) SDWebImageNoParamsBlock cancelBlock; @property (strong, nonatomic, nullable) NSOperation *cacheOperation; @end @interface SDWebImageManager () @property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache; @property (strong, nonatomic, readwrite, nonnull) SDWebImageDownloader *imageDownloader; @property (strong, nonatomic, nonnull) NSMutableSet *failedURLs; @property (strong, nonatomic, nonnull) NSMutableArray *runningOperations; @end @implementation SDWebImageManager + (nonnull instancetype)sharedManager { static dispatch_once_t once; static id instance; dispatch_once(&once, ^{ instance = [self new]; }); return instance; } - (nonnull instancetype)init { SDImageCache *cache = [SDImageCache sharedImageCache]; SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader]; return [self initWithCache:cache downloader:downloader]; } - (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader { if ((self = [super init])) { _imageCache = cache; _imageDownloader = downloader; _failedURLs = [NSMutableSet new]; _runningOperations = [NSMutableArray new]; } return self; } - (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url { if (!url) { return @""; } if (self.cacheKeyFilter) { return self.cacheKeyFilter(url); } else { return url.absoluteString; } } - (void)cachedImageExistsForURL:(nullable NSURL *)url completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { NSString *key = [self cacheKeyForURL:url]; BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil); if (isInMemoryCache) { // making sure we call the completion block on the main queue dispatch_async(dispatch_get_main_queue(), ^{ if (completionBlock) { completionBlock(YES); } }); return; } [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch if (completionBlock) { completionBlock(isInDiskCache); } }]; } - (void)diskImageExistsForURL:(nullable NSURL *)url completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { NSString *key = [self cacheKeyForURL:url]; [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch if (completionBlock) { completionBlock(isInDiskCache); } }]; } - (id )loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDInternalCompletionBlock)completedBlock { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, Xcode won't // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString. if ([url isKindOfClass:NSString.class]) { url = [NSURL URLWithString:(NSString *)url]; } // Prevents app crashing on argument type error like sending NSNull instead of NSURL if (![url isKindOfClass:NSURL.class]) { url = nil; } __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new]; __weak SDWebImageCombinedOperation *weakOperation = operation; BOOL isFailedUrl = NO; if (url) { @synchronized (self.failedURLs) { isFailedUrl = [self.failedURLs containsObject:url]; } } if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) { [self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil] url:url]; return operation; } @synchronized (self.runningOperations) { [self.runningOperations addObject:operation]; } NSString *key = [self cacheKeyForURL:url]; operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { if (operation.isCancelled) { [self safelyRemoveOperationFromRunning:operation]; return; } if ((!cachedImage || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) { if (cachedImage && options & SDWebImageRefreshCached) { // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. [self callCompletionBlockForOperation:weakOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; } // download if no image or requested to refresh anyway, and download allowed by delegate SDWebImageDownloaderOptions downloaderOptions = 0; if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache; if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground; if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies; if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages; if (cachedImage && options & SDWebImageRefreshCached) { // force progressive off if image already cached but forced refreshing downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; // ignore image read from NSURLCache if image if cached but force refreshing downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; } SDWebImageDownloadToken *subOperationToken = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong __typeof(weakOperation) strongOperation = weakOperation; if (!strongOperation || strongOperation.isCancelled) { // Do nothing if the operation was cancelled // See #699 for more details // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data } else if (error) { [self callCompletionBlockForOperation:strongOperation completion:completedBlock error:error url:url]; if ( error.code != NSURLErrorNotConnectedToInternet && error.code != NSURLErrorCancelled && error.code != NSURLErrorTimedOut && error.code != NSURLErrorInternationalRoamingOff && error.code != NSURLErrorDataNotAllowed && error.code != NSURLErrorCannotFindHost && error.code != NSURLErrorCannotConnectToHost && error.code != NSURLErrorNetworkConnectionLost) { @synchronized (self.failedURLs) { [self.failedURLs addObject:url]; } } } else { if ((options & SDWebImageRetryFailed)) { @synchronized (self.failedURLs) { [self.failedURLs removeObject:url]; } } BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { // Image refresh hit the NSURLCache cache, do not call the completion block } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; if (transformedImage && finished) { BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; // pass nil if the image was transformed, so we can recalculate the data from the image [self.imageCache storeImage:transformedImage imageData:(imageWasTransformed ? nil : downloadedData) forKey:key toDisk:cacheOnDisk completion:nil]; } [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; }); } else { if (downloadedImage && finished) { [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil]; } [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; } } if (finished) { [self safelyRemoveOperationFromRunning:strongOperation]; } }]; operation.cancelBlock = ^{ [self.imageDownloader cancel:subOperationToken]; __strong __typeof(weakOperation) strongOperation = weakOperation; [self safelyRemoveOperationFromRunning:strongOperation]; }; } else if (cachedImage) { __strong __typeof(weakOperation) strongOperation = weakOperation; [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; [self safelyRemoveOperationFromRunning:operation]; } else { // Image not in cache and download disallowed by delegate __strong __typeof(weakOperation) strongOperation = weakOperation; [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url]; [self safelyRemoveOperationFromRunning:operation]; } }]; return operation; } - (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url { if (image && url) { NSString *key = [self cacheKeyForURL:url]; [self.imageCache storeImage:image forKey:key toDisk:YES completion:nil]; } } - (void)cancelAll { @synchronized (self.runningOperations) { NSArray *copiedOperations = [self.runningOperations copy]; [copiedOperations makeObjectsPerformSelector:@selector(cancel)]; [self.runningOperations removeObjectsInArray:copiedOperations]; } } - (BOOL)isRunning { BOOL isRunning = NO; @synchronized (self.runningOperations) { isRunning = (self.runningOperations.count > 0); } return isRunning; } - (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation { @synchronized (self.runningOperations) { if (operation) { [self.runningOperations removeObject:operation]; } } } - (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation completion:(nullable SDInternalCompletionBlock)completionBlock error:(nullable NSError *)error url:(nullable NSURL *)url { [self callCompletionBlockForOperation:operation completion:completionBlock image:nil data:nil error:error cacheType:SDImageCacheTypeNone finished:YES url:url]; } - (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation completion:(nullable SDInternalCompletionBlock)completionBlock image:(nullable UIImage *)image data:(nullable NSData *)data error:(nullable NSError *)error cacheType:(SDImageCacheType)cacheType finished:(BOOL)finished url:(nullable NSURL *)url { dispatch_main_async_safe(^{ if (operation && !operation.isCancelled && completionBlock) { completionBlock(image, data, error, cacheType, finished, url); } }); } @end @implementation SDWebImageCombinedOperation - (void)setCancelBlock:(nullable SDWebImageNoParamsBlock)cancelBlock { // check if the operation is already cancelled, then we just call the cancelBlock if (self.isCancelled) { if (cancelBlock) { cancelBlock(); } _cancelBlock = nil; // don't forget to nil the cancelBlock, otherwise we will get crashes } else { _cancelBlock = [cancelBlock copy]; } } - (void)cancel { self.cancelled = YES; if (self.cacheOperation) { [self.cacheOperation cancel]; self.cacheOperation = nil; } if (self.cancelBlock) { self.cancelBlock(); // TODO: this is a temporary fix to #809. // Until we can figure the exact cause of the crash, going with the ivar instead of the setter // self.cancelBlock = nil; _cancelBlock = nil; } } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImageOperation.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import @protocol SDWebImageOperation - (void)cancel; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import #import "SDWebImageManager.h" @class SDWebImagePrefetcher; @protocol SDWebImagePrefetcherDelegate @optional /** * Called when an image was prefetched. * * @param imagePrefetcher The current image prefetcher * @param imageURL The image url that was prefetched * @param finishedCount The total number of images that were prefetched (successful or not) * @param totalCount The total number of images that were to be prefetched */ - (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(nullable NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount; /** * Called when all images are prefetched. * @param imagePrefetcher The current image prefetcher * @param totalCount The total number of images that were prefetched (whether successful or not) * @param skippedCount The total number of images that were skipped */ - (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount; @end typedef void(^SDWebImagePrefetcherProgressBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls); typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls); /** * Prefetch some URLs in the cache for future use. Images are downloaded in low priority. */ @interface SDWebImagePrefetcher : NSObject /** * The web image manager */ @property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager; /** * Maximum number of URLs to prefetch at the same time. Defaults to 3. */ @property (nonatomic, assign) NSUInteger maxConcurrentDownloads; /** * SDWebImageOptions for prefetcher. Defaults to SDWebImageLowPriority. */ @property (nonatomic, assign) SDWebImageOptions options; /** * Queue options for Prefetcher. Defaults to Main Queue. */ @property (SDDispatchQueueSetterSementics, nonatomic, nonnull) dispatch_queue_t prefetcherQueue; @property (weak, nonatomic, nullable) id delegate; /** * Return the global image prefetcher instance. */ + (nonnull instancetype)sharedImagePrefetcher; /** * Allows you to instantiate a prefetcher with any arbitrary image manager. */ - (nonnull instancetype)initWithImageManager:(nonnull SDWebImageManager *)manager NS_DESIGNATED_INITIALIZER; /** * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, * currently one image is downloaded at a time, * and skips images for failed downloads and proceed to the next image in the list. * Any previously-running prefetch operations are canceled. * * @param urls list of URLs to prefetch */ - (void)prefetchURLs:(nullable NSArray *)urls; /** * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, * currently one image is downloaded at a time, * and skips images for failed downloads and proceed to the next image in the list. * Any previously-running prefetch operations are canceled. * * @param urls list of URLs to prefetch * @param progressBlock block to be called when progress updates; * first parameter is the number of completed (successful or not) requests, * second parameter is the total number of images originally requested to be prefetched * @param completionBlock block to be called when prefetching is completed * first param is the number of completed (successful or not) requests, * second parameter is the number of skipped requests */ - (void)prefetchURLs:(nullable NSArray *)urls progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock; /** * Remove and cancel queued list */ - (void)cancelPrefetching; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImagePrefetcher.h" @interface SDWebImagePrefetcher () @property (strong, nonatomic, nonnull) SDWebImageManager *manager; @property (strong, nonatomic, nullable) NSArray *prefetchURLs; @property (assign, nonatomic) NSUInteger requestedCount; @property (assign, nonatomic) NSUInteger skippedCount; @property (assign, nonatomic) NSUInteger finishedCount; @property (assign, nonatomic) NSTimeInterval startedTime; @property (copy, nonatomic, nullable) SDWebImagePrefetcherCompletionBlock completionBlock; @property (copy, nonatomic, nullable) SDWebImagePrefetcherProgressBlock progressBlock; @end @implementation SDWebImagePrefetcher + (nonnull instancetype)sharedImagePrefetcher { static dispatch_once_t once; static id instance; dispatch_once(&once, ^{ instance = [self new]; }); return instance; } - (nonnull instancetype)init { return [self initWithImageManager:[SDWebImageManager new]]; } - (nonnull instancetype)initWithImageManager:(SDWebImageManager *)manager { if ((self = [super init])) { _manager = manager; _options = SDWebImageLowPriority; _prefetcherQueue = dispatch_get_main_queue(); self.maxConcurrentDownloads = 3; } return self; } - (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads { self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads; } - (NSUInteger)maxConcurrentDownloads { return self.manager.imageDownloader.maxConcurrentDownloads; } - (void)startPrefetchingAtIndex:(NSUInteger)index { if (index >= self.prefetchURLs.count) return; self.requestedCount++; [self.manager loadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!finished) return; self.finishedCount++; if (image) { if (self.progressBlock) { self.progressBlock(self.finishedCount,(self.prefetchURLs).count); } } else { if (self.progressBlock) { self.progressBlock(self.finishedCount,(self.prefetchURLs).count); } // Add last failed self.skippedCount++; } if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) { [self.delegate imagePrefetcher:self didPrefetchURL:self.prefetchURLs[index] finishedCount:self.finishedCount totalCount:self.prefetchURLs.count ]; } if (self.prefetchURLs.count > self.requestedCount) { dispatch_async(self.prefetcherQueue, ^{ [self startPrefetchingAtIndex:self.requestedCount]; }); } else if (self.finishedCount == self.requestedCount) { [self reportStatus]; if (self.completionBlock) { self.completionBlock(self.finishedCount, self.skippedCount); self.completionBlock = nil; } self.progressBlock = nil; } }]; } - (void)reportStatus { NSUInteger total = (self.prefetchURLs).count; if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) { [self.delegate imagePrefetcher:self didFinishWithTotalCount:(total - self.skippedCount) skippedCount:self.skippedCount ]; } } - (void)prefetchURLs:(nullable NSArray *)urls { [self prefetchURLs:urls progress:nil completed:nil]; } - (void)prefetchURLs:(nullable NSArray *)urls progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock { [self cancelPrefetching]; // Prevent duplicate prefetch request self.startedTime = CFAbsoluteTimeGetCurrent(); self.prefetchURLs = urls; self.completionBlock = completionBlock; self.progressBlock = progressBlock; if (urls.count == 0) { if (completionBlock) { completionBlock(0,0); } } else { // Starts prefetching from the very first image on the list with the max allowed concurrency NSUInteger listCount = self.prefetchURLs.count; for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) { [self startPrefetchingAtIndex:i]; } } } - (void)cancelPrefetching { self.prefetchURLs = nil; self.skippedCount = 0; self.requestedCount = 0; self.finishedCount = 0; [self.manager cancelAll]; } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIButton+WebCache.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #if SD_UIKIT #import "SDWebImageManager.h" /** * Integrates SDWebImage async downloading and caching of remote images with UIButtonView. */ @interface UIButton (WebCache) #pragma mark - Image /** * Get the current image URL. */ - (nullable NSURL *)sd_currentImageURL; /** * Get the image URL for a control state. * * @param state Which state you want to know the URL for. The values are described in UIControlState. */ - (nullable NSURL *)sd_imageURLForState:(UIControlState)state; /** * Set the imageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url` and a placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @see sd_setImageWithURL:placeholderImage:options: */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; #pragma mark - Background image /** * Get the current background image URL. */ - (nullable NSURL *)sd_currentBackgroundImageURL; /** * Get the background image URL for a control state. * * @param state Which state you want to know the URL for. The values are described in UIControlState. */ - (nullable NSURL *)sd_backgroundImageURLForState:(UIControlState)state; /** * Set the backgroundImageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state NS_REFINED_FOR_SWIFT; /** * Set the backgroundImageView `image` with an `url` and a placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @see sd_setImageWithURL:placeholderImage:options: */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; /** * Set the backgroundImageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; /** * Set the backgroundImageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the backgroundImageView `image` with an `url`, placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param state The state that uses the specified title. The values are described in UIControlState. * @param placeholder The image to be set initially, until the image request finishes. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; /** * Set the backgroundImageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; #pragma mark - Cancel /** * Cancel the current image download */ - (void)sd_cancelImageLoadForState:(UIControlState)state; /** * Cancel the current backgroundImage download */ - (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state; @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIButton+WebCache.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIButton+WebCache.h" #if SD_UIKIT #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" #import "UIView+WebCache.h" static char imageURLStorageKey; typedef NSMutableDictionary SDStateImageURLDictionary; static inline NSString * imageURLKeyForState(UIControlState state) { return [NSString stringWithFormat:@"image_%lu", (unsigned long)state]; } static inline NSString * backgroundImageURLKeyForState(UIControlState state) { return [NSString stringWithFormat:@"backgroundImage_%lu", (unsigned long)state]; } @implementation UIButton (WebCache) #pragma mark - Image - (nullable NSURL *)sd_currentImageURL { NSURL *url = self.imageURLStorage[imageURLKeyForState(self.state)]; if (!url) { url = self.imageURLStorage[imageURLKeyForState(UIControlStateNormal)]; } return url; } - (nullable NSURL *)sd_imageURLForState:(UIControlState)state { return self.imageURLStorage[imageURLKeyForState(state)]; } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state { [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder { [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; } - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { if (!url) { [self.imageURLStorage removeObjectForKey:imageURLKeyForState(state)]; } else { self.imageURLStorage[imageURLKeyForState(state)] = url; } __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)] setImageBlock:^(UIImage *image, NSData *imageData) { [weakSelf setImage:image forState:state]; } progress:nil completed:completedBlock]; } #pragma mark - Background image - (nullable NSURL *)sd_currentBackgroundImageURL { NSURL *url = self.imageURLStorage[backgroundImageURLKeyForState(self.state)]; if (!url) { url = self.imageURLStorage[backgroundImageURLKeyForState(UIControlStateNormal)]; } return url; } - (nullable NSURL *)sd_backgroundImageURLForState:(UIControlState)state { return self.imageURLStorage[backgroundImageURLKeyForState(state)]; } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; } - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { if (!url) { [self.imageURLStorage removeObjectForKey:backgroundImageURLKeyForState(state)]; } else { self.imageURLStorage[backgroundImageURLKeyForState(state)] = url; } __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)] setImageBlock:^(UIImage *image, NSData *imageData) { [weakSelf setBackgroundImage:image forState:state]; } progress:nil completed:completedBlock]; } - (void)sd_setImageLoadOperation:(id)operation forState:(UIControlState)state { [self sd_setImageLoadOperation:operation forKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)]]; } - (void)sd_cancelImageLoadForState:(UIControlState)state { [self sd_cancelImageLoadOperationWithKey:[NSString stringWithFormat:@"UIButtonImageOperation%@", @(state)]]; } - (void)sd_setBackgroundImageLoadOperation:(id)operation forState:(UIControlState)state { [self sd_setImageLoadOperation:operation forKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)]]; } - (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state { [self sd_cancelImageLoadOperationWithKey:[NSString stringWithFormat:@"UIButtonBackgroundImageOperation%@", @(state)]]; } - (SDStateImageURLDictionary *)imageURLStorage { SDStateImageURLDictionary *storage = objc_getAssociatedObject(self, &imageURLStorageKey); if (!storage) { storage = [NSMutableDictionary dictionary]; objc_setAssociatedObject(self, &imageURLStorageKey, storage, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return storage; } @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImage+GIF.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * (c) Laurin Brandner * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" @interface UIImage (GIF) /** * Compatibility method - creates an animated UIImage from an NSData, it will only contain the 1st frame image */ + (UIImage *)sd_animatedGIFWithData:(NSData *)data; /** * Checks if an UIImage instance is a GIF. Will use the `images` array */ - (BOOL)isGIF; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImage+GIF.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * (c) Laurin Brandner * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIImage+GIF.h" #import #import "objc/runtime.h" #import "NSImage+WebCache.h" @implementation UIImage (GIF) + (UIImage *)sd_animatedGIFWithData:(NSData *)data { if (!data) { return nil; } #if SD_MAC return [[UIImage alloc] initWithData:data]; #else CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); size_t count = CGImageSourceGetCount(source); UIImage *staticImage; if (count <= 1) { staticImage = [[UIImage alloc] initWithData:data]; } else { // we will only retrieve the 1st frame. the full GIF support is available via the FLAnimatedImageView category. // this here is only code to allow drawing animated images as static ones #if SD_WATCH CGFloat scale = 1; scale = [WKInterfaceDevice currentDevice].screenScale; #elif SD_UIKIT CGFloat scale = 1; scale = [UIScreen mainScreen].scale; #endif CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL); #if SD_UIKIT || SD_WATCH UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:scale orientation:UIImageOrientationUp]; staticImage = [UIImage animatedImageWithImages:@[frameImage] duration:0.0f]; #endif CGImageRelease(CGImage); } CFRelease(source); return staticImage; #endif } - (BOOL)isGIF { return (self.images != nil); } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #import "NSData+ImageContentType.h" @interface UIImage (MultiFormat) + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data; - (nullable NSData *)sd_imageData; - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat; @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIImage+MultiFormat.h" #import "UIImage+GIF.h" #import "NSData+ImageContentType.h" #import #ifdef SD_WEBP #import "UIImage+WebP.h" #endif @implementation UIImage (MultiFormat) + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { if (!data) { return nil; } UIImage *image; SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data]; if (imageFormat == SDImageFormatGIF) { image = [UIImage sd_animatedGIFWithData:data]; } #ifdef SD_WEBP else if (imageFormat == SDImageFormatWebP) { image = [UIImage sd_imageWithWebPData:data]; } #endif else { image = [[UIImage alloc] initWithData:data]; #if SD_UIKIT || SD_WATCH UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data]; if (orientation != UIImageOrientationUp) { image = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:orientation]; } #endif } return image; } #if SD_UIKIT || SD_WATCH +(UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData { UIImageOrientation result = UIImageOrientationUp; CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); if (imageSource) { CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); if (properties) { CFTypeRef val; int exifOrientation; val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); if (val) { CFNumberGetValue(val, kCFNumberIntType, &exifOrientation); result = [self sd_exifOrientationToiOSOrientation:exifOrientation]; } // else - if it's not set it remains at up CFRelease((CFTypeRef) properties); } else { //NSLog(@"NO PROPERTIES, FAIL"); } CFRelease(imageSource); } return result; } #pragma mark EXIF orientation tag converter // Convert an EXIF image orientation to an iOS one. // reference see here: http://sylvana.net/jpegcrop/exif_orientation.html + (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation { UIImageOrientation orientation = UIImageOrientationUp; switch (exifOrientation) { case 1: orientation = UIImageOrientationUp; break; case 3: orientation = UIImageOrientationDown; break; case 8: orientation = UIImageOrientationLeft; break; case 6: orientation = UIImageOrientationRight; break; case 2: orientation = UIImageOrientationUpMirrored; break; case 4: orientation = UIImageOrientationDownMirrored; break; case 5: orientation = UIImageOrientationLeftMirrored; break; case 7: orientation = UIImageOrientationRightMirrored; break; default: break; } return orientation; } #endif - (nullable NSData *)sd_imageData { return [self sd_imageDataAsFormat:SDImageFormatUndefined]; } - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat { NSData *imageData = nil; if (self) { #if SD_UIKIT || SD_WATCH int alphaInfo = CGImageGetAlphaInfo(self.CGImage); BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || alphaInfo == kCGImageAlphaNoneSkipFirst || alphaInfo == kCGImageAlphaNoneSkipLast); BOOL usePNG = hasAlpha; // the imageFormat param has priority here. But if the format is undefined, we relly on the alpha channel if (imageFormat != SDImageFormatUndefined) { usePNG = (imageFormat == SDImageFormatPNG); } if (usePNG) { imageData = UIImagePNGRepresentation(self); } else { imageData = UIImageJPEGRepresentation(self, (CGFloat)1.0); } #else NSBitmapImageFileType imageFileType = NSJPEGFileType; if (imageFormat == SDImageFormatGIF) { imageFileType = NSGIFFileType; } else if (imageFormat == SDImageFormatPNG) { imageFileType = NSPNGFileType; } imageData = [NSBitmapImageRep representationOfImageRepsInArray:self.representations usingType:imageFileType properties:@{}]; #endif } return imageData; } @end ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #if SD_UIKIT #import "SDWebImageManager.h" /** * Integrates SDWebImage async downloading and caching of remote images with UIImageView for highlighted state. */ @interface UIImageView (HighlightedWebCache) /** * Set the imageView `highlightedImage` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; /** * Set the imageView `highlightedImage` with an `url` and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; /** * Set the imageView `highlightedImage` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; /** * Set the imageView `highlightedImage` with an `url` and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `highlightedImage` with an `url` and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param progressBlock A block called while image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIImageView+HighlightedWebCache.h" #if SD_UIKIT #import "UIView+WebCacheOperation.h" #import "UIView+WebCache.h" @implementation UIImageView (HighlightedWebCache) - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url { [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; } - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options { [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; } - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock]; } - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; } - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { __weak typeof(self)weakSelf = self; [self sd_internalSetImageWithURL:url placeholderImage:nil options:options operationKey:@"UIImageViewImageOperationHighlighted" setImageBlock:^(UIImage *image, NSData *imageData) { weakSelf.highlightedImage = image; } progress:progressBlock completed:completedBlock]; } @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #if SD_UIKIT || SD_MAC #import "SDWebImageManager.h" /** * Integrates SDWebImage async downloading and caching of remote images with UIImageView. * * Usage with a UITableViewCell sub-class: * * @code #import ... - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *MyIdentifier = @"MyIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease]; } // Here we use the provided sd_setImageWithURL: method to load the web image // Ensure you use a placeholder image otherwise cells will be initialized with no image [cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://example.com/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder"]]; cell.textLabel.text = @"My Text"; return cell; } * @endcode */ @interface UIImageView (WebCache) /** * Set the imageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. */ - (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url` and a placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @see sd_setImageWithURL:placeholderImage:options: */ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. */ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url`. * * The download is asynchronous and cached. * * @param url The url for the image. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; /** * Set the imageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder and custom options. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param progressBlock A block called while image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url` and optionally a placeholder image. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param progressBlock A block called while image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; #if SD_UIKIT #pragma mark - Animation of multiple images /** * Download an array of images and starts them in an animation loop * * @param arrayOfURLs An array of NSURL */ - (void)sd_setAnimationImagesWithURLs:(nonnull NSArray *)arrayOfURLs; - (void)sd_cancelCurrentAnimationImagesLoad; #endif @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIImageView+WebCache.h" #if SD_UIKIT || SD_MAC #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" #import "UIView+WebCache.h" @implementation UIImageView (WebCache) - (void)sd_setImageWithURL:(nullable NSURL *)url { [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; } - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; } - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; } - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:nil setImageBlock:nil progress:progressBlock completed:completedBlock]; } - (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:key]; [self sd_setImageWithURL:url placeholderImage:lastPreviousCachedImage ?: placeholder options:options progress:progressBlock completed:completedBlock]; } #if SD_UIKIT #pragma mark - Animation of multiple images - (void)sd_setAnimationImagesWithURLs:(nonnull NSArray *)arrayOfURLs { [self sd_cancelCurrentAnimationImagesLoad]; __weak __typeof(self)wself = self; NSMutableArray> *operationsArray = [[NSMutableArray alloc] init]; [arrayOfURLs enumerateObjectsUsingBlock:^(NSURL *logoImageURL, NSUInteger idx, BOOL * _Nonnull stop) { id operation = [SDWebImageManager.sharedManager loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!wself) return; dispatch_main_async_safe(^{ __strong UIImageView *sself = wself; [sself stopAnimating]; if (sself && image) { NSMutableArray *currentImages = [[sself animationImages] mutableCopy]; if (!currentImages) { currentImages = [[NSMutableArray alloc] init]; } // We know what index objects should be at when they are returned so // we will put the object at the index, filling any empty indexes // with the image that was returned too "early". These images will // be overwritten. (does not require additional sorting datastructure) while ([currentImages count] < idx) { [currentImages addObject:image]; } currentImages[idx] = image; sself.animationImages = currentImages; [sself setNeedsLayout]; } [sself startAnimating]; }); }]; [operationsArray addObject:operation]; }]; [self sd_setImageLoadOperation:[operationsArray copy] forKey:@"UIImageViewAnimationImages"]; } - (void)sd_cancelCurrentAnimationImagesLoad { [self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"]; } #endif @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIView+WebCache.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #if SD_UIKIT || SD_MAC #import "SDWebImageManager.h" typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData); @interface UIView (WebCache) /** * Get the current image URL. * * Note that because of the limitations of categories this property can get out of sync * if you use setImage: directly. */ - (nullable NSURL *)sd_imageURL; /** * Set the imageView `image` with an `url` and optionally a placeholder image. * * The download is asynchronous and cached. * * @param url The url for the image. * @param placeholder The image to be set initially, until the image request finishes. * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. * @param operationKey A string to be used as the operation key. If nil, will use the class name * @param setImageBlock Block used for custom set image code * @param progressBlock A block called while image is downloading * @note the progress block is executed on a background queue * @param completedBlock A block called when operation has been completed. This block has no return value * and takes the requested UIImage as first parameter. In case of error the image parameter * is nil and the second parameter may contain an NSError. The third parameter is a Boolean * indicating if the image was retrieved from the local cache or from the network. * The fourth parameter is the original image url. */ - (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options operationKey:(nullable NSString *)operationKey setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Cancel the current download */ - (void)sd_cancelCurrentImageLoad; #if SD_UIKIT #pragma mark - Activity indicator /** * Show activity UIActivityIndicatorView */ - (void)sd_setShowActivityIndicatorView:(BOOL)show; /** * set desired UIActivityIndicatorViewStyle * * @param style The style of the UIActivityIndicatorView */ - (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style; - (BOOL)sd_showActivityIndicatorView; - (void)sd_addActivityIndicator; - (void)sd_removeActivityIndicator; #endif @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIView+WebCache.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIView+WebCache.h" #if SD_UIKIT || SD_MAC #import "objc/runtime.h" #import "UIView+WebCacheOperation.h" static char imageURLKey; #if SD_UIKIT static char TAG_ACTIVITY_INDICATOR; static char TAG_ACTIVITY_STYLE; #endif static char TAG_ACTIVITY_SHOW; @implementation UIView (WebCache) - (nullable NSURL *)sd_imageURL { return objc_getAssociatedObject(self, &imageURLKey); } - (void)sd_internalSetImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options operationKey:(nullable NSString *)operationKey setImageBlock:(nullable SDSetImageBlock)setImageBlock progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock { NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]); [self sd_cancelImageLoadOperationWithKey:validOperationKey]; objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (!(options & SDWebImageDelayPlaceholder)) { dispatch_main_async_safe(^{ [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; }); } if (url) { // check if activityView is enabled or not if ([self sd_showActivityIndicatorView]) { [self sd_addActivityIndicator]; } __weak __typeof(self)wself = self; id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { __strong __typeof (wself) sself = wself; [sself sd_removeActivityIndicator]; if (!sself) { return; } dispatch_main_async_safe(^{ if (!sself) { return; } if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) { completedBlock(image, error, cacheType, url); return; } else if (image) { [sself sd_setImage:image imageData:data basedOnClassOrViaCustomSetImageBlock:setImageBlock]; [sself sd_setNeedsLayout]; } else { if ((options & SDWebImageDelayPlaceholder)) { [sself sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock]; [sself sd_setNeedsLayout]; } } if (completedBlock && finished) { completedBlock(image, error, cacheType, url); } }); }]; [self sd_setImageLoadOperation:operation forKey:validOperationKey]; } else { dispatch_main_async_safe(^{ [self sd_removeActivityIndicator]; if (completedBlock) { NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; completedBlock(nil, error, SDImageCacheTypeNone, url); } }); } } - (void)sd_cancelCurrentImageLoad { [self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])]; } - (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDSetImageBlock)setImageBlock { if (setImageBlock) { setImageBlock(image, imageData); return; } #if SD_UIKIT || SD_MAC if ([self isKindOfClass:[UIImageView class]]) { UIImageView *imageView = (UIImageView *)self; imageView.image = image; } #endif #if SD_UIKIT if ([self isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton *)self; [button setImage:image forState:UIControlStateNormal]; } #endif } - (void)sd_setNeedsLayout { #if SD_UIKIT [self setNeedsLayout]; #elif SD_MAC [self setNeedsLayout:YES]; #endif } #pragma mark - Activity indicator #pragma mark - #if SD_UIKIT - (UIActivityIndicatorView *)activityIndicator { return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR); } - (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator { objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN); } #endif - (void)sd_setShowActivityIndicatorView:(BOOL)show { objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN); } - (BOOL)sd_showActivityIndicatorView { return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue]; } #if SD_UIKIT - (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style{ objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInt:style], OBJC_ASSOCIATION_RETAIN); } - (int)sd_getIndicatorStyle{ return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue]; } #endif - (void)sd_addActivityIndicator { #if SD_UIKIT dispatch_main_async_safe(^{ if (!self.activityIndicator) { self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self sd_getIndicatorStyle]]; self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:self.activityIndicator]; [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]]; } [self.activityIndicator startAnimating]; }); #endif } - (void)sd_removeActivityIndicator { #if SD_UIKIT dispatch_main_async_safe(^{ if (self.activityIndicator) { [self.activityIndicator removeFromSuperview]; self.activityIndicator = nil; } }); #endif } @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "SDWebImageCompat.h" #if SD_UIKIT || SD_MAC #import "SDWebImageManager.h" @interface UIView (WebCacheOperation) /** * Set the image load operation (storage in a UIView based dictionary) * * @param operation the operation * @param key key for storing the operation */ - (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key; /** * Cancel all operations for the current UIView and key * * @param key key for identifying the operations */ - (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key; /** * Just remove the operations corresponding to the current UIView and key without cancelling them * * @param key key for identifying the operations */ - (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key; @end #endif ================================================ FILE: Example/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m ================================================ /* * This file is part of the SDWebImage package. * (c) Olivier Poitrey * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #import "UIView+WebCacheOperation.h" #if SD_UIKIT || SD_MAC #import "objc/runtime.h" static char loadOperationKey; typedef NSMutableDictionary SDOperationsDictionary; @implementation UIView (WebCacheOperation) - (SDOperationsDictionary *)operationDictionary { SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); if (operations) { return operations; } operations = [NSMutableDictionary dictionary]; objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return operations; } - (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key { if (key) { [self sd_cancelImageLoadOperationWithKey:key]; if (operation) { SDOperationsDictionary *operationDictionary = [self operationDictionary]; operationDictionary[key] = operation; } } } - (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key { // Cancel in progress downloader from queue SDOperationsDictionary *operationDictionary = [self operationDictionary]; id operations = operationDictionary[key]; if (operations) { if ([operations isKindOfClass:[NSArray class]]) { for (id operation in operations) { if (operation) { [operation cancel]; } } } else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){ [(id) operations cancel]; } [operationDictionary removeObjectForKey:key]; } } - (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key { if (key) { SDOperationsDictionary *operationDictionary = [self operationDictionary]; [operationDictionary removeObjectForKey:key]; } } @end #endif ================================================ FILE: Example/Pods/SVProgressHUD/LICENSE.txt ================================================ Copyright (c) 2011-2017 Sam Vermette, Tobias Tiemerding and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. A different license may apply to other resources included in this package, including Freepik Icons. Please consult their respective headers for the terms of their individual licenses. ================================================ FILE: Example/Pods/SVProgressHUD/README.md ================================================ # SVProgressHUD ![Pod Version](https://img.shields.io/cocoapods/v/SVProgressHUD.svg?style=flat) ![Pod Platform](https://img.shields.io/cocoapods/p/SVProgressHUD.svg?style=flat) ![Pod License](https://img.shields.io/cocoapods/l/SVProgressHUD.svg?style=flat) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) `SVProgressHUD` is a clean and easy-to-use HUD meant to display the progress of an ongoing task on iOS and tvOS. ![SVProgressHUD](http://f.cl.ly/items/2G1F1Z0M0k0h2U3V1p39/SVProgressHUD.gif) ## Demo Try `SVProgressHUD` on [Appetize.io](https://appetize.io/app/p8r2cvy8kq74x7q7tjqf5gyatr). ## Installation ### From CocoaPods [CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like `SVProgressHUD` in your projects. First, add the following line to your [Podfile](http://guides.cocoapods.org/using/using-cocoapods.html): ```ruby pod 'SVProgressHUD' ``` If you want to use the latest features of `SVProgressHUD` use normal external source dependencies. ```ruby pod 'SVProgressHUD', :git => 'https://github.com/SVProgressHUD/SVProgressHUD.git' ``` This pulls from the `master` branch directly. Second, install `SVProgressHUD` into your project: ```ruby pod install ``` ### Carthage [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate `SVProgressHUD` into your Xcode project using Carthage, specify it in your `Cartfile`: ```ogdl github "SVProgressHUD/SVProgressHUD" ``` Run `carthage update` to build the framework and drag the built `SVProgressHUD.framework` (in Carthage/Build/iOS folder) into your Xcode project (Linked Frameworks and Libraries in `Targets`). ### Manually * Drag the `SVProgressHUD/SVProgressHUD` folder into your project. * Take care that `SVProgressHUD.bundle` is added to `Targets->Build Phases->Copy Bundle Resources`. * Add the **QuartzCore** framework to your project. ## Swift Even though `SVProgressHUD` is written in Objective-C, it can be used in Swift with no hassle. If you use [CocoaPods](http://cocoapods.org) add the following line to your [Podfile](http://guides.cocoapods.org/using/using-cocoapods.html): ```ruby use_frameworks! ``` If you added `SVProgressHUD` manually, just add a [bridging header](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html) file to your project with the `SVProgressHUD` header included. ## Usage (see sample Xcode project in `/Demo`) `SVProgressHUD` is created as a singleton (i.e. it doesn't need to be explicitly allocated and instantiated; you directly call `[SVProgressHUD method]`). **Use `SVProgressHUD` wisely! Only use it if you absolutely need to perform a task before taking the user forward. Bad use case examples: pull to refresh, infinite scrolling, sending message.** Using `SVProgressHUD` in your app will usually look as simple as this (using Grand Central Dispatch): ```objective-c [SVProgressHUD show]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // time-consuming task dispatch_async(dispatch_get_main_queue(), ^{ [SVProgressHUD dismiss]; }); }); ``` ### Showing the HUD You can show the status of indeterminate tasks using one of the following: ```objective-c + (void)show; + (void)showWithStatus:(NSString*)string; ``` If you'd like the HUD to reflect the progress of a task, use one of these: ```objective-c + (void)showProgress:(CGFloat)progress; + (void)showProgress:(CGFloat)progress status:(NSString*)status; ``` ### Dismissing the HUD The HUD can be dismissed using: ```objective-c + (void)dismiss; + (void)dismissWithDelay:(NSTimeInterval)delay; ``` If you'd like to stack HUDs, you can balance out every show call using: ``` + (void)popActivity; ``` The HUD will get dismissed once the popActivity calls will match the number of show calls. Or show a confirmation glyph before before getting dismissed a little bit later. The display time depends on `minimumDismissTimeInterval` and the length of the given string. ```objective-c + (void)showInfoWithStatus:(NSString*)string; + (void)showSuccessWithStatus:(NSString*)string; + (void)showErrorWithStatus:(NSString*)string; + (void)showImage:(UIImage*)image status:(NSString*)string; ``` ## Customization `SVProgressHUD` can be customized via the following methods: ```objective-c + (void)setDefaultStyle:(SVProgressHUDStyle)style; // default is SVProgressHUDStyleLight + (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType; // default is SVProgressHUDMaskTypeNone + (void)setDefaultAnimationType:(SVProgressHUDAnimationType)type; // default is SVProgressHUDAnimationTypeFlat + (void)setContainerView:(UIView*)containerView; // default is window level + (void)setMinimumSize:(CGSize)minimumSize; // default is CGSizeZero, can be used to avoid resizing + (void)setRingThickness:(CGFloat)width; // default is 2 pt + (void)setRingRadius:(CGFloat)radius; // default is 18 pt + (void)setRingNoTextRadius:(CGFloat)radius; // default is 24 pt + (void)setCornerRadius:(CGFloat)cornerRadius; // default is 14 pt + (void)setBorderColor:(nonnull UIColor*)color; // default is nil + (void)setBorderWidth:(CGFloat)width; // default is 0 + (void)setFont:(UIFont*)font; // default is [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline] + (void)setForegroundColor:(UIColor*)color; // default is [UIColor blackColor], only used for SVProgressHUDStyleCustom + (void)setBackgroundColor:(UIColor*)color; // default is [UIColor whiteColor], only used for SVProgressHUDStyleCustom + (void)setBackgroundLayerColor:(UIColor*)color; // default is [UIColor colorWithWhite:0 alpha:0.4], only used for SVProgressHUDMaskTypeCustom + (void)setImageViewSize:(CGSize)size; // default is 28x28 pt + (void)setInfoImage:(UIImage*)image; // default is the bundled info image provided by Freepik + (void)setSuccessImage:(UIImage*)image; // default is bundled success image from Freepik + (void)setErrorImage:(UIImage*)image; // default is bundled error image from Freepik + (void)setViewForExtension:(UIView*)view; // default is nil, only used if #define SV_APP_EXTENSIONS is set + (void)setGraceTimeInterval:(NSTimeInterval)interval; // default is 0 seconds + (void)setMinimumDismissTimeInterval:(NSTimeInterval)interval; // default is 5.0 seconds + (void)setMaximumDismissTimeInterval:(NSTimeInterval)interval; // default is CGFLOAT_MAX + (void)setFadeInAnimationDuration:(NSTimeInterval)duration; // default is 0.15 seconds + (void)setFadeOutAnimationDuration:(NSTimeInterval)duration; // default is 0.15 seconds + (void)setMaxSupportedWindowLevel:(UIWindowLevel)windowLevel; // default is UIWindowLevelNormal + (void)setHapticsEnabled:(BOOL)hapticsEnabled; // default is NO ``` Additionally `SVProgressHUD` supports the `UIAppearance` protocol for most of the above methods. ### Hint As standard `SVProgressHUD` offers two preconfigured styles: * `SVProgressHUDStyleLight`: White background with black spinner and text * `SVProgressHUDStyleDark`: Black background with white spinner and text If you want to use custom colors use `setForegroundColor` and `setBackgroundColor:`. These implicity set the HUD's style to `SVProgressHUDStyleCustom`. ## Haptic Feedback For users with newer devices (starting with the iPhone 7), `SVProgressHUD` can automatically trigger haptic feedback depending on which HUD is being displayed. The feedback maps as follows: * `showSuccessWithStatus:` <-> `UINotificationFeedbackTypeSuccess` * `showInfoWithStatus:` <-> `UINotificationFeedbackTypeWarning` * `showErrorWithStatus:` <-> `UINotificationFeedbackTypeError` To enable this functionality, use `setHapticsEnabled:`. Users with devices prior to iPhone 7 will have no change in functionality. ## Notifications `SVProgressHUD` posts four notifications via `NSNotificationCenter` in response to being shown/dismissed: * `SVProgressHUDWillAppearNotification` when the show animation starts * `SVProgressHUDDidAppearNotification` when the show animation completes * `SVProgressHUDWillDisappearNotification` when the dismiss animation starts * `SVProgressHUDDidDisappearNotification` when the dismiss animation completes Each notification passes a `userInfo` dictionary holding the HUD's status string (if any), retrievable via `SVProgressHUDStatusUserInfoKey`. `SVProgressHUD` also posts `SVProgressHUDDidReceiveTouchEventNotification` when users touch on the overall screen or `SVProgressHUDDidTouchDownInsideNotification` when a user touches on the HUD directly. For this notifications `userInfo` is not passed but the object parameter contains the `UIEvent` that related to the touch. ## App Extensions When using `SVProgressHUD` in an App Extension, `#define SV_APP_EXTENSIONS` to avoid using unavailable APIs. Additionally call `setViewForExtension:` from your extensions view controller with `self.view`. ## Contributing to this project If you have feature requests or bug reports, feel free to help out by sending pull requests or by [creating new issues](https://github.com/SVProgressHUD/SVProgressHUD/issues/new). Please take a moment to review the guidelines written by [Nicolas Gallagher](https://github.com/necolas): * [Bug reports](https://github.com/necolas/issue-guidelines/blob/master/CONTRIBUTING.md#bugs) * [Feature requests](https://github.com/necolas/issue-guidelines/blob/master/CONTRIBUTING.md#features) * [Pull requests](https://github.com/necolas/issue-guidelines/blob/master/CONTRIBUTING.md#pull-requests) ## License `SVProgressHUD` is distributed under the terms and conditions of the [MIT license](https://github.com/SVProgressHUD/SVProgressHUD/blob/master/LICENSE.txt). The success, error and info icons are made by [Freepik](http://www.freepik.com) from [Flaticon](http://www.flaticon.com) and are licensed under [Creative Commons BY 3.0](http://creativecommons.org/licenses/by/3.0/). ## Credits `SVProgressHUD` is brought to you by [Sam Vermette](http://samvermette.com), [Tobias Tiemerding](http://tiemerding.com) and [contributors to the project](https://github.com/SVProgressHUD/SVProgressHUD/contributors). If you're using `SVProgressHUD` in your project, attribution would be very appreciated. ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVIndefiniteAnimatedView.h ================================================ // // SVIndefiniteAnimatedView.h // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2014-2017 Guillaume Campagna. All rights reserved. // #import @interface SVIndefiniteAnimatedView : UIView @property (nonatomic, assign) CGFloat strokeThickness; @property (nonatomic, assign) CGFloat radius; @property (nonatomic, strong) UIColor *strokeColor; @end ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVIndefiniteAnimatedView.m ================================================ // // SVIndefiniteAnimatedView.m // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2014-2017 Guillaume Campagna. All rights reserved. // #import "SVIndefiniteAnimatedView.h" #import "SVProgressHUD.h" @interface SVIndefiniteAnimatedView () @property (nonatomic, strong) CAShapeLayer *indefiniteAnimatedLayer; @end @implementation SVIndefiniteAnimatedView - (void)willMoveToSuperview:(UIView*)newSuperview { if (newSuperview) { [self layoutAnimatedLayer]; } else { [_indefiniteAnimatedLayer removeFromSuperlayer]; _indefiniteAnimatedLayer = nil; } } - (void)layoutAnimatedLayer { CALayer *layer = self.indefiniteAnimatedLayer; [self.layer addSublayer:layer]; CGFloat widthDiff = CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds); CGFloat heightDiff = CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds); layer.position = CGPointMake(CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds) / 2 - widthDiff / 2, CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds) / 2 - heightDiff / 2); } - (CAShapeLayer*)indefiniteAnimatedLayer { if(!_indefiniteAnimatedLayer) { CGPoint arcCenter = CGPointMake(self.radius+self.strokeThickness/2+5, self.radius+self.strokeThickness/2+5); UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:self.radius startAngle:(CGFloat) (M_PI*3/2) endAngle:(CGFloat) (M_PI/2+M_PI*5) clockwise:YES]; _indefiniteAnimatedLayer = [CAShapeLayer layer]; _indefiniteAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale]; _indefiniteAnimatedLayer.frame = CGRectMake(0.0f, 0.0f, arcCenter.x*2, arcCenter.y*2); _indefiniteAnimatedLayer.fillColor = [UIColor clearColor].CGColor; _indefiniteAnimatedLayer.strokeColor = self.strokeColor.CGColor; _indefiniteAnimatedLayer.lineWidth = self.strokeThickness; _indefiniteAnimatedLayer.lineCap = kCALineCapRound; _indefiniteAnimatedLayer.lineJoin = kCALineJoinBevel; _indefiniteAnimatedLayer.path = smoothedPath.CGPath; CALayer *maskLayer = [CALayer layer]; NSBundle *bundle = [NSBundle bundleForClass:[SVProgressHUD class]]; NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"]; NSBundle *imageBundle = [NSBundle bundleWithURL:url]; NSString *path = [imageBundle pathForResource:@"angle-mask" ofType:@"png"]; maskLayer.contents = (__bridge id)[[UIImage imageWithContentsOfFile:path] CGImage]; maskLayer.frame = _indefiniteAnimatedLayer.bounds; _indefiniteAnimatedLayer.mask = maskLayer; NSTimeInterval animationDuration = 1; CAMediaTimingFunction *linearCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; animation.fromValue = (id) 0; animation.toValue = @(M_PI*2); animation.duration = animationDuration; animation.timingFunction = linearCurve; animation.removedOnCompletion = NO; animation.repeatCount = INFINITY; animation.fillMode = kCAFillModeForwards; animation.autoreverses = NO; [_indefiniteAnimatedLayer.mask addAnimation:animation forKey:@"rotate"]; CAAnimationGroup *animationGroup = [CAAnimationGroup animation]; animationGroup.duration = animationDuration; animationGroup.repeatCount = INFINITY; animationGroup.removedOnCompletion = NO; animationGroup.timingFunction = linearCurve; CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; strokeStartAnimation.fromValue = @0.015; strokeStartAnimation.toValue = @0.515; CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; strokeEndAnimation.fromValue = @0.485; strokeEndAnimation.toValue = @0.985; animationGroup.animations = @[strokeStartAnimation, strokeEndAnimation]; [_indefiniteAnimatedLayer addAnimation:animationGroup forKey:@"progress"]; } return _indefiniteAnimatedLayer; } - (void)setFrame:(CGRect)frame { if(!CGRectEqualToRect(frame, super.frame)) { [super setFrame:frame]; if(self.superview) { [self layoutAnimatedLayer]; } } } - (void)setRadius:(CGFloat)radius { if(radius != _radius) { _radius = radius; [_indefiniteAnimatedLayer removeFromSuperlayer]; _indefiniteAnimatedLayer = nil; if(self.superview) { [self layoutAnimatedLayer]; } } } - (void)setStrokeColor:(UIColor*)strokeColor { _strokeColor = strokeColor; _indefiniteAnimatedLayer.strokeColor = strokeColor.CGColor; } - (void)setStrokeThickness:(CGFloat)strokeThickness { _strokeThickness = strokeThickness; _indefiniteAnimatedLayer.lineWidth = _strokeThickness; } - (CGSize)sizeThatFits:(CGSize)size { return CGSizeMake((self.radius+self.strokeThickness/2+5)*2, (self.radius+self.strokeThickness/2+5)*2); } @end ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVProgressAnimatedView.h ================================================ // // SVProgressAnimatedView.h // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2017 Tobias Tiemerding. All rights reserved. // #import @interface SVProgressAnimatedView : UIView @property (nonatomic, assign) CGFloat radius; @property (nonatomic, assign) CGFloat strokeThickness; @property (nonatomic, strong) UIColor *strokeColor; @property (nonatomic, assign) CGFloat strokeEnd; @end ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVProgressAnimatedView.m ================================================ // // SVProgressAnimatedView.m // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2017 Tobias Tiemerding. All rights reserved. // #import "SVProgressAnimatedView.h" @interface SVProgressAnimatedView () @property (nonatomic, strong) CAShapeLayer *ringAnimatedLayer; @end @implementation SVProgressAnimatedView - (void)willMoveToSuperview:(UIView*)newSuperview { if (newSuperview) { [self layoutAnimatedLayer]; } else { [_ringAnimatedLayer removeFromSuperlayer]; _ringAnimatedLayer = nil; } } - (void)layoutAnimatedLayer { CALayer *layer = self.ringAnimatedLayer; [self.layer addSublayer:layer]; CGFloat widthDiff = CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds); CGFloat heightDiff = CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds); layer.position = CGPointMake(CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds) / 2 - widthDiff / 2, CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds) / 2 - heightDiff / 2); } - (CAShapeLayer*)ringAnimatedLayer { if(!_ringAnimatedLayer) { CGPoint arcCenter = CGPointMake(self.radius+self.strokeThickness/2+5, self.radius+self.strokeThickness/2+5); UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:self.radius startAngle:(CGFloat)-M_PI_2 endAngle:(CGFloat) (M_PI + M_PI_2) clockwise:YES]; _ringAnimatedLayer = [CAShapeLayer layer]; _ringAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale]; _ringAnimatedLayer.frame = CGRectMake(0.0f, 0.0f, arcCenter.x*2, arcCenter.y*2); _ringAnimatedLayer.fillColor = [UIColor clearColor].CGColor; _ringAnimatedLayer.strokeColor = self.strokeColor.CGColor; _ringAnimatedLayer.lineWidth = self.strokeThickness; _ringAnimatedLayer.lineCap = kCALineCapRound; _ringAnimatedLayer.lineJoin = kCALineJoinBevel; _ringAnimatedLayer.path = smoothedPath.CGPath; } return _ringAnimatedLayer; } - (void)setFrame:(CGRect)frame { if(!CGRectEqualToRect(frame, super.frame)) { [super setFrame:frame]; if(self.superview) { [self layoutAnimatedLayer]; } } } - (void)setRadius:(CGFloat)radius { if(radius != _radius) { _radius = radius; [_ringAnimatedLayer removeFromSuperlayer]; _ringAnimatedLayer = nil; if(self.superview) { [self layoutAnimatedLayer]; } } } - (void)setStrokeColor:(UIColor*)strokeColor { _strokeColor = strokeColor; _ringAnimatedLayer.strokeColor = strokeColor.CGColor; } - (void)setStrokeThickness:(CGFloat)strokeThickness { _strokeThickness = strokeThickness; _ringAnimatedLayer.lineWidth = _strokeThickness; } - (void)setStrokeEnd:(CGFloat)strokeEnd { _strokeEnd = strokeEnd; _ringAnimatedLayer.strokeEnd = _strokeEnd; } - (CGSize)sizeThatFits:(CGSize)size { return CGSizeMake((self.radius+self.strokeThickness/2+5)*2, (self.radius+self.strokeThickness/2+5)*2); } @end ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVProgressHUD.h ================================================ // // SVProgressHUD.h // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2011-2017 Sam Vermette and contributors. All rights reserved. // #import #import #if __IPHONE_OS_VERSION_MAX_ALLOWED < 70000 #define UI_APPEARANCE_SELECTOR #endif extern NSString * _Nonnull const SVProgressHUDDidReceiveTouchEventNotification; extern NSString * _Nonnull const SVProgressHUDDidTouchDownInsideNotification; extern NSString * _Nonnull const SVProgressHUDWillDisappearNotification; extern NSString * _Nonnull const SVProgressHUDDidDisappearNotification; extern NSString * _Nonnull const SVProgressHUDWillAppearNotification; extern NSString * _Nonnull const SVProgressHUDDidAppearNotification; extern NSString * _Nonnull const SVProgressHUDStatusUserInfoKey; typedef NS_ENUM(NSInteger, SVProgressHUDStyle) { SVProgressHUDStyleLight, // default style, white HUD with black text, HUD background will be blurred SVProgressHUDStyleDark, // black HUD and white text, HUD background will be blurred SVProgressHUDStyleCustom // uses the fore- and background color properties }; typedef NS_ENUM(NSUInteger, SVProgressHUDMaskType) { SVProgressHUDMaskTypeNone = 1, // default mask type, allow user interactions while HUD is displayed SVProgressHUDMaskTypeClear, // don't allow user interactions with background objects SVProgressHUDMaskTypeBlack, // don't allow user interactions with background objects and dim the UI in the back of the HUD (as seen in iOS 7 and above) SVProgressHUDMaskTypeGradient, // don't allow user interactions with background objects and dim the UI with a a-la UIAlertView background gradient (as seen in iOS 6) SVProgressHUDMaskTypeCustom // don't allow user interactions with background objects and dim the UI in the back of the HUD with a custom color }; typedef NS_ENUM(NSUInteger, SVProgressHUDAnimationType) { SVProgressHUDAnimationTypeFlat, // default animation type, custom flat animation (indefinite animated ring) SVProgressHUDAnimationTypeNative // iOS native UIActivityIndicatorView }; typedef void (^SVProgressHUDShowCompletion)(void); typedef void (^SVProgressHUDDismissCompletion)(void); @interface SVProgressHUD : UIView #pragma mark - Customization @property (assign, nonatomic) SVProgressHUDStyle defaultStyle UI_APPEARANCE_SELECTOR; // default is SVProgressHUDStyleLight @property (assign, nonatomic) SVProgressHUDMaskType defaultMaskType UI_APPEARANCE_SELECTOR; // default is SVProgressHUDMaskTypeNone @property (assign, nonatomic) SVProgressHUDAnimationType defaultAnimationType UI_APPEARANCE_SELECTOR; // default is SVProgressHUDAnimationTypeFlat @property (strong, nonatomic, nullable) UIView *containerView; // if nil then use default window level @property (assign, nonatomic) CGSize minimumSize UI_APPEARANCE_SELECTOR; // default is CGSizeZero, can be used to avoid resizing for a larger message @property (assign, nonatomic) CGFloat ringThickness UI_APPEARANCE_SELECTOR; // default is 2 pt @property (assign, nonatomic) CGFloat ringRadius UI_APPEARANCE_SELECTOR; // default is 18 pt @property (assign, nonatomic) CGFloat ringNoTextRadius UI_APPEARANCE_SELECTOR; // default is 24 pt @property (assign, nonatomic) CGFloat cornerRadius UI_APPEARANCE_SELECTOR; // default is 14 pt @property (strong, nonatomic, nonnull) UIFont *font UI_APPEARANCE_SELECTOR; // default is [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline] @property (strong, nonatomic, nonnull) UIColor *backgroundColor UI_APPEARANCE_SELECTOR; // default is [UIColor whiteColor] @property (strong, nonatomic, nonnull) UIColor *foregroundColor UI_APPEARANCE_SELECTOR; // default is [UIColor blackColor] @property (strong, nonatomic, nonnull) UIColor *backgroundLayerColor UI_APPEARANCE_SELECTOR;// default is [UIColor colorWithWhite:0 alpha:0.4] @property (assign, nonatomic) CGSize imageViewSize UI_APPEARANCE_SELECTOR; // default is 28x28 pt @property (strong, nonatomic, nonnull) UIImage *infoImage UI_APPEARANCE_SELECTOR; // default is the bundled info image provided by Freepik @property (strong, nonatomic, nonnull) UIImage *successImage UI_APPEARANCE_SELECTOR; // default is the bundled success image provided by Freepik @property (strong, nonatomic, nonnull) UIImage *errorImage UI_APPEARANCE_SELECTOR; // default is the bundled error image provided by Freepik @property (strong, nonatomic, nonnull) UIView *viewForExtension UI_APPEARANCE_SELECTOR; // default is nil, only used if #define SV_APP_EXTENSIONS is set @property (assign, nonatomic) NSTimeInterval graceTimeInterval; // default is 0 seconds @property (assign, nonatomic) NSTimeInterval minimumDismissTimeInterval; // default is 5.0 seconds @property (assign, nonatomic) NSTimeInterval maximumDismissTimeInterval; // default is CGFLOAT_MAX @property (assign, nonatomic) UIOffset offsetFromCenter UI_APPEARANCE_SELECTOR; // default is 0, 0 @property (assign, nonatomic) NSTimeInterval fadeInAnimationDuration UI_APPEARANCE_SELECTOR; // default is 0.15 @property (assign, nonatomic) NSTimeInterval fadeOutAnimationDuration UI_APPEARANCE_SELECTOR; // default is 0.15 @property (assign, nonatomic) UIWindowLevel maxSupportedWindowLevel; // default is UIWindowLevelNormal @property (assign, nonatomic) BOOL hapticsEnabled; // default is NO + (void)setDefaultStyle:(SVProgressHUDStyle)style; // default is SVProgressHUDStyleLight + (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType; // default is SVProgressHUDMaskTypeNone + (void)setDefaultAnimationType:(SVProgressHUDAnimationType)type; // default is SVProgressHUDAnimationTypeFlat + (void)setContainerView:(nullable UIView*)containerView; // default is window level + (void)setMinimumSize:(CGSize)minimumSize; // default is CGSizeZero, can be used to avoid resizing for a larger message + (void)setRingThickness:(CGFloat)ringThickness; // default is 2 pt + (void)setRingRadius:(CGFloat)radius; // default is 18 pt + (void)setRingNoTextRadius:(CGFloat)radius; // default is 24 pt + (void)setCornerRadius:(CGFloat)cornerRadius; // default is 14 pt + (void)setBorderColor:(nonnull UIColor*)color; // default is nil + (void)setBorderWidth:(CGFloat)width; // default is 0 + (void)setFont:(nonnull UIFont*)font; // default is [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline] + (void)setForegroundColor:(nonnull UIColor*)color; // default is [UIColor blackColor], only used for SVProgressHUDStyleCustom + (void)setBackgroundColor:(nonnull UIColor*)color; // default is [UIColor whiteColor], only used for SVProgressHUDStyleCustom + (void)setBackgroundLayerColor:(nonnull UIColor*)color; // default is [UIColor colorWithWhite:0 alpha:0.5], only used for SVProgressHUDMaskTypeCustom + (void)setImageViewSize:(CGSize)size; // default is 28x28 pt + (void)setInfoImage:(nonnull UIImage*)image; // default is the bundled info image provided by Freepik + (void)setSuccessImage:(nonnull UIImage*)image; // default is the bundled success image provided by Freepik + (void)setErrorImage:(nonnull UIImage*)image; // default is the bundled error image provided by Freepik + (void)setViewForExtension:(nonnull UIView*)view; // default is nil, only used if #define SV_APP_EXTENSIONS is set + (void)setGraceTimeInterval:(NSTimeInterval)interval; // default is 0 seconds + (void)setMinimumDismissTimeInterval:(NSTimeInterval)interval; // default is 5.0 seconds + (void)setMaximumDismissTimeInterval:(NSTimeInterval)interval; // default is infinite + (void)setFadeInAnimationDuration:(NSTimeInterval)duration; // default is 0.15 seconds + (void)setFadeOutAnimationDuration:(NSTimeInterval)duration; // default is 0.15 seconds + (void)setMaxSupportedWindowLevel:(UIWindowLevel)windowLevel; // default is UIWindowLevelNormal + (void)setHapticsEnabled:(BOOL)hapticsEnabled; // default is NO #pragma mark - Show Methods + (void)show; + (void)showWithMaskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use show and setDefaultMaskType: instead."))); + (void)showWithStatus:(nullable NSString*)status; + (void)showWithStatus:(nullable NSString*)status maskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use showWithStatus: and setDefaultMaskType: instead."))); + (void)showProgress:(float)progress; + (void)showProgress:(float)progress maskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use showProgress: and setDefaultMaskType: instead."))); + (void)showProgress:(float)progress status:(nullable NSString*)status; + (void)showProgress:(float)progress status:(nullable NSString*)status maskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use showProgress:status: and setDefaultMaskType: instead."))); + (void)setStatus:(nullable NSString*)status; // change the HUD loading status while it's showing // stops the activity indicator, shows a glyph + status, and dismisses the HUD a little bit later + (void)showInfoWithStatus:(nullable NSString*)status; + (void)showInfoWithStatus:(nullable NSString*)status maskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use showInfoWithStatus: and setDefaultMaskType: instead."))); + (void)showSuccessWithStatus:(nullable NSString*)status; + (void)showSuccessWithStatus:(nullable NSString*)status maskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use showSuccessWithStatus: and setDefaultMaskType: instead."))); + (void)showErrorWithStatus:(nullable NSString*)status; + (void)showErrorWithStatus:(nullable NSString*)status maskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use showErrorWithStatus: and setDefaultMaskType: instead."))); // shows a image + status, use white PNGs with the imageViewSize (default is 28x28 pt) + (void)showImage:(nonnull UIImage*)image status:(nullable NSString*)status; + (void)showImage:(nonnull UIImage*)image status:(nullable NSString*)status maskType:(SVProgressHUDMaskType)maskType __attribute__((deprecated("Use showImage:status: and setDefaultMaskType: instead."))); + (void)setOffsetFromCenter:(UIOffset)offset; + (void)resetOffsetFromCenter; + (void)popActivity; // decrease activity count, if activity count == 0 the HUD is dismissed + (void)dismiss; + (void)dismissWithCompletion:(nullable SVProgressHUDDismissCompletion)completion; + (void)dismissWithDelay:(NSTimeInterval)delay; + (void)dismissWithDelay:(NSTimeInterval)delay completion:(nullable SVProgressHUDDismissCompletion)completion; + (BOOL)isVisible; + (NSTimeInterval)displayDurationForString:(nullable NSString*)string; @end ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVProgressHUD.m ================================================ // // SVProgressHUD.h // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2011-2017 Sam Vermette and contributors. All rights reserved. // #if !__has_feature(objc_arc) #error SVProgressHUD is ARC only. Either turn on ARC for the project or use -fobjc-arc flag #endif #import "SVProgressHUD.h" #import "SVIndefiniteAnimatedView.h" #import "SVProgressAnimatedView.h" #import "SVRadialGradientLayer.h" NSString * const SVProgressHUDDidReceiveTouchEventNotification = @"SVProgressHUDDidReceiveTouchEventNotification"; NSString * const SVProgressHUDDidTouchDownInsideNotification = @"SVProgressHUDDidTouchDownInsideNotification"; NSString * const SVProgressHUDWillDisappearNotification = @"SVProgressHUDWillDisappearNotification"; NSString * const SVProgressHUDDidDisappearNotification = @"SVProgressHUDDidDisappearNotification"; NSString * const SVProgressHUDWillAppearNotification = @"SVProgressHUDWillAppearNotification"; NSString * const SVProgressHUDDidAppearNotification = @"SVProgressHUDDidAppearNotification"; NSString * const SVProgressHUDStatusUserInfoKey = @"SVProgressHUDStatusUserInfoKey"; static const CGFloat SVProgressHUDParallaxDepthPoints = 10.0f; static const CGFloat SVProgressHUDUndefinedProgress = -1; static const CGFloat SVProgressHUDDefaultAnimationDuration = 0.15f; static const CGFloat SVProgressHUDVerticalSpacing = 12.0f; static const CGFloat SVProgressHUDHorizontalSpacing = 12.0f; static const CGFloat SVProgressHUDLabelSpacing = 8.0f; @interface SVProgressHUD () @property (nonatomic, strong) NSTimer *graceTimer; @property (nonatomic, strong) NSTimer *fadeOutTimer; @property (nonatomic, strong) UIControl *controlView; @property (nonatomic, strong) UIView *backgroundView; @property (nonatomic, strong) SVRadialGradientLayer *backgroundRadialGradientLayer; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 @property (nonatomic, strong) UIVisualEffectView *hudView; #else @property (nonatomic, strong) UIView *hudView; #endif @property (nonatomic, strong) UILabel *statusLabel; @property (nonatomic, strong) UIImageView *imageView; @property (nonatomic, strong) UIView *indefiniteAnimatedView; @property (nonatomic, strong) SVProgressAnimatedView *ringView; @property (nonatomic, strong) SVProgressAnimatedView *backgroundRingView; @property (nonatomic, readwrite) CGFloat progress; @property (nonatomic, readwrite) NSUInteger activityCount; @property (nonatomic, readonly) CGFloat visibleKeyboardHeight; @property (nonatomic, readonly) UIWindow *frontWindow; #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 @property (nonatomic, strong) UINotificationFeedbackGenerator *hapticGenerator; #endif @end @implementation SVProgressHUD { BOOL _isInitializing; } + (SVProgressHUD*)sharedView { static dispatch_once_t once; static SVProgressHUD *sharedView; #if !defined(SV_APP_EXTENSIONS) dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[[[UIApplication sharedApplication] delegate] window].bounds]; }); #else dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; }); #endif return sharedView; } #pragma mark - Setters + (void)setStatus:(NSString*)status { [[self sharedView] setStatus:status]; } + (void)setDefaultStyle:(SVProgressHUDStyle)style { [self sharedView].defaultStyle = style; } + (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType { [self sharedView].defaultMaskType = maskType; } + (void)setDefaultAnimationType:(SVProgressHUDAnimationType)type { [self sharedView].defaultAnimationType = type; } + (void)setContainerView:(nullable UIView*)containerView { [self sharedView].containerView = containerView; } + (void)setMinimumSize:(CGSize)minimumSize { [self sharedView].minimumSize = minimumSize; } + (void)setRingThickness:(CGFloat)ringThickness { [self sharedView].ringThickness = ringThickness; } + (void)setRingRadius:(CGFloat)radius { [self sharedView].ringRadius = radius; } + (void)setRingNoTextRadius:(CGFloat)radius { [self sharedView].ringNoTextRadius = radius; } + (void)setCornerRadius:(CGFloat)cornerRadius { [self sharedView].cornerRadius = cornerRadius; } + (void)setBorderColor:(nonnull UIColor*)color { [self sharedView].hudView.layer.borderColor = color.CGColor; } + (void)setBorderWidth:(CGFloat)width { [self sharedView].hudView.layer.borderWidth = width; } + (void)setFont:(UIFont*)font { [self sharedView].font = font; } + (void)setForegroundColor:(UIColor*)color { [self sharedView].foregroundColor = color; [self setDefaultStyle:SVProgressHUDStyleCustom]; } + (void)setBackgroundColor:(UIColor*)color { [self sharedView].backgroundColor = color; [self setDefaultStyle:SVProgressHUDStyleCustom]; } + (void)setBackgroundLayerColor:(UIColor*)color { [self sharedView].backgroundLayerColor = color; } + (void)setImageViewSize:(CGSize)size { [self sharedView].imageViewSize = size; } + (void)setInfoImage:(UIImage*)image { [self sharedView].infoImage = image; } + (void)setSuccessImage:(UIImage*)image { [self sharedView].successImage = image; } + (void)setErrorImage:(UIImage*)image { [self sharedView].errorImage = image; } + (void)setViewForExtension:(UIView*)view { [self sharedView].viewForExtension = view; } + (void)setGraceTimeInterval:(NSTimeInterval)interval { [self sharedView].graceTimeInterval = interval; } + (void)setMinimumDismissTimeInterval:(NSTimeInterval)interval { [self sharedView].minimumDismissTimeInterval = interval; } + (void)setMaximumDismissTimeInterval:(NSTimeInterval)interval { [self sharedView].maximumDismissTimeInterval = interval; } + (void)setFadeInAnimationDuration:(NSTimeInterval)duration { [self sharedView].fadeInAnimationDuration = duration; } + (void)setFadeOutAnimationDuration:(NSTimeInterval)duration { [self sharedView].fadeOutAnimationDuration = duration; } + (void)setMaxSupportedWindowLevel:(UIWindowLevel)windowLevel { [self sharedView].maxSupportedWindowLevel = windowLevel; } + (void)setHapticsEnabled:(BOOL)hapticsEnabled { [self sharedView].hapticsEnabled = hapticsEnabled; } #pragma mark - Show Methods + (void)show { [self showWithStatus:nil]; } + (void)showWithMaskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self show]; [self setDefaultMaskType:existingMaskType]; } + (void)showWithStatus:(NSString*)status { [self showProgress:SVProgressHUDUndefinedProgress status:status]; } + (void)showWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self showWithStatus:status]; [self setDefaultMaskType:existingMaskType]; } + (void)showProgress:(float)progress { [self showProgress:progress status:nil]; } + (void)showProgress:(float)progress maskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self showProgress:progress]; [self setDefaultMaskType:existingMaskType]; } + (void)showProgress:(float)progress status:(NSString*)status { [[self sharedView] showProgress:progress status:status]; } + (void)showProgress:(float)progress status:(NSString*)status maskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self showProgress:progress status:status]; [self setDefaultMaskType:existingMaskType]; } #pragma mark - Show, then automatically dismiss methods + (void)showInfoWithStatus:(NSString*)status { [self showImage:[self sharedView].infoImage status:status]; #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 dispatch_async(dispatch_get_main_queue(), ^{ [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeWarning]; }); #endif } + (void)showInfoWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self showInfoWithStatus:status]; [self setDefaultMaskType:existingMaskType]; } + (void)showSuccessWithStatus:(NSString*)status { [self showImage:[self sharedView].successImage status:status]; #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 dispatch_async(dispatch_get_main_queue(), ^{ [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeSuccess]; }); #endif } + (void)showSuccessWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self showSuccessWithStatus:status]; [self setDefaultMaskType:existingMaskType]; #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 dispatch_async(dispatch_get_main_queue(), ^{ [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeSuccess]; }); #endif } + (void)showErrorWithStatus:(NSString*)status { [self showImage:[self sharedView].errorImage status:status]; #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 dispatch_async(dispatch_get_main_queue(), ^{ [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeError]; }); #endif } + (void)showErrorWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self showErrorWithStatus:status]; [self setDefaultMaskType:existingMaskType]; #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 dispatch_async(dispatch_get_main_queue(), ^{ [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeError]; }); #endif } + (void)showImage:(UIImage*)image status:(NSString*)status { NSTimeInterval displayInterval = [self displayDurationForString:status]; [[self sharedView] showImage:image status:status duration:displayInterval]; } + (void)showImage:(UIImage*)image status:(NSString*)status maskType:(SVProgressHUDMaskType)maskType { SVProgressHUDMaskType existingMaskType = [self sharedView].defaultMaskType; [self setDefaultMaskType:maskType]; [self showImage:image status:status]; [self setDefaultMaskType:existingMaskType]; } #pragma mark - Dismiss Methods + (void)popActivity { if([self sharedView].activityCount > 0) { [self sharedView].activityCount--; } if([self sharedView].activityCount == 0) { [[self sharedView] dismiss]; } } + (void)dismiss { [self dismissWithDelay:0.0 completion:nil]; } + (void)dismissWithCompletion:(SVProgressHUDDismissCompletion)completion { [self dismissWithDelay:0.0 completion:completion]; } + (void)dismissWithDelay:(NSTimeInterval)delay { [self dismissWithDelay:delay completion:nil]; } + (void)dismissWithDelay:(NSTimeInterval)delay completion:(SVProgressHUDDismissCompletion)completion { [[self sharedView] dismissWithDelay:delay completion:completion]; } #pragma mark - Offset + (void)setOffsetFromCenter:(UIOffset)offset { [self sharedView].offsetFromCenter = offset; } + (void)resetOffsetFromCenter { [self setOffsetFromCenter:UIOffsetZero]; } #pragma mark - Instance Methods - (instancetype)initWithFrame:(CGRect)frame { if((self = [super initWithFrame:frame])) { _isInitializing = YES; self.userInteractionEnabled = NO; self.activityCount = 0; self.backgroundView.alpha = 0.0f; self.imageView.alpha = 0.0f; self.statusLabel.alpha = 0.0f; self.indefiniteAnimatedView.alpha = 0.0f; self.ringView.alpha = self.backgroundRingView.alpha = 0.0f; _backgroundColor = [UIColor whiteColor]; _foregroundColor = [UIColor blackColor]; _backgroundLayerColor = [UIColor colorWithWhite:0 alpha:0.4]; // Set default values _defaultMaskType = SVProgressHUDMaskTypeNone; _defaultStyle = SVProgressHUDStyleLight; _defaultAnimationType = SVProgressHUDAnimationTypeFlat; _minimumSize = CGSizeZero; _font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; NSBundle *bundle = [NSBundle bundleForClass:[SVProgressHUD class]]; NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"]; NSBundle *imageBundle = [NSBundle bundleWithURL:url]; UIImage* infoImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"info" ofType:@"png"]]; UIImage* successImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"success" ofType:@"png"]]; UIImage* errorImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"error" ofType:@"png"]]; _infoImage = [infoImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; _successImage = [successImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; _errorImage = [errorImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; _ringThickness = 2.0f; _ringRadius = 18.0f; _ringNoTextRadius = 24.0f; _cornerRadius = 14.0f; _imageViewSize = CGSizeMake(28.0f, 28.0f); _graceTimeInterval = 0.0f; _minimumDismissTimeInterval = 5.0; _maximumDismissTimeInterval = CGFLOAT_MAX; _fadeInAnimationDuration = SVProgressHUDDefaultAnimationDuration; _fadeOutAnimationDuration = SVProgressHUDDefaultAnimationDuration; _maxSupportedWindowLevel = UIWindowLevelNormal; _hapticsEnabled = NO; // Accessibility support self.accessibilityIdentifier = @"SVProgressHUD"; self.isAccessibilityElement = YES; _isInitializing = NO; } return self; } - (void)updateHUDFrame { // Check if an image or progress ring is displayed BOOL imageUsed = (self.imageView.image) && !(self.imageView.hidden); BOOL progressUsed = self.imageView.hidden; // Calculate size of string CGRect labelRect = CGRectZero; CGFloat labelHeight = 0.0f; CGFloat labelWidth = 0.0f; if(self.statusLabel.text) { CGSize constraintSize = CGSizeMake(200.0f, 300.0f); labelRect = [self.statusLabel.text boundingRectWithSize:constraintSize options:(NSStringDrawingOptions)(NSStringDrawingUsesFontLeading | NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin) attributes:@{NSFontAttributeName: self.statusLabel.font} context:NULL]; labelHeight = ceilf(CGRectGetHeight(labelRect)); labelWidth = ceilf(CGRectGetWidth(labelRect)); } // Calculate hud size based on content // For the beginning use default values, these // might get update if string is too large etc. CGFloat hudWidth; CGFloat hudHeight; CGFloat contentWidth = 0.0f; CGFloat contentHeight = 0.0f; if(imageUsed || progressUsed) { contentWidth = CGRectGetWidth(imageUsed ? self.imageView.frame : self.indefiniteAnimatedView.frame); contentHeight = CGRectGetHeight(imageUsed ? self.imageView.frame : self.indefiniteAnimatedView.frame); } // |-spacing-content-spacing-| hudWidth = SVProgressHUDHorizontalSpacing + MAX(labelWidth, contentWidth) + SVProgressHUDHorizontalSpacing; // |-spacing-content-(labelSpacing-label-)spacing-| hudHeight = SVProgressHUDVerticalSpacing + labelHeight + contentHeight + SVProgressHUDVerticalSpacing; if(self.statusLabel.text && (imageUsed || progressUsed)){ // Add spacing if both content and label are used hudHeight += SVProgressHUDLabelSpacing; } // Update values on subviews self.hudView.bounds = CGRectMake(0.0f, 0.0f, MAX(self.minimumSize.width, hudWidth), MAX(self.minimumSize.height, hudHeight)); // Animate value update [CATransaction begin]; [CATransaction setDisableActions:YES]; // Spinner and image view CGFloat centerY; if(self.statusLabel.text) { CGFloat yOffset = MAX(SVProgressHUDVerticalSpacing, (self.minimumSize.height - contentHeight - SVProgressHUDLabelSpacing - labelHeight) / 2.0f); centerY = yOffset + contentHeight / 2.0f; } else { centerY = CGRectGetMidY(self.hudView.bounds); } self.indefiniteAnimatedView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY); if(self.progress != SVProgressHUDUndefinedProgress) { self.backgroundRingView.center = self.ringView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY); } self.imageView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY); // Label if(imageUsed || progressUsed) { centerY = CGRectGetMaxY(imageUsed ? self.imageView.frame : self.indefiniteAnimatedView.frame) + SVProgressHUDLabelSpacing + labelHeight / 2.0f; } else { centerY = CGRectGetMidY(self.hudView.bounds); } self.statusLabel.frame = labelRect; self.statusLabel.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY); [CATransaction commit]; } #if TARGET_OS_IOS - (void)updateMotionEffectForOrientation:(UIInterfaceOrientation)orientation { UIInterpolatingMotionEffectType xMotionEffectType = UIInterfaceOrientationIsPortrait(orientation) ? UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis : UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis; UIInterpolatingMotionEffectType yMotionEffectType = UIInterfaceOrientationIsPortrait(orientation) ? UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis : UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis; [self updateMotionEffectForXMotionEffectType:xMotionEffectType yMotionEffectType:yMotionEffectType]; } #endif - (void)updateMotionEffectForXMotionEffectType:(UIInterpolatingMotionEffectType)xMotionEffectType yMotionEffectType:(UIInterpolatingMotionEffectType)yMotionEffectType { UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:xMotionEffectType]; effectX.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints); effectX.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints); UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:yMotionEffectType]; effectY.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints); effectY.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints); UIMotionEffectGroup *effectGroup = [UIMotionEffectGroup new]; effectGroup.motionEffects = @[effectX, effectY]; // Clear old motion effect, then add new motion effects self.hudView.motionEffects = @[]; [self.hudView addMotionEffect:effectGroup]; } - (void)updateViewHierarchy { // Add the overlay to the application window if necessary if(!self.controlView.superview) { if(self.containerView){ [self.containerView addSubview:self.controlView]; } else { #if !defined(SV_APP_EXTENSIONS) [self.frontWindow addSubview:self.controlView]; #else // If SVProgressHUD is used inside an app extension add it to the given view if(self.viewForExtension) { [self.viewForExtension addSubview:self.controlView]; } #endif } } else { // The HUD is already on screen, but maybe not in front. Therefore // ensure that overlay will be on top of rootViewController (which may // be changed during runtime). [self.controlView.superview bringSubviewToFront:self.controlView]; } // Add self to the overlay view if(!self.superview) { [self.controlView addSubview:self]; } } - (void)setStatus:(NSString*)status { self.statusLabel.text = status; [self updateHUDFrame]; } - (void)setGraceTimer:(NSTimer*)timer { if(_graceTimer) { [_graceTimer invalidate]; _graceTimer = nil; } if(timer) { _graceTimer = timer; } } - (void)setFadeOutTimer:(NSTimer*)timer { if(_fadeOutTimer) { [_fadeOutTimer invalidate]; _fadeOutTimer = nil; } if(timer) { _fadeOutTimer = timer; } } #pragma mark - Notifications and their handling - (void)registerNotifications { #if TARGET_OS_IOS [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(positionHUD:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(positionHUD:) name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(positionHUD:) name:UIKeyboardDidHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(positionHUD:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(positionHUD:) name:UIKeyboardDidShowNotification object:nil]; #endif [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(positionHUD:) name:UIApplicationDidBecomeActiveNotification object:nil]; } - (NSDictionary*)notificationUserInfo { return (self.statusLabel.text ? @{SVProgressHUDStatusUserInfoKey : self.statusLabel.text} : nil); } - (void)positionHUD:(NSNotification*)notification { CGFloat keyboardHeight = 0.0f; double animationDuration = 0.0; #if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS self.frame = [[[UIApplication sharedApplication] delegate] window].bounds; UIInterfaceOrientation orientation = UIApplication.sharedApplication.statusBarOrientation; #elif !defined(SV_APP_EXTENSIONS) && !TARGET_OS_IOS self.frame= [UIApplication sharedApplication].keyWindow.bounds; #else if (self.viewForExtension) { self.frame = self.viewForExtension.frame; } else { self.frame = UIScreen.mainScreen.bounds; } #if TARGET_OS_IOS UIInterfaceOrientation orientation = CGRectGetWidth(self.frame) > CGRectGetHeight(self.frame) ? UIInterfaceOrientationLandscapeLeft : UIInterfaceOrientationPortrait; #endif #endif // No transforms applied to window in iOS 8, but only if compiled with iOS 8 SDK as base SDK, otherwise system supports old rotation logic. BOOL ignoreOrientation = NO; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 if([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) { ignoreOrientation = YES; } #endif #if TARGET_OS_IOS // Get keyboardHeight in regard to current state if(notification) { NSDictionary* keyboardInfo = [notification userInfo]; CGRect keyboardFrame = [keyboardInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; animationDuration = [keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; if(notification.name == UIKeyboardWillShowNotification || notification.name == UIKeyboardDidShowNotification) { keyboardHeight = CGRectGetWidth(keyboardFrame); if(ignoreOrientation || UIInterfaceOrientationIsPortrait(orientation)) { keyboardHeight = CGRectGetHeight(keyboardFrame); } } } else { keyboardHeight = self.visibleKeyboardHeight; } #endif // Get the currently active frame of the display (depends on orientation) CGRect orientationFrame = self.bounds; #if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS CGRect statusBarFrame = UIApplication.sharedApplication.statusBarFrame; #else CGRect statusBarFrame = CGRectZero; #endif #if TARGET_OS_IOS if(!ignoreOrientation && UIInterfaceOrientationIsLandscape(orientation)) { float temp = CGRectGetWidth(orientationFrame); orientationFrame.size.width = CGRectGetHeight(orientationFrame); orientationFrame.size.height = temp; temp = CGRectGetWidth(statusBarFrame); statusBarFrame.size.width = CGRectGetHeight(statusBarFrame); statusBarFrame.size.height = temp; } // Update the motion effects in regard to orientation [self updateMotionEffectForOrientation:orientation]; #else [self updateMotionEffectForXMotionEffectType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis yMotionEffectType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; #endif // Calculate available height for display CGFloat activeHeight = CGRectGetHeight(orientationFrame); if(keyboardHeight > 0) { activeHeight += CGRectGetHeight(statusBarFrame) * 2; } activeHeight -= keyboardHeight; CGFloat posX = CGRectGetMidX(orientationFrame); CGFloat posY = floorf(activeHeight*0.45f); CGFloat rotateAngle = 0.0; CGPoint newCenter = CGPointMake(posX, posY); if(notification) { // Animate update if notification was present [UIView animateWithDuration:animationDuration delay:0 options:(UIViewAnimationOptions) (UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState) animations:^{ [self moveToPoint:newCenter rotateAngle:rotateAngle]; [self.hudView setNeedsDisplay]; } completion:nil]; } else { [self moveToPoint:newCenter rotateAngle:rotateAngle]; } } - (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle { self.hudView.transform = CGAffineTransformMakeRotation(angle); if (self.containerView) { self.hudView.center = CGPointMake(self.containerView.center.x + self.offsetFromCenter.horizontal, self.containerView.center.y + self.offsetFromCenter.vertical); } else { self.hudView.center = CGPointMake(newCenter.x + self.offsetFromCenter.horizontal, newCenter.y + self.offsetFromCenter.vertical); } } #pragma mark - Event handling - (void)controlViewDidReceiveTouchEvent:(id)sender forEvent:(UIEvent*)event { [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidReceiveTouchEventNotification object:self userInfo:[self notificationUserInfo]]; UITouch *touch = event.allTouches.anyObject; CGPoint touchLocation = [touch locationInView:self]; if(CGRectContainsPoint(self.hudView.frame, touchLocation)) { [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidTouchDownInsideNotification object:self userInfo:[self notificationUserInfo]]; } } #pragma mark - Master show/dismiss methods - (void)showProgress:(float)progress status:(NSString*)status { __weak SVProgressHUD *weakSelf = self; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ __strong SVProgressHUD *strongSelf = weakSelf; if(strongSelf){ if(strongSelf.fadeOutTimer) { strongSelf.activityCount = 0; } // Stop timer strongSelf.fadeOutTimer = nil; strongSelf.graceTimer = nil; // Update / Check view hierarchy to ensure the HUD is visible [strongSelf updateViewHierarchy]; // Reset imageView and fadeout timer if an image is currently displayed strongSelf.imageView.hidden = YES; strongSelf.imageView.image = nil; // Update text and set progress to the given value strongSelf.statusLabel.hidden = status.length == 0; strongSelf.statusLabel.text = status; strongSelf.progress = progress; // Choose the "right" indicator depending on the progress if(progress >= 0) { // Cancel the indefiniteAnimatedView, then show the ringLayer [strongSelf cancelIndefiniteAnimatedViewAnimation]; // Add ring to HUD if(!strongSelf.ringView.superview){ #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 [strongSelf.hudView.contentView addSubview:strongSelf.ringView]; #else [strongSelf.hudView addSubview:strongSelf.ringView]; #endif } if(!strongSelf.backgroundRingView.superview){ #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 [strongSelf.hudView.contentView addSubview:strongSelf.backgroundRingView]; #else [strongSelf.hudView addSubview:strongSelf.backgroundRingView]; #endif } // Set progress animated [CATransaction begin]; [CATransaction setDisableActions:YES]; strongSelf.ringView.strokeEnd = progress; [CATransaction commit]; // Update the activity count if(progress == 0) { strongSelf.activityCount++; } } else { // Cancel the ringLayer animation, then show the indefiniteAnimatedView [strongSelf cancelRingLayerAnimation]; // Add indefiniteAnimatedView to HUD #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 [strongSelf.hudView.contentView addSubview:strongSelf.indefiniteAnimatedView]; #else [strongSelf.hudView addSubview:strongSelf.indefiniteAnimatedView]; #endif if([strongSelf.indefiniteAnimatedView respondsToSelector:@selector(startAnimating)]) { [(id)strongSelf.indefiniteAnimatedView startAnimating]; } // Update the activity count strongSelf.activityCount++; } // Fade in delayed if a grace time is set if (self.graceTimeInterval > 0.0 && self.backgroundView.alpha == 0.0f) { strongSelf.graceTimer = [NSTimer timerWithTimeInterval:self.graceTimeInterval target:strongSelf selector:@selector(fadeIn:) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:strongSelf.graceTimer forMode:NSRunLoopCommonModes]; } else { [strongSelf fadeIn:nil]; } // Tell the Haptics Generator to prepare for feedback, which may come soon #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 [strongSelf.hapticGenerator prepare]; #endif } }]; } - (void)showImage:(UIImage*)image status:(NSString*)status duration:(NSTimeInterval)duration { __weak SVProgressHUD *weakSelf = self; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ __strong SVProgressHUD *strongSelf = weakSelf; if(strongSelf){ // Stop timer strongSelf.fadeOutTimer = nil; strongSelf.graceTimer = nil; // Update / Check view hierarchy to ensure the HUD is visible [strongSelf updateViewHierarchy]; // Reset progress and cancel any running animation strongSelf.progress = SVProgressHUDUndefinedProgress; [strongSelf cancelRingLayerAnimation]; [strongSelf cancelIndefiniteAnimatedViewAnimation]; // Update imageView strongSelf.imageView.tintColor = strongSelf.foregroundColorForStyle; strongSelf.imageView.image = image; strongSelf.imageView.hidden = NO; // Update text strongSelf.statusLabel.hidden = status.length == 0; strongSelf.statusLabel.text = status; // Fade in delayed if a grace time is set // An image will be dismissed automatically. Thus pass the duration as userInfo. if (self.graceTimeInterval > 0.0 && self.backgroundView.alpha == 0.0f) { strongSelf.graceTimer = [NSTimer timerWithTimeInterval:self.graceTimeInterval target:strongSelf selector:@selector(fadeIn:) userInfo:@(duration) repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:strongSelf.graceTimer forMode:NSRunLoopCommonModes]; } else { [strongSelf fadeIn:@(duration)]; } } }]; } - (void)fadeIn:(id)data { // Update the HUDs frame to the new content and position HUD [self updateHUDFrame]; [self positionHUD:nil]; // Update accessibility as well as user interaction if(self.defaultMaskType != SVProgressHUDMaskTypeNone) { self.controlView.userInteractionEnabled = YES; self.accessibilityLabel = self.statusLabel.text ?: NSLocalizedString(@"Loading", nil); self.isAccessibilityElement = YES; } else { self.controlView.userInteractionEnabled = NO; self.hudView.accessibilityLabel = self.statusLabel.text ?: NSLocalizedString(@"Loading", nil); self.hudView.isAccessibilityElement = YES; } // Get duration id duration = [data isKindOfClass:[NSTimer class]] ? ((NSTimer *)data).userInfo : data; // Show if not already visible if(self.backgroundView.alpha != 1.0f) { // Post notification to inform user [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillAppearNotification object:self userInfo:[self notificationUserInfo]]; // Shrink HUD to to make a nice appear / pop up animation self.hudView.transform = self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1/1.5f, 1/1.5f); __block void (^animationsBlock)(void) = ^{ // Zoom HUD a little to make a nice appear / pop up animation self.hudView.transform = CGAffineTransformIdentity; // Fade in all effects (colors, blur, etc.) [self fadeInEffects]; }; __block void (^completionBlock)(void) = ^{ // Check if we really achieved to show the HUD (<=> alpha) // and the change of these values has not been cancelled in between e.g. due to a dismissal if(self.backgroundView.alpha == 1.0f){ // Register observer <=> we now have to handle orientation changes etc. [self registerNotifications]; // Post notification to inform user [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidAppearNotification object:self userInfo:[self notificationUserInfo]]; // Update accessibility UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.statusLabel.text); // Dismiss automatically if a duration was passed as userInfo. We start a timer // which then will call dismiss after the predefined duration if(duration){ self.fadeOutTimer = [NSTimer timerWithTimeInterval:[(NSNumber *)duration doubleValue] target:self selector:@selector(dismiss) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:self.fadeOutTimer forMode:NSRunLoopCommonModes]; } } }; // Animate appearance if (self.fadeInAnimationDuration > 0) { // Animate appearance [UIView animateWithDuration:self.fadeInAnimationDuration delay:0 options:(UIViewAnimationOptions) (UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState) animations:^{ animationsBlock(); } completion:^(BOOL finished) { completionBlock(); }]; } else { animationsBlock(); completionBlock(); } // Inform iOS to redraw the view hierarchy [self setNeedsDisplay]; } else { // Update accessibility UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.statusLabel.text); // Dismiss automatically if a duration was passed as userInfo. We start a timer // which then will call dismiss after the predefined duration if(duration){ self.fadeOutTimer = [NSTimer timerWithTimeInterval:[(NSNumber *)duration doubleValue] target:self selector:@selector(dismiss) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:self.fadeOutTimer forMode:NSRunLoopCommonModes]; } } } - (void)dismiss { [self dismissWithDelay:0.0 completion:nil]; } - (void)dismissWithDelay:(NSTimeInterval)delay completion:(SVProgressHUDDismissCompletion)completion { __weak SVProgressHUD *weakSelf = self; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ __strong SVProgressHUD *strongSelf = weakSelf; if(strongSelf){ // Stop timer strongSelf.graceTimer = nil; // Post notification to inform user [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillDisappearNotification object:nil userInfo:[strongSelf notificationUserInfo]]; // Reset activity count strongSelf.activityCount = 0; __block void (^animationsBlock)(void) = ^{ // Shrink HUD a little to make a nice disappear animation strongSelf.hudView.transform = CGAffineTransformScale(strongSelf.hudView.transform, 1/1.3f, 1/1.3f); // Fade out all effects (colors, blur, etc.) [strongSelf fadeOutEffects]; }; __block void (^completionBlock)(void) = ^{ // Check if we really achieved to dismiss the HUD (<=> alpha values are applied) // and the change of these values has not been cancelled in between e.g. due to a new show if(self.backgroundView.alpha == 0.0f){ // Clean up view hierarchy (overlays) [strongSelf.controlView removeFromSuperview]; [strongSelf.backgroundView removeFromSuperview]; [strongSelf.hudView removeFromSuperview]; [strongSelf removeFromSuperview]; // Reset progress and cancel any running animation strongSelf.progress = SVProgressHUDUndefinedProgress; [strongSelf cancelRingLayerAnimation]; [strongSelf cancelIndefiniteAnimatedViewAnimation]; // Remove observer <=> we do not have to handle orientation changes etc. [[NSNotificationCenter defaultCenter] removeObserver:strongSelf]; // Post notification to inform user [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidDisappearNotification object:strongSelf userInfo:[strongSelf notificationUserInfo]]; // Tell the rootViewController to update the StatusBar appearance #if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS UIViewController *rootController = [[UIApplication sharedApplication] keyWindow].rootViewController; [rootController setNeedsStatusBarAppearanceUpdate]; #endif // Run an (optional) completionHandler if (completion) { completion(); } } }; // UIViewAnimationOptionBeginFromCurrentState AND a delay doesn't always work as expected // When UIViewAnimationOptionBeginFromCurrentState is set, animateWithDuration: evaluates the current // values to check if an animation is necessary. The evaluation happens at function call time and not // after the delay => the animation is sometimes skipped. Therefore we delay using dispatch_after. dispatch_time_t dipatchTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)); dispatch_after(dipatchTime, dispatch_get_main_queue(), ^{ if (strongSelf.fadeOutAnimationDuration > 0) { // Animate appearance [UIView animateWithDuration:strongSelf.fadeOutAnimationDuration delay:0 options:(UIViewAnimationOptions) (UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState) animations:^{ animationsBlock(); } completion:^(BOOL finished) { completionBlock(); }]; } else { animationsBlock(); completionBlock(); } }); // Inform iOS to redraw the view hierarchy [strongSelf setNeedsDisplay]; } }]; } #pragma mark - Ring progress animation - (UIView*)indefiniteAnimatedView { // Get the correct spinner for defaultAnimationType if(self.defaultAnimationType == SVProgressHUDAnimationTypeFlat){ // Check if spinner exists and is an object of different class if(_indefiniteAnimatedView && ![_indefiniteAnimatedView isKindOfClass:[SVIndefiniteAnimatedView class]]){ [_indefiniteAnimatedView removeFromSuperview]; _indefiniteAnimatedView = nil; } if(!_indefiniteAnimatedView){ _indefiniteAnimatedView = [[SVIndefiniteAnimatedView alloc] initWithFrame:CGRectZero]; } // Update styling SVIndefiniteAnimatedView *indefiniteAnimatedView = (SVIndefiniteAnimatedView*)_indefiniteAnimatedView; indefiniteAnimatedView.strokeColor = self.foregroundColorForStyle; indefiniteAnimatedView.strokeThickness = self.ringThickness; indefiniteAnimatedView.radius = self.statusLabel.text ? self.ringRadius : self.ringNoTextRadius; } else { // Check if spinner exists and is an object of different class if(_indefiniteAnimatedView && ![_indefiniteAnimatedView isKindOfClass:[UIActivityIndicatorView class]]){ [_indefiniteAnimatedView removeFromSuperview]; _indefiniteAnimatedView = nil; } if(!_indefiniteAnimatedView){ _indefiniteAnimatedView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; } // Update styling UIActivityIndicatorView *activityIndicatorView = (UIActivityIndicatorView*)_indefiniteAnimatedView; activityIndicatorView.color = self.foregroundColorForStyle; } [_indefiniteAnimatedView sizeToFit]; return _indefiniteAnimatedView; } - (SVProgressAnimatedView*)ringView { if(!_ringView) { _ringView = [[SVProgressAnimatedView alloc] initWithFrame:CGRectZero]; } // Update styling _ringView.strokeColor = self.foregroundColorForStyle; _ringView.strokeThickness = self.ringThickness; _ringView.radius = self.statusLabel.text ? self.ringRadius : self.ringNoTextRadius; return _ringView; } - (SVProgressAnimatedView*)backgroundRingView { if(!_backgroundRingView) { _backgroundRingView = [[SVProgressAnimatedView alloc] initWithFrame:CGRectZero]; _backgroundRingView.strokeEnd = 1.0f; } // Update styling _backgroundRingView.strokeColor = [self.foregroundColorForStyle colorWithAlphaComponent:0.1f]; _backgroundRingView.strokeThickness = self.ringThickness; _backgroundRingView.radius = self.statusLabel.text ? self.ringRadius : self.ringNoTextRadius; return _backgroundRingView; } - (void)cancelRingLayerAnimation { // Animate value update, stop animation [CATransaction begin]; [CATransaction setDisableActions:YES]; [self.hudView.layer removeAllAnimations]; self.ringView.strokeEnd = 0.0f; [CATransaction commit]; // Remove from view [self.ringView removeFromSuperview]; [self.backgroundRingView removeFromSuperview]; } - (void)cancelIndefiniteAnimatedViewAnimation { // Stop animation if([self.indefiniteAnimatedView respondsToSelector:@selector(stopAnimating)]) { [(id)self.indefiniteAnimatedView stopAnimating]; } // Remove from view [self.indefiniteAnimatedView removeFromSuperview]; } #pragma mark - Utilities + (BOOL)isVisible { // Checking one alpha value is sufficient as they are all the same return [self sharedView].backgroundView.alpha > 0.0f; } #pragma mark - Getters + (NSTimeInterval)displayDurationForString:(NSString*)string { CGFloat minimum = MAX((CGFloat)string.length * 0.06 + 0.5, [self sharedView].minimumDismissTimeInterval); return MIN(minimum, [self sharedView].maximumDismissTimeInterval); } - (UIColor*)foregroundColorForStyle { if(self.defaultStyle == SVProgressHUDStyleLight) { return [UIColor blackColor]; } else if(self.defaultStyle == SVProgressHUDStyleDark) { return [UIColor whiteColor]; } else { return self.foregroundColor; } } - (UIColor*)backgroundColorForStyle { if(self.defaultStyle == SVProgressHUDStyleLight) { return [UIColor whiteColor]; } else if(self.defaultStyle == SVProgressHUDStyleDark) { return [UIColor blackColor]; } else { return self.backgroundColor; } } - (UIControl*)controlView { if(!_controlView) { _controlView = [UIControl new]; _controlView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _controlView.backgroundColor = [UIColor clearColor]; _controlView.userInteractionEnabled = YES; [_controlView addTarget:self action:@selector(controlViewDidReceiveTouchEvent:forEvent:) forControlEvents:UIControlEventTouchDown]; } // Update frames #if !defined(SV_APP_EXTENSIONS) CGRect windowBounds = [[[UIApplication sharedApplication] delegate] window].bounds; _controlView.frame = windowBounds; #else _controlView.frame = [UIScreen mainScreen].bounds; #endif return _controlView; } -(UIView *)backgroundView { if(!_backgroundView){ _backgroundView = [UIView new]; _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; } if(!_backgroundView.superview){ [self insertSubview:_backgroundView belowSubview:self.hudView]; } // Update styling if(self.defaultMaskType == SVProgressHUDMaskTypeGradient){ if(!_backgroundRadialGradientLayer){ _backgroundRadialGradientLayer = [SVRadialGradientLayer layer]; } if(!_backgroundRadialGradientLayer.superlayer){ [_backgroundView.layer insertSublayer:_backgroundRadialGradientLayer atIndex:0]; } _backgroundView.backgroundColor = [UIColor clearColor]; } else { if(_backgroundRadialGradientLayer && _backgroundRadialGradientLayer.superlayer){ [_backgroundRadialGradientLayer removeFromSuperlayer]; } if(self.defaultMaskType == SVProgressHUDMaskTypeBlack){ _backgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4]; } else if(self.defaultMaskType == SVProgressHUDMaskTypeCustom){ _backgroundView.backgroundColor = self.backgroundLayerColor; } else { _backgroundView.backgroundColor = [UIColor clearColor]; } } // Update frame if(_backgroundView){ _backgroundView.frame = self.bounds; } if(_backgroundRadialGradientLayer){ _backgroundRadialGradientLayer.frame = self.bounds; // Calculate the new center of the gradient, it may change if keyboard is visible CGPoint gradientCenter = self.center; gradientCenter.y = (self.bounds.size.height - self.visibleKeyboardHeight)/2; _backgroundRadialGradientLayer.gradientCenter = gradientCenter; [_backgroundRadialGradientLayer setNeedsDisplay]; } return _backgroundView; } #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 - (UIVisualEffectView*)hudView { #else - (UIView*)hudView { #endif if(!_hudView) { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 _hudView = [UIVisualEffectView new]; #else _hudView = [UIView new]; #endif _hudView.layer.masksToBounds = YES; _hudView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin; } if(!_hudView.superview) { [self addSubview:_hudView]; } // Update styling _hudView.layer.cornerRadius = self.cornerRadius; return _hudView; } - (UILabel*)statusLabel { if(!_statusLabel) { _statusLabel = [[UILabel alloc] initWithFrame:CGRectZero]; _statusLabel.backgroundColor = [UIColor clearColor]; _statusLabel.adjustsFontSizeToFitWidth = YES; _statusLabel.textAlignment = NSTextAlignmentCenter; _statusLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; _statusLabel.numberOfLines = 0; } if(!_statusLabel.superview) { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 [self.hudView.contentView addSubview:_statusLabel]; #else [self.hudView addSubview:_statusLabel]; #endif } // Update styling _statusLabel.textColor = self.foregroundColorForStyle; _statusLabel.font = self.font; return _statusLabel; } - (UIImageView*)imageView { if(_imageView && !CGSizeEqualToSize(_imageView.bounds.size, _imageViewSize)) { [_imageView removeFromSuperview]; _imageView = nil; } if(!_imageView) { _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _imageViewSize.width, _imageViewSize.height)]; } if(!_imageView.superview) { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 [self.hudView.contentView addSubview:_imageView]; #else [self.hudView addSubview:_imageView]; #endif } return _imageView; } #pragma mark - Helper - (CGFloat)visibleKeyboardHeight { #if !defined(SV_APP_EXTENSIONS) UIWindow *keyboardWindow = nil; for (UIWindow *testWindow in UIApplication.sharedApplication.windows) { if(![testWindow.class isEqual:UIWindow.class]) { keyboardWindow = testWindow; break; } } for (__strong UIView *possibleKeyboard in keyboardWindow.subviews) { NSString *viewName = NSStringFromClass(possibleKeyboard.class); if([viewName hasPrefix:@"UI"]){ if([viewName hasSuffix:@"PeripheralHostView"] || [viewName hasSuffix:@"Keyboard"]){ return CGRectGetHeight(possibleKeyboard.bounds); } else if ([viewName hasSuffix:@"InputSetContainerView"]){ for (__strong UIView *possibleKeyboardSubview in possibleKeyboard.subviews) { viewName = NSStringFromClass(possibleKeyboardSubview.class); if([viewName hasPrefix:@"UI"] && [viewName hasSuffix:@"InputSetHostView"]) { return CGRectGetHeight(possibleKeyboardSubview.bounds); } } } } } #endif return 0; } - (UIWindow *)frontWindow { #if !defined(SV_APP_EXTENSIONS) NSEnumerator *frontToBackWindows = [UIApplication.sharedApplication.windows reverseObjectEnumerator]; for (UIWindow *window in frontToBackWindows) { BOOL windowOnMainScreen = window.screen == UIScreen.mainScreen; BOOL windowIsVisible = !window.hidden && window.alpha > 0; BOOL windowLevelSupported = (window.windowLevel >= UIWindowLevelNormal && window.windowLevel <= self.maxSupportedWindowLevel); BOOL windowKeyWindow = window.isKeyWindow; if(windowOnMainScreen && windowIsVisible && windowLevelSupported && windowKeyWindow) { return window; } } #endif return nil; } - (void)fadeInEffects { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 if(self.defaultStyle != SVProgressHUDStyleCustom) { // Add blur effect UIBlurEffectStyle blurEffectStyle = self.defaultStyle == SVProgressHUDStyleDark ? UIBlurEffectStyleDark : UIBlurEffectStyleLight; UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:blurEffectStyle]; self.hudView.effect = blurEffect; // We omit UIVibrancy effect and use a suitable background color as an alternative. // This will make everyting more readable. See the following for details: // https://www.omnigroup.com/developer/how-to-make-text-in-a-uivisualeffectview-readable-on-any-background self.hudView.backgroundColor = [self.backgroundColorForStyle colorWithAlphaComponent:0.6f]; } else { self.hudView.backgroundColor = self.backgroundColorForStyle; } #else self.hudView.backgroundColor = self.backgroundColorForStyle; #endif // Fade in views self.backgroundView.alpha = 1.0f; self.imageView.alpha = 1.0f; self.statusLabel.alpha = 1.0f; self.indefiniteAnimatedView.alpha = 1.0f; self.ringView.alpha = self.backgroundRingView.alpha = 1.0f; } - (void)fadeOutEffects { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 if(self.defaultStyle != SVProgressHUDStyleCustom) { // Remove blur effect self.hudView.effect = nil; } #endif // Remove background color self.hudView.backgroundColor = [UIColor clearColor]; // Fade out views self.backgroundView.alpha = 0.0f; self.imageView.alpha = 0.0f; self.statusLabel.alpha = 0.0f; self.indefiniteAnimatedView.alpha = 0.0f; self.ringView.alpha = self.backgroundRingView.alpha = 0.0f; } #if TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 - (UINotificationFeedbackGenerator *)hapticGenerator { // Only return if haptics are enabled if(!self.hapticsEnabled) { return nil; } if(!_hapticGenerator) { _hapticGenerator = [[UINotificationFeedbackGenerator alloc] init]; } return _hapticGenerator; } #endif #pragma mark - UIAppearance Setters - (void)setDefaultStyle:(SVProgressHUDStyle)style { if (!_isInitializing) _defaultStyle = style; } - (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType { if (!_isInitializing) _defaultMaskType = maskType; } - (void)setDefaultAnimationType:(SVProgressHUDAnimationType)animationType { if (!_isInitializing) _defaultAnimationType = animationType; } - (void)setContainerView:(UIView *)containerView { if (!_isInitializing) _containerView = containerView; } - (void)setMinimumSize:(CGSize)minimumSize { if (!_isInitializing) _minimumSize = minimumSize; } - (void)setRingThickness:(CGFloat)ringThickness { if (!_isInitializing) _ringThickness = ringThickness; } - (void)setRingRadius:(CGFloat)ringRadius { if (!_isInitializing) _ringRadius = ringRadius; } - (void)setRingNoTextRadius:(CGFloat)ringNoTextRadius { if (!_isInitializing) _ringNoTextRadius = ringNoTextRadius; } - (void)setCornerRadius:(CGFloat)cornerRadius { if (!_isInitializing) _cornerRadius = cornerRadius; } - (void)setFont:(UIFont*)font { if (!_isInitializing) _font = font; } - (void)setForegroundColor:(UIColor*)color { if (!_isInitializing) _foregroundColor = color; } - (void)setBackgroundColor:(UIColor*)color { if (!_isInitializing) _backgroundColor = color; } - (void)setBackgroundLayerColor:(UIColor*)color { if (!_isInitializing) _backgroundLayerColor = color; } - (void)setInfoImage:(UIImage*)image { if (!_isInitializing) _infoImage = image; } - (void)setSuccessImage:(UIImage*)image { if (!_isInitializing) _successImage = image; } - (void)setErrorImage:(UIImage*)image { if (!_isInitializing) _errorImage = image; } - (void)setViewForExtension:(UIView*)view { if (!_isInitializing) _viewForExtension = view; } - (void)setOffsetFromCenter:(UIOffset)offset { if (!_isInitializing) _offsetFromCenter = offset; } - (void)setMinimumDismissTimeInterval:(NSTimeInterval)minimumDismissTimeInterval { if (!_isInitializing) _minimumDismissTimeInterval = minimumDismissTimeInterval; } - (void)setFadeInAnimationDuration:(NSTimeInterval)duration { if (!_isInitializing) _fadeInAnimationDuration = duration; } - (void)setFadeOutAnimationDuration:(NSTimeInterval)duration { if (!_isInitializing) _fadeOutAnimationDuration = duration; } - (void)setMaxSupportedWindowLevel:(UIWindowLevel)maxSupportedWindowLevel { if (!_isInitializing) _maxSupportedWindowLevel = maxSupportedWindowLevel; } @end ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVRadialGradientLayer.h ================================================ // // SVRadialGradientLayer.h // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2014-2017 Tobias Tiemerding. All rights reserved. // #import @interface SVRadialGradientLayer : CALayer @property (nonatomic) CGPoint gradientCenter; @end ================================================ FILE: Example/Pods/SVProgressHUD/SVProgressHUD/SVRadialGradientLayer.m ================================================ // // SVRadialGradientLayer.m // SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD // // Copyright (c) 2014-2017 Tobias Tiemerding. All rights reserved. // #import "SVRadialGradientLayer.h" @implementation SVRadialGradientLayer - (void)drawInContext:(CGContextRef)context { size_t locationsCount = 2; CGFloat locations[2] = {0.0f, 1.0f}; CGFloat colors[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.75f}; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, locationsCount); CGColorSpaceRelease(colorSpace); float radius = MIN(self.bounds.size.width , self.bounds.size.height); CGContextDrawRadialGradient (context, gradient, self.gradientCenter, 0, self.gradientCenter, radius, kCGGradientDrawsAfterEndLocation); CGGradientRelease(gradient); } @end ================================================ FILE: Example/Pods/Target Support Files/HUPhotoBrowser/HUPhotoBrowser-dummy.m ================================================ #import @interface PodsDummy_HUPhotoBrowser : NSObject @end @implementation PodsDummy_HUPhotoBrowser @end ================================================ FILE: Example/Pods/Target Support Files/HUPhotoBrowser/HUPhotoBrowser-prefix.pch ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif ================================================ FILE: Example/Pods/Target Support Files/HUPhotoBrowser/HUPhotoBrowser.xcconfig ================================================ CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/HUPhotoBrowser GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/SVProgressHUD" OTHER_LDFLAGS = -framework "AssetsLibrary" -framework "Photos" -framework "UIKit" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES ================================================ FILE: Example/Pods/Target Support Files/HUPhotoPicker/HUPhotoPicker-dummy.m ================================================ #import @interface PodsDummy_HUPhotoPicker : NSObject @end @implementation PodsDummy_HUPhotoPicker @end ================================================ FILE: Example/Pods/Target Support Files/HUPhotoPicker/HUPhotoPicker-prefix.pch ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif ================================================ FILE: Example/Pods/Target Support Files/HUPhotoPicker/HUPhotoPicker.xcconfig ================================================ CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/HUPhotoPicker GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/HUPhotoPicker" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_LDFLAGS = -framework "Photos" -framework "UIKit" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/HUPhotoPicker PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES ================================================ FILE: Example/Pods/Target Support Files/HUPhotoPicker/ResourceBundle-HUPhotoPicker-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleIdentifier ${PRODUCT_BUNDLE_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0.3 CFBundleSignature ???? CFBundleVersion 1 NSPrincipalClass ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-acknowledgements.markdown ================================================ # Acknowledgements This application makes use of the following third party libraries: ## HUPhotoBrowser The MIT License (MIT) Copyright (c) 2016 Jewelz Hu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## HUPhotoPicker MIT License Copyright (c) 2017 Jewelz Hu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## SDWebImage Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ## SVProgressHUD Copyright (c) 2011-2017 Sam Vermette, Tobias Tiemerding and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. A different license may apply to other resources included in this package, including Freepik Icons. Please consult their respective headers for the terms of their individual licenses. Generated by CocoaPods - https://cocoapods.org ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-acknowledgements.plist ================================================ PreferenceSpecifiers FooterText This application makes use of the following third party libraries: Title Acknowledgements Type PSGroupSpecifier FooterText The MIT License (MIT) Copyright (c) 2016 Jewelz Hu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License MIT Title HUPhotoBrowser Type PSGroupSpecifier FooterText MIT License Copyright (c) 2017 Jewelz Hu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License MIT Title HUPhotoPicker Type PSGroupSpecifier FooterText Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License MIT Title SDWebImage Type PSGroupSpecifier FooterText Copyright (c) 2011-2017 Sam Vermette, Tobias Tiemerding and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. A different license may apply to other resources included in this package, including Freepik Icons. Please consult their respective headers for the terms of their individual licenses. License MIT Title SVProgressHUD Type PSGroupSpecifier FooterText Generated by CocoaPods - https://cocoapods.org Title Type PSGroupSpecifier StringsTable Acknowledgements Title Acknowledgements ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-dummy.m ================================================ #import @interface PodsDummy_Pods_HUPhotoBrowser_Demo : NSObject @end @implementation PodsDummy_Pods_HUPhotoBrowser_Demo @end ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-frameworks.sh ================================================ #!/bin/sh set -e echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" # This protects against multiple targets copying the same framework dependency at the same time. The solution # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") install_framework() { if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then local source="${BUILT_PRODUCTS_DIR}/$1" elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" elif [ -r "$1" ]; then local source="$1" fi local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" if [ -L "${source}" ]; then echo "Symlinked..." source="$(readlink "${source}")" fi # Use filter instead of exclude so missing patterns don't throw errors. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" local basename basename="$(basename -s .framework "$1")" binary="${destination}/${basename}.framework/${basename}" if ! [ -r "$binary" ]; then binary="${destination}/${basename}" fi # Strip invalid architectures so "fat" simulator / device frameworks work on device if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then strip_invalid_archs "$binary" fi # Resign the code if required by the build settings to avoid unstable apps code_sign_if_enabled "${destination}/$(basename "$1")" # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then local swift_runtime_libs swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) for lib in $swift_runtime_libs; do echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" code_sign_if_enabled "${destination}/${lib}" done fi } # Copies the dSYM of a vendored framework install_dsym() { local source="$1" if [ -r "$source" ]; then echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" fi } # Signs a framework with the provided identity code_sign_if_enabled() { if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then # Use the current code_sign_identitiy echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then code_sign_cmd="$code_sign_cmd &" fi echo "$code_sign_cmd" eval "$code_sign_cmd" fi } # Strip invalid architectures strip_invalid_archs() { binary="$1" # Get architectures for current file archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" stripped="" for arch in $archs; do if ! [[ "${ARCHS}" == *"$arch"* ]]; then # Strip non-valid architectures in-place lipo -remove "$arch" -output "$binary" "$binary" || exit 1 stripped="$stripped $arch" fi done if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi } if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then wait fi ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo-resources.sh ================================================ #!/bin/sh set -e mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt > "$RESOURCES_TO_COPY" XCASSET_FILES=() # This protects against multiple targets copying the same framework dependency at the same time. The solution # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") case "${TARGETED_DEVICE_FAMILY}" in 1,2) TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" ;; 1) TARGET_DEVICE_ARGS="--target-device iphone" ;; 2) TARGET_DEVICE_ARGS="--target-device ipad" ;; 3) TARGET_DEVICE_ARGS="--target-device tv" ;; 4) TARGET_DEVICE_ARGS="--target-device watch" ;; *) TARGET_DEVICE_ARGS="--target-device mac" ;; esac install_resource() { if [[ "$1" = /* ]] ; then RESOURCE_PATH="$1" else RESOURCE_PATH="${PODS_ROOT}/$1" fi if [[ ! -e "$RESOURCE_PATH" ]] ; then cat << EOM error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. EOM exit 1 fi case $RESOURCE_PATH in *.storyboard) 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}" || true 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} ;; *.xib) 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}" || true 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} ;; *.framework) echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" ;; *.xcdatamodel) echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" ;; *.xcdatamodeld) echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" ;; *.xcmappingmodel) echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" ;; *.xcassets) ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") ;; *) echo "$RESOURCE_PATH" || true echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" ;; esac } if [[ "$CONFIGURATION" == "Debug" ]]; then install_resource "$PODS_CONFIGURATION_BUILD_DIR/HUPhotoPicker/HUPhotoPicker.bundle" install_resource "${PODS_ROOT}/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_resource "$PODS_CONFIGURATION_BUILD_DIR/HUPhotoPicker/HUPhotoPicker.bundle" install_resource "${PODS_ROOT}/SVProgressHUD/SVProgressHUD/SVProgressHUD.bundle" fi mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" fi rm -f "$RESOURCES_TO_COPY" if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] then # Find all other xcassets (this unfortunately includes those of path pods and other targets). OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) while read line; do if [[ $line != "${PODS_ROOT}*" ]]; then XCASSET_FILES+=("$line") fi done <<<"$OTHER_XCASSETS" 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}" fi ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo.debug.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/HUPhotoBrowser" "$PODS_CONFIGURATION_BUILD_DIR/HUPhotoPicker" "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage" "$PODS_CONFIGURATION_BUILD_DIR/SVProgressHUD" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoPicker" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_LDFLAGS = $(inherited) -ObjC -l"HUPhotoBrowser" -l"HUPhotoPicker" -l"SDWebImage" -l"SVProgressHUD" -framework "AssetsLibrary" -framework "ImageIO" -framework "Photos" -framework "QuartzCore" -framework "UIKit" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser Demo/Pods-HUPhotoBrowser Demo.release.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/HUPhotoBrowser" "$PODS_CONFIGURATION_BUILD_DIR/HUPhotoPicker" "$PODS_CONFIGURATION_BUILD_DIR/SDWebImage" "$PODS_CONFIGURATION_BUILD_DIR/SVProgressHUD" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoPicker" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_LDFLAGS = $(inherited) -ObjC -l"HUPhotoBrowser" -l"HUPhotoPicker" -l"SDWebImage" -l"SVProgressHUD" -framework "AssetsLibrary" -framework "ImageIO" -framework "Photos" -framework "QuartzCore" -framework "UIKit" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests-acknowledgements.markdown ================================================ # Acknowledgements This application makes use of the following third party libraries: Generated by CocoaPods - https://cocoapods.org ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests-acknowledgements.plist ================================================ PreferenceSpecifiers FooterText This application makes use of the following third party libraries: Title Acknowledgements Type PSGroupSpecifier FooterText Generated by CocoaPods - https://cocoapods.org Title Type PSGroupSpecifier StringsTable Acknowledgements Title Acknowledgements ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests-dummy.m ================================================ #import @interface PodsDummy_Pods_HUPhotoBrowser_DemoTests : NSObject @end @implementation PodsDummy_Pods_HUPhotoBrowser_DemoTests @end ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests-frameworks.sh ================================================ #!/bin/sh set -e echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" # This protects against multiple targets copying the same framework dependency at the same time. The solution # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") install_framework() { if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then local source="${BUILT_PRODUCTS_DIR}/$1" elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" elif [ -r "$1" ]; then local source="$1" fi local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" if [ -L "${source}" ]; then echo "Symlinked..." source="$(readlink "${source}")" fi # Use filter instead of exclude so missing patterns don't throw errors. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" local basename basename="$(basename -s .framework "$1")" binary="${destination}/${basename}.framework/${basename}" if ! [ -r "$binary" ]; then binary="${destination}/${basename}" fi # Strip invalid architectures so "fat" simulator / device frameworks work on device if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then strip_invalid_archs "$binary" fi # Resign the code if required by the build settings to avoid unstable apps code_sign_if_enabled "${destination}/$(basename "$1")" # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then local swift_runtime_libs swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) for lib in $swift_runtime_libs; do echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" code_sign_if_enabled "${destination}/${lib}" done fi } # Copies the dSYM of a vendored framework install_dsym() { local source="$1" if [ -r "$source" ]; then echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" fi } # Signs a framework with the provided identity code_sign_if_enabled() { if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then # Use the current code_sign_identitiy echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then code_sign_cmd="$code_sign_cmd &" fi echo "$code_sign_cmd" eval "$code_sign_cmd" fi } # Strip invalid architectures strip_invalid_archs() { binary="$1" # Get architectures for current file archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" stripped="" for arch in $archs; do if ! [[ "${ARCHS}" == *"$arch"* ]]; then # Strip non-valid architectures in-place lipo -remove "$arch" -output "$binary" "$binary" || exit 1 stripped="$stripped $arch" fi done if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi } if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then wait fi ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests-resources.sh ================================================ #!/bin/sh set -e mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt > "$RESOURCES_TO_COPY" XCASSET_FILES=() # This protects against multiple targets copying the same framework dependency at the same time. The solution # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") case "${TARGETED_DEVICE_FAMILY}" in 1,2) TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" ;; 1) TARGET_DEVICE_ARGS="--target-device iphone" ;; 2) TARGET_DEVICE_ARGS="--target-device ipad" ;; 3) TARGET_DEVICE_ARGS="--target-device tv" ;; 4) TARGET_DEVICE_ARGS="--target-device watch" ;; *) TARGET_DEVICE_ARGS="--target-device mac" ;; esac install_resource() { if [[ "$1" = /* ]] ; then RESOURCE_PATH="$1" else RESOURCE_PATH="${PODS_ROOT}/$1" fi if [[ ! -e "$RESOURCE_PATH" ]] ; then cat << EOM error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. EOM exit 1 fi case $RESOURCE_PATH in *.storyboard) 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}" || true 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} ;; *.xib) 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}" || true 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} ;; *.framework) echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" ;; *.xcdatamodel) echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" ;; *.xcdatamodeld) echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" ;; *.xcmappingmodel) echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" ;; *.xcassets) ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") ;; *) echo "$RESOURCE_PATH" || true echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" ;; esac } mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" fi rm -f "$RESOURCES_TO_COPY" if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] then # Find all other xcassets (this unfortunately includes those of path pods and other targets). OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) while read line; do if [[ $line != "${PODS_ROOT}*" ]]; then XCASSET_FILES+=("$line") fi done <<<"$OTHER_XCASSETS" 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}" fi ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests.debug.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoPicker" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_LDFLAGS = $(inherited) -ObjC PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Example/Pods/Target Support Files/Pods-HUPhotoBrowser DemoTests/Pods-HUPhotoBrowser DemoTests.release.xcconfig ================================================ GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" -isystem "${PODS_ROOT}/Headers/Public/HUPhotoPicker" -isystem "${PODS_ROOT}/Headers/Public/SDWebImage" -isystem "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_LDFLAGS = $(inherited) -ObjC PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods ================================================ FILE: Example/Pods/Target Support Files/SDWebImage/SDWebImage-dummy.m ================================================ #import @interface PodsDummy_SDWebImage : NSObject @end @implementation PodsDummy_SDWebImage @end ================================================ FILE: Example/Pods/Target Support Files/SDWebImage/SDWebImage-prefix.pch ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif ================================================ FILE: Example/Pods/Target Support Files/SDWebImage/SDWebImage.xcconfig ================================================ CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/SDWebImage GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SDWebImage" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_LDFLAGS = -framework "ImageIO" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/SDWebImage PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES ================================================ FILE: Example/Pods/Target Support Files/SVProgressHUD/SVProgressHUD-dummy.m ================================================ #import @interface PodsDummy_SVProgressHUD : NSObject @end @implementation PodsDummy_SVProgressHUD @end ================================================ FILE: Example/Pods/Target Support Files/SVProgressHUD/SVProgressHUD-prefix.pch ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif ================================================ FILE: Example/Pods/Target Support Files/SVProgressHUD/SVProgressHUD.xcconfig ================================================ CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/SVProgressHUD GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SVProgressHUD" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/HUPhotoBrowser" "${PODS_ROOT}/Headers/Public/HUPhotoPicker" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SVProgressHUD" OTHER_LDFLAGS = -framework "QuartzCore" PODS_BUILD_DIR = $BUILD_DIR PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/SVProgressHUD PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES ================================================ FILE: HUPhotoBrowser/HUPhotoBrowser.h ================================================ // // HUPhotoBrowser.h // HUPhotoBrowser // // Created by mac on 16/2/24. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import typedef void(^ __nullable DismissBlock)(UIImage * __nullable image, NSInteger index); @interface HUPhotoBrowser : UIView @property (nonatomic, strong, readonly) UIButton *saveButton; /* * 是否隐藏工具栏,默认不隐藏 */ @property (nonatomic) BOOL didHideToolBar; /* * @param imageView 点击的imageView * @param URLStrings 加载的网络图片的urlString * @param index 点击的图片在所有要展示图片中的位置 */ + (nonnull instancetype)showFromImageView:(nullable UIImageView *)imageView withURLStrings:(nullable NSArray *)URLStrings atIndex:(NSInteger)index; /* * @param imageView 点击的imageView * @param withImages 加载的本地图片 * @param index 点击的图片在所有要展示图片中的位置 */ + (nonnull instancetype)showFromImageView:(nullable UIImageView *)imageView withImages:(nullable NSArray *)images atIndex:(NSInteger)index; /* * @param imageView 点击的imageView * @param URLStrings 加载的网络图片的urlString * @param image 占位图片 * @param index 点击的图片在所有要展示图片中的位置 * @param dismiss photoBrowser消失的回调 */ + (nonnull instancetype)showFromImageView:(nullable UIImageView *)imageView withURLStrings:(nullable NSArray *)URLStrings placeholderImage:(nullable UIImage *)image atIndex:(NSInteger)index dismiss:(DismissBlock)block; /* * @param imageView 点击的imageView * @param withImages 加载的本地图片 * @param image 占位图片 * @param index 点击的图片在所有要展示图片中的位置 * @param dismiss photoBrowser消失的回调 */ + (nonnull instancetype)showFromImageView:(nullable UIImageView *)imageView withImages:(nullable NSArray *)images atIndex:(NSInteger)index dismiss:(DismissBlock)block; @property (nonatomic, strong, nullable) UIImage *placeholderImage; @end ================================================ FILE: HUPhotoBrowser/HUPhotoBrowser.m ================================================ // // HUPhotoBrowser.m // HUPhotoBrowser // // Created by mac on 16/2/24. // Copyright (c) 2016年 jinhuadiqigan. All rights reserved. // #import "HUPhotoBrowser.h" #import "HUPhotoBrowserCell.h" #import "hu_const.h" #import "HUWebImage.h" #import @interface HUPhotoBrowser () { CGRect _endTempFrame; NSInteger _currentPage; NSIndexPath *_zoomingIndexPath; BOOL _imageDidLoaded; BOOL _animationCompleted; } @property (nonatomic, strong) UIImageView *imageView; @property (nonatomic, strong) UIImageView *tmpImageView; @property (nonatomic, strong) UICollectionView *collectionView; @property (nonatomic, strong) UIView *toolBar; @property (nonatomic, weak) UILabel *countLab; @property (nonatomic, strong) NSArray *URLStrings; @property (nonatomic) NSInteger index; @property (nonatomic) NSInteger imagesCount; @property (nonatomic, copy) DismissBlock dismissDlock; @property (nonatomic, strong) NSArray *images; @end @implementation HUPhotoBrowser - (void)dealloc { self.collectionView.delegate = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; } + (instancetype)showFromImageView:(UIImageView *)imageView withURLStrings:(NSArray *)URLStrings placeholderImage:(UIImage *)image atIndex:(NSInteger)index dismiss:(DismissBlock)block { HUPhotoBrowser *browser = [[HUPhotoBrowser alloc] initWithFrame:kScreenRect]; browser.imageView = imageView; browser.URLStrings = URLStrings; browser.imagesCount = URLStrings.count; [browser resetCountLabWithIndex:index+1]; [browser configureBrowser]; [browser animateImageViewAtIndex:index]; browser.placeholderImage = image; browser.dismissDlock = block; return browser; } + (instancetype)showFromImageView:(UIImageView *)imageView withImages:(NSArray *)images atIndex:(NSInteger)index dismiss:(DismissBlock)block { HUPhotoBrowser *browser = [[HUPhotoBrowser alloc] initWithFrame:kScreenRect]; browser.imageView = imageView; browser.images = images; browser.imagesCount = images.count; [browser resetCountLabWithIndex:index+1]; [browser configureBrowser]; [browser animateImageViewAtIndex:index]; browser.dismissDlock = block; return browser; } + (instancetype)showFromImageView:(UIImageView *)imageView withURLStrings:(NSArray *)URLStrings atIndex:(NSInteger)index { return [self showFromImageView:imageView withURLStrings:URLStrings placeholderImage:nil atIndex:index dismiss:nil]; } + (instancetype)showFromImageView:(UIImageView *)imageView withImages:(NSArray *)images atIndex:(NSInteger)index { return [self showFromImageView:imageView withImages:images atIndex:index dismiss:nil]; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor blackColor]; [self addSubview:self.collectionView]; [self setupToolBar]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadForScreenRotate) name:UIDeviceOrientationDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(photoCellDidZooming:) name:kPhotoCellDidZommingNotification object:nil]; } return self; } #pragma mark - UICollectionViewDataSource - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { NSInteger count = 0; if (self.URLStrings) { count = _URLStrings.count; }else if (self.images) { count = _images.count; } return count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { HUPhotoBrowserCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kPhotoBrowserCellID forIndexPath:indexPath]; cell.indexPath = indexPath; [cell resetZoomingScale]; __weak __typeof(self) wself = self; cell.tapActionBlock = ^(UITapGestureRecognizer *sender) { [wself dismiss]; }; if (self.URLStrings) { [cell startAnimating]; __weak __typeof(cell) weakCell = cell; NSURL *url = [NSURL URLWithString:self.URLStrings[indexPath.row]]; if (indexPath.row != _index) { if (_placeholderImage) { [cell stopAnimating]; [cell.imageView hu_setImageWithURL:url placeholderImage:_placeholderImage completed:^(UIImage * _Nullable image, NSError * _Nullable error, NSURL * _Nullable imageUrl) { __strong __typeof(weakCell) strongCell = weakCell; [strongCell resizeImageView]; }]; } else { [cell.imageView hu_setImageWithURL:url placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, NSURL * _Nullable imageUrl) { if (image) { __strong __typeof(weakCell) strongCell = weakCell; [strongCell resizeImageView]; [strongCell stopAnimating]; } }]; } } else { UIImage *placeHolder = _tmpImageView.image; [cell.imageView hu_setImageWithURL:url placeholderImage:placeHolder completed:^(UIImage *image, NSError *error, NSURL *imageUrl) { __strong __typeof(wself) strongSelf = wself; __strong __typeof(weakCell) strongCell = weakCell; [strongCell stopAnimating]; [strongCell resizeImageView]; if (!strongSelf->_imageDidLoaded) { strongSelf->_imageDidLoaded = YES; if (strongSelf->_animationCompleted) { strongSelf.collectionView.hidden = NO; [strongSelf->_tmpImageView removeFromSuperview]; strongSelf->_animationCompleted = NO; } } }]; } } else if (self.images) { [cell stopAnimating]; cell.imageView.image = self.images[indexPath.row]; [cell resizeImageView]; } return cell; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return kScreenRect.size; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { _currentPage = scrollView.contentOffset.x/kScreenWidth + 0.5; _countLab.text = [NSString stringWithFormat:@"%zd/%zd",_currentPage+1,_imagesCount]; if (_zoomingIndexPath) { [self.collectionView reloadItemsAtIndexPaths:@[_zoomingIndexPath]]; _zoomingIndexPath = nil; } } #pragma mark - notification handler - (void)reloadForScreenRotate { _collectionView.frame = kScreenRect; [self.collectionView reloadData]; self.collectionView.contentOffset = CGPointMake(kScreenWidth * _currentPage,0); } - (void)photoCellDidZooming:(NSNotification *)nofit { NSIndexPath *indexPath = nofit.object; _zoomingIndexPath = indexPath; } #pragma mark - getter & setter - (void)setDidHideToolBar:(BOOL)didHideToolBar { _didHideToolBar = didHideToolBar; _toolBar.hidden = didHideToolBar; } - (UICollectionView *)collectionView { if (!_collectionView) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; layout.minimumInteritemSpacing = 0; layout.minimumLineSpacing = 0; _collectionView = [[UICollectionView alloc]initWithFrame:self.bounds collectionViewLayout:layout]; _collectionView.hidden = YES; _collectionView.pagingEnabled = YES; _collectionView.showsHorizontalScrollIndicator = NO; } return _collectionView; } #pragma mark - private - (void)configureBrowser { self.collectionView.delegate = self; self.collectionView.dataSource = self; [self.collectionView registerClass:[HUPhotoBrowserCell class] forCellWithReuseIdentifier:kPhotoBrowserCellID]; [[UIApplication sharedApplication].keyWindow addSubview:self]; } - (void)setupToolBar { _toolBar = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height-38, self.frame.size.width, 30)]; _toolBar.backgroundColor = [UIColor clearColor]; [self addSubview:_toolBar]; UILabel *countLab = [[UILabel alloc] init]; countLab.textColor = [UIColor whiteColor]; countLab.layer.cornerRadius = 2; countLab.layer.masksToBounds = YES; countLab.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.4]; countLab.font = [UIFont systemFontOfSize:13]; countLab.textAlignment = NSTextAlignmentCenter; [_toolBar addSubview:countLab]; _countLab = countLab; UIButton *saveBtn = [UIButton buttonWithType:UIButtonTypeCustom]; saveBtn.frame = CGRectMake(_toolBar.frame.size.width-58, 1, 50, 28); saveBtn.layer.cornerRadius = 2; [saveBtn setBackgroundColor:[[UIColor blackColor]colorWithAlphaComponent:0.4]]; [saveBtn setTitle:@"保存" forState:UIControlStateNormal]; [saveBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; saveBtn.titleLabel.font = [UIFont systemFontOfSize:13]; [saveBtn addTarget:self action:@selector(saveImae) forControlEvents:UIControlEventTouchUpInside]; [_toolBar addSubview:saveBtn]; _saveButton = saveBtn; } - (void)animateImageViewAtIndex:(NSInteger)index { _index = index; CGRect startFrame = [self.imageView.superview convertRect:self.imageView.frame toView:[UIApplication sharedApplication].keyWindow]; CGRect endFrame = kScreenRect; if (self.imageView.image) { UIImage *image = self.imageView.image; CGFloat ratio = image.size.width / image.size.height; if (ratio > kScreenRatio) { endFrame.size.width = kScreenWidth; endFrame.size.height = kScreenWidth / ratio; } else { endFrame.size.height = kScreenHeight; endFrame.size.width = kScreenHeight * ratio; } endFrame.origin.x = (kScreenWidth - endFrame.size.width) / 2; endFrame.origin.y = (kScreenHeight - endFrame.size.height) / 2; } _endTempFrame = endFrame; #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0 [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade]; #endif UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:startFrame]; tempImageView.image = self.imageView.image; tempImageView.contentMode = UIViewContentModeScaleAspectFit; [[UIApplication sharedApplication].keyWindow addSubview:tempImageView]; _tmpImageView = tempImageView; if (self.URLStrings && !self.images) { NSString *key = [HUWebImageDownloader cacheKeyForURL:[NSURL URLWithString:self.URLStrings[_index]]]; UIImage *image = [HUWebImageDownloader imageFromDiskCacheForKey:key]; _imageDidLoaded = image != nil; } [self.collectionView setContentOffset:CGPointMake(kScreenWidth * index,0) animated:NO]; [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ tempImageView.frame = endFrame; } completion:^(BOOL finished) { _currentPage = index; _animationCompleted = YES; if (self.images || _imageDidLoaded || (self.URLStrings && !_imageDidLoaded)) { self.collectionView.hidden = NO; [tempImageView removeFromSuperview]; _animationCompleted = NO; } }]; } - (void)dismiss { #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0 [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade]; #endif if (self.dismissDlock) { HUPhotoBrowserCell *cell = (HUPhotoBrowserCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:_currentPage inSection:0]]; self.dismissDlock(cell.imageView.image, _currentPage); } if (_currentPage != _index) { [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ self.alpha = 0; } completion:^(BOOL finished) { [self removeFromSuperview]; }]; return; } CGRect endFrame = [self.imageView.superview convertRect:self.imageView.frame toView:[UIApplication sharedApplication].keyWindow]; UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:_endTempFrame]; tempImageView.image = self.imageView.image; tempImageView.contentMode = UIViewContentModeScaleAspectFit; self.collectionView.hidden = YES; [[UIApplication sharedApplication].keyWindow addSubview:tempImageView]; [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ tempImageView.frame = endFrame; self.alpha = 0; } completion:^(BOOL finished) { [self removeFromSuperview]; [tempImageView removeFromSuperview]; }]; } - (void)resetCountLabWithIndex:(NSInteger)index { NSString *text = [NSString stringWithFormat:@"%zd%zd",_imagesCount,_imagesCount]; CGFloat width = [text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]}].width+8; _countLab.frame = CGRectMake(8, 1, MAX(50, width), 28); _countLab.text = [NSString stringWithFormat:@"%zd/%zd",index,_imagesCount]; } - (void)saveImae { HUPhotoBrowserCell *cell = (HUPhotoBrowserCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:_currentPage inSection:0]]; UIImage *seavedImage = cell.imageView.image; if (seavedImage) { UIImageWriteToSavedPhotosAlbum(seavedImage, self, @selector(imageSavedToPhotosAlbum:didFinishSavingWithError:contextInfo:), nil); } } - (void)imageSavedToPhotosAlbum:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { NSString *msg = nil ; if(error != nil){ msg = @"保存图片失败"; [SVProgressHUD showInfoWithStatus:msg]; } else{ msg = @"保存图片成功"; [SVProgressHUD showSuccessWithStatus:msg]; } } @end ================================================ FILE: HUPhotoBrowser/HUPhotoBrowserCell.h ================================================ // // HUPhotoBrowserCell.h // HUPhotoBrowser // // Created by mac on 16/2/24. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import #define kPhotoBrowserCellID @"HUPhotoBrowserCell" static NSString * const kPhotoCellDidZommingNotification = @"kPhotoCellDidZommingNotification"; static NSString * const kPhotoCellDidImageLoadedNotification = @"kPhotoCellDidImageLoadedNotification"; @interface HUPhotoBrowserCell : UICollectionViewCell @property (nonatomic, strong, readonly) UIActivityIndicatorView *indicatorView; @property (nonatomic, strong, readonly) UIImageView *imageView; @property (nonatomic, strong) NSIndexPath *indexPath; - (void)resetZoomingScale; - (void)resizeImageView; - (void)startAnimating; - (void)stopAnimating; @property (nonatomic, copy) void(^tapActionBlock)(UITapGestureRecognizer *tapGesture); @end ================================================ FILE: HUPhotoBrowser/HUPhotoBrowserCell.m ================================================ // // HUPhotoBrowserCell.m // HUPhotoBrowser // // Created by mac on 16/2/24. // Copyright (c) 2016年 jinhuadiqigan. All rights reserved. // #import "HUPhotoBrowserCell.h" #import "hu_const.h" #import "UIImageView+HUWebImage.h" @interface HUPhotoBrowserCell () @property (nonatomic, strong, readwrite) UIActivityIndicatorView *indicatorView; @property (nonatomic, strong, readwrite) UIImageView *imageView; @property (nonatomic, strong) UIScrollView *scrollView; @property (nonatomic,strong) UITapGestureRecognizer *doubleTap; @property (nonatomic,strong) UITapGestureRecognizer *singleTap; @end @implementation HUPhotoBrowserCell - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor blackColor]; [self setupView]; [self addGestureRecognizer:self.singleTap]; [self addGestureRecognizer:self.doubleTap]; } return self; } - (void)setupView { [self.scrollView addSubview:self.imageView]; [self addSubview:self.scrollView]; [self addSubview:self.indicatorView]; } - (void)resetZoomingScale { if (self.scrollView.zoomScale !=1) { self.scrollView.zoomScale = 1; } } - (void)resizeImageView { CGSize size = self.imageView.image.size; CGFloat scale = size.height / size.width; BOOL flag = scale > kScreenHeight / kScreenWidth; if (size.height > kScreenHeight * 2 && flag) { CGFloat height = kScreenWidth * size.height / size.width; self.imageView.frame = CGRectMake(0, 0, kScreenWidth, height); } else { self.imageView.frame = self.scrollView.bounds; } } - (void)startAnimating { [self.indicatorView startAnimating]; } - (void)stopAnimating { [self.indicatorView stopAnimating]; } - (void)layoutSubviews { [super layoutSubviews]; self.scrollView.frame = self.bounds; self.imageView.frame = self.scrollView.bounds; self.indicatorView.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); } - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.imageView; } #pragma mark UIScrollViewDelegate - (void)scrollViewDidZoom:(UIScrollView *)scrollView { self.imageView.center = [self centerOfScrollViewContent:scrollView]; } - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { [[NSNotificationCenter defaultCenter] postNotificationName:kPhotoCellDidZommingNotification object:_indexPath]; } #pragma mark - gesture handler - (void)doubleTapGestrueHandle:(UITapGestureRecognizer *)sender { CGPoint p = [sender locationInView:self]; if (self.scrollView.zoomScale <=1.0) { //CGFloat scaleX = p.x + self.scrollView.contentOffset.x; //CGFloat scaley = p.y + self.scrollView.contentOffset.y; CGRect rect = [self zoomRectForScale:self.scrollView.zoomScale*3 withCenter:p]; [self.scrollView zoomToRect:rect animated:YES]; } else { [self.scrollView setZoomScale:1.0 animated:YES]; } } - (void)singleTapGestrueHandle:(UITapGestureRecognizer *)sender { if (self.tapActionBlock) { self.tapActionBlock(sender); } } #pragma mark - private - (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center { CGRect zoomRect; zoomRect.size.height = self.scrollView.frame.size.height/scale; zoomRect.size.width = self.scrollView.frame.size.width/scale; zoomRect.origin.x = center.x - (zoomRect.size.width/2.0); zoomRect.origin.y = center.y - (zoomRect.size.height/2.0); return zoomRect; } - (CGPoint)centerOfScrollViewContent:(UIScrollView *)scrollView { CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)? (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0.0; CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)? (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0.0; CGPoint actualCenter = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY); return actualCenter; } #pragma mark - getter - (UIScrollView *)scrollView { if (_scrollView == nil) { _scrollView = [[UIScrollView alloc] init]; _scrollView.backgroundColor = [UIColor blackColor]; _scrollView.showsHorizontalScrollIndicator = NO; _scrollView.showsVerticalScrollIndicator = NO; _scrollView.maximumZoomScale = 4; _scrollView.minimumZoomScale = 0.5; _scrollView.delegate = self; } return _scrollView; } - (UIImageView *)imageView { if (_imageView == nil) { _imageView = [[UIImageView alloc] init]; _imageView.contentMode = UIViewContentModeScaleAspectFit; } return _imageView; } - (UIActivityIndicatorView *)indicatorView { if (_indicatorView == nil) { _indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; _indicatorView.hidesWhenStopped = YES; } return _indicatorView; } - (UITapGestureRecognizer *)doubleTap { if (!_doubleTap) { _doubleTap =[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapGestrueHandle:)]; _doubleTap.numberOfTapsRequired = 2; _doubleTap.numberOfTouchesRequired = 1; } return _doubleTap; } - (UITapGestureRecognizer *)singleTap { if (!_singleTap) { _singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapGestrueHandle:)]; _singleTap.numberOfTapsRequired = 1; _singleTap.numberOfTouchesRequired = 1; [_singleTap requireGestureRecognizerToFail:self.doubleTap]; } return _singleTap; } @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/HUWebImage.h ================================================ // // HUWebImage.h // HUPhotoBrowser // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #ifndef HUPhotoBrowser_HUWebImage_h #define HUPhotoBrowser_HUWebImage_h #import "UIImageView+HUWebImage.h" #import "HUWebImageDownloader.h" #endif ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/HUWebImageDownloadOperation.h ================================================ // // HUWebImageDownloadOperation.h // Pods // // Created by mac on 16/4/19. // // #import typedef void (^HUWebImageDownloadCompltedBlock) (UIImage * __nullable image, NSData * __nullable data, NSError * __nullable error); @interface HUWebImageDownloadOperation : NSOperation - (nonnull instancetype)initWithURL:(nonnull NSURL *)url completed:(nullable HUWebImageDownloadCompltedBlock)completedBlock; - (void)resume; @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/HUWebImageDownloadOperation.m ================================================ // // HUWebImageDownloadOperation.m // Pods // // Created by mac on 16/4/19. // // #import "HUWebImageDownloadOperation.h" #import "UIImage+HUExtension.h" @interface HUWebImageDownloadOperation () { NSLock *_lock; } @property (nonatomic, copy) HUWebImageDownloadCompltedBlock completedBlock; @property (nonatomic, strong) NSURL *url; @property (nonatomic, strong) NSURLSession *session; @property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask; @property (nonatomic, assign) BOOL myFinished; @property (nonatomic, assign) BOOL myExecuting; @end @implementation HUWebImageDownloadOperation - (instancetype)initWithURL:(NSURL *)url completed:(HUWebImageDownloadCompltedBlock)completedBlock { if (self = [super init]) { _url = url; _completedBlock = completedBlock; _lock = [NSLock new]; } return self; } - (void)resume { if (self.isCancelled && !self.isFinished) { [_lock lock]; self.myExecuting = YES; [_lock unlock]; [_downloadTask resume]; } } - (void)start { if (self.isCancelled) { [self reset]; return; } [_lock lock]; self.myExecuting = YES; [_lock unlock]; [self beginTask]; } - (BOOL)isConcurrent { return YES; } - (BOOL)isFinished { return _myFinished; } - (BOOL)isExecuting { return _myExecuting; } - (void)setMyExecuting:(BOOL)myExecuting { [self willChangeValueForKey:@"isExecuting"]; _myExecuting = myExecuting; [self didChangeValueForKey:@"isExecuting"]; } - (void)setMyFinished:(BOOL)myFinished { [self willChangeValueForKey:@"isFinished"]; _myFinished = myFinished; [self didChangeValueForKey:@"isFinished"]; } - (void)beginTask { NSURLRequest *request = [NSURLRequest requestWithURL:_url]; __weak __typeof(self) wself = self; self.downloadTask = [self.session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { __strong __typeof(self) sself = wself; [sself end]; if (!sself.completedBlock) { sself.myFinished = YES; return ; } NSString *caches = [NSSearchPathForDirectoriesInDomains (NSCachesDirectory, NSUserDomainMask, YES) lastObject]; NSString *file = [caches stringByAppendingPathComponent:response.suggestedFilename]; if (location.path) { [NSFileManager.defaultManager moveItemAtPath:location.path toPath:file error:nil]; } NSData *data = [NSData dataWithContentsOfFile:file]; [NSFileManager.defaultManager removeItemAtPath:file error:nil]; if (data == nil || sself.isCancelled) { sself.completedBlock(nil, nil, error); sself.myFinished = YES; return ; } UIImage *image = [UIImage hu_imageFromData:data]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ sself.completedBlock(image, data, nil); sself.myFinished = YES; }]; }]; [_downloadTask resume]; } - (void)reset { [self end]; self.completedBlock = nil; [[self.session dataTaskWithURL:_url] cancel]; } - (void)end { self.myExecuting = NO; self.myFinished = YES; } - (NSURLSession *)session { if (_session == nil) { NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; _session = [NSURLSession sessionWithConfiguration:configuration]; } return _session; } @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/HUWebImageDownloader.h ================================================ // // HUWebImageDownloader.h // HUPhotoBrowser // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import typedef NS_ENUM(NSInteger, HUWebImageOption) { HUWebImageOptionNone, HUWebImageOptionMemoryOnely, HUWebImageOptionMemoryAndDisk, }; typedef void(^HUDownloadCompletionBlock)( UIImage * __nullable image, NSError * __nullable error, NSURL * __nullable imageUrl); @class HUWebImageDownloadOperation; @interface HUWebImageDownloader : NSObject + (nonnull instancetype)sharedInstance; + (nonnull NSString *)cacheKeyForURL:(nonnull NSURL *)url; + (nullable UIImage *)imageFromDiskCacheForKey:(nonnull NSString *)key; + (nullable UIImage *)imageFromMemoryCacheForKey:(nonnull NSString *)key; + (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url completed:(nullable HUDownloadCompletionBlock)completeBlock; + (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url option:(HUWebImageOption)option completed:(nullable HUDownloadCompletionBlock)completeBlock; - (nonnull NSString *)cacheKeyForURL:(nonnull NSURL *)url; - (nullable UIImage *)imageFromDiskCacheForKey:(nonnull NSString *)key; - (nullable UIImage *)imageFromMemoryCacheForKey:(nonnull NSString *)key; - (void)saveImage:(nullable UIImage *)image forKey:(nonnull NSString *)key toDisk:(BOOL)toDisk; - (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url completed:(nullable HUDownloadCompletionBlock)completeBlock; - (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url option:(HUWebImageOption)option completed:(nullable HUDownloadCompletionBlock)completeBlock; @property (nonatomic) BOOL shouldCacheImagesInMemory; @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/HUWebImageDownloader.m ================================================ // // HUWebImageDownloader.m // HUPhotoBrowser // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import "HUWebImageDownloader.h" #import #import "HUWebImageDownloadOperation.h" #import "hu_const.h" static NSString *const kDefaultDiskCachePath = @"com.huwebimagedownloader"; FOUNDATION_STATIC_INLINE NSUInteger HUCacheCostForImage(UIImage *image) { return image.size.width * image.size.height *image.scale * image.scale; } @interface HUWebImageDownloader () { int count; } @property (nonatomic, strong) NSCache *webImageCache; @property (nonatomic) dispatch_queue_t ioQueue; @property (nonatomic, strong) NSOperationQueue *operationQueue; @property (nonatomic, strong) NSMutableDictionary *downloadOperations; @end @implementation HUWebImageDownloader + (nonnull instancetype)sharedInstance { static HUWebImageDownloader *downloader = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ downloader = [self new]; }); return downloader; } - (instancetype)init { self = [super init]; if (self) { _webImageCache = [[NSCache alloc] init]; _shouldCacheImagesInMemory = YES; [self createDefaultCachePath]; _ioQueue = dispatch_queue_create("com.huwebimagedownloader.io", DISPATCH_QUEUE_SERIAL); _downloadOperations = [NSMutableDictionary dictionary]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearMemory) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; } + (nonnull NSString *)cacheKeyForURL:(nonnull NSURL *)url { return [[HUWebImageDownloader sharedInstance] cacheKeyForURL:url]; } + (nullable UIImage *)imageFromDiskCacheForKey:(nonnull NSString *)key { return [[HUWebImageDownloader sharedInstance] imageFromDiskCacheForKey:key]; } + (nullable UIImage *)imageFromMemoryCacheForKey:(nonnull NSString *)key { return [[HUWebImageDownloader sharedInstance] imageFromMemoryCacheForKey:key]; } + (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url completed:(nullable HUDownloadCompletionBlock)completeBlock { return[self downloadImageWithURL:url option:HUWebImageOptionMemoryAndDisk completed:completeBlock]; } + (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url option:(HUWebImageOption)option completed:(nullable HUDownloadCompletionBlock)completeBlock { return[[HUWebImageDownloader sharedInstance] downloadImageWithURL:url option:option completed:completeBlock]; } #pragma mark - save image - (void)saveImage:(nullable UIImage *)image forKey:(nonnull NSString *)key toDisk:(BOOL)toDisk { if (image == nil) { return; } if (toDisk) { NSData *imageData = UIImagePNGRepresentation(image); [self saveImage:imageData toDiskForKey:key]; } [self saveImage:image toMemoryForKey:key]; } #pragma mark - cache key for url - (nonnull NSString *)cacheKeyForURL:(nonnull NSURL *)url { return [url absoluteString]; } #pragma mark - the image from disk for key - (nullable UIImage *)imageFromDiskCacheForKey:(nonnull NSString *)key { UIImage *image = [self imageFromMemoryCacheForKey:key]; //first from memory if (image) { //NSLog(@"image from memory"); return image; } UIImage *diskImage = [self diskImageForKey:key]; if (diskImage && self.shouldCacheImagesInMemory) { ///NSLog(@"image from disk"); NSUInteger cost = HUCacheCostForImage(diskImage); [self.webImageCache setObject:diskImage forKey:key cost:cost]; } return diskImage; } #pragma mark - the image from memory for key - (nullable UIImage *)imageFromMemoryCacheForKey:(nonnull NSString *)key { return [self.webImageCache objectForKey:key]; } #pragma mark - download image for url whit option - (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url option:(HUWebImageOption)option completed:(nullable HUDownloadCompletionBlock)completeBlock { UIImage *image = [self imageFromDiskCacheForKey:[self cacheKeyForURL:url]]; if (image) { if (completeBlock) { completeBlock(image, nil, url); } return nil; } HUWebImageDownloadOperation *operation = self.downloadOperations[[self cacheKeyForURL:url]]; __weak __typeof(self) wself = self; if (operation == nil) { operation = [[HUWebImageDownloadOperation alloc] initWithURL:url completed:^(UIImage *image, NSData *data, NSError *error) { __strong __typeof(self) sself = wself; if (completeBlock) { dispatch_async_main({ completeBlock(image, nil, url); }) } if (image == nil) return ; [sself.downloadOperations removeObjectForKey:[self cacheKeyForURL:url]]; if (option == HUWebImageOptionMemoryAndDisk) { [sself saveImage:data toDiskForKey:[sself cacheKeyForURL:url]]; [sself saveImage:image toMemoryForKey:[sself cacheKeyForURL:url]]; } else if (option == HUWebImageOptionMemoryOnely) { [sself saveImage:image toMemoryForKey:[sself cacheKeyForURL:url]]; } }]; [self.operationQueue addOperation:operation]; [self.downloadOperations setValue:operation forKey:[self cacheKeyForURL:url]]; } else if (operation.isCancelled) { [operation resume]; } return operation; } #pragma mark - download image for url and store to disk - (nonnull HUWebImageDownloadOperation *)downloadImageWithURL:(nonnull NSURL *)url completed:(nullable HUDownloadCompletionBlock)completeBlock { return [self downloadImageWithURL:url option:HUWebImageOptionMemoryAndDisk completed:completeBlock]; } #pragma mark - parvate - (void)saveImage:(UIImage *)image toMemoryForKey:(NSString *)key { UIImage *memoryImage = [self imageFromMemoryCacheForKey:key]; //first from memory if (memoryImage == nil && image) { NSUInteger cost = HUCacheCostForImage(image); [self.webImageCache setObject:image forKey:key cost:cost]; //NSLog(@"save image to memory"); } } #pragma mark - save image to disk - (void)saveImage:(NSData *)imageData toDiskForKey:(NSString *)key { if (imageData == nil) { return; } UIImage *image = [self imageFromDiskCacheForKey:key]; if (image) { return; } NSString *file = [self cacheFileForKey:key]; dispatch_sync(_ioQueue, ^{ // NSLog(@"save data to disk %@", file); [imageData writeToFile:file atomically:YES]; }); } - (UIImage *)diskImageForKey:(NSString *)key { NSString *fileName = [self cacheFileForKey:key]; UIImage *img = [UIImage imageWithContentsOfFile:fileName]; return img; } - (nonnull NSString *)cacheFileForKey:(nonnull NSString *)key { const char *cStr = [key UTF8String]; if (cStr == NULL) { return @""; } unsigned char result[16]; CC_MD5(cStr, (CC_LONG)strlen(cStr), result); NSString *md5Key = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15] ]; NSString *cachePath = [self defaultCahePath]; return [cachePath stringByAppendingPathComponent:md5Key]; } - (BOOL)createDefaultCachePath { NSString *cachePath = [self defaultCahePath]; NSFileManager *fileManager = [NSFileManager defaultManager]; BOOL isDir = FALSE; BOOL isDirExit = [fileManager fileExistsAtPath:cachePath isDirectory:&isDir]; if (!(isDir && isDirExit)) { if ([fileManager createDirectoryAtPath:cachePath withIntermediateDirectories:YES attributes:nil error:nil]) { return NO; } } return isDirExit; } - (NSString *)defaultCahePath { NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; return [cacheDir stringByAppendingPathComponent:kDefaultDiskCachePath]; } - (void)clearMemory { [self.webImageCache removeAllObjects]; [self.downloadOperations removeAllObjects]; } - (NSOperationQueue *)operationQueue { if (!_operationQueue) { _operationQueue = [[NSOperationQueue alloc] init]; _operationQueue.maxConcurrentOperationCount = 5; } return _operationQueue; } @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/UIImage+HUExtension.h ================================================ // // UIImage+HUExtension.h // HUPhotoBrowser // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import @interface UIImage (HUExtension) + (UIImage *)hu_imageFromData:(NSData *)data; @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/UIImage+HUExtension.m ================================================ // // UIImage+HUExtension.m // HUPhotoBrowser // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import "UIImage+HUExtension.h" @implementation UIImage (HUExtension) + (UIImage *)hu_imageFromData:(NSData *)data { UIImage *image = [UIImage imageWithData:data]; return [image fixOrientation]; } - (UIImage *)fixOrientation { // No-op if the orientation is already correct if (self.imageOrientation == UIImageOrientationUp) return self; // We need to calculate the proper transformation to make the image upright. // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. CGAffineTransform transform = CGAffineTransformIdentity; switch (self.imageOrientation) { case UIImageOrientationDown: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); transform = CGAffineTransformRotate(transform, M_PI); break; case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, 0); transform = CGAffineTransformRotate(transform, M_PI_2); break; case UIImageOrientationRight: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate(transform, 0, self.size.height); transform = CGAffineTransformRotate(transform, -M_PI_2); break; default: break; } switch (self.imageOrientation) { case UIImageOrientationUpMirrored: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, 0); transform = CGAffineTransformScale(transform, -1, 1); break; case UIImageOrientationLeftMirrored: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate(transform, self.size.height, 0); transform = CGAffineTransformScale(transform, -1, 1); break; default: break; } // Now we draw the underlying CGImage into a new context, applying the transform // calculated above. CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, CGImageGetBitsPerComponent(self.CGImage), 0, CGImageGetColorSpace(self.CGImage), CGImageGetBitmapInfo(self.CGImage)); CGContextConcatCTM(ctx, transform); switch (self.imageOrientation) { case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: case UIImageOrientationRight: case UIImageOrientationRightMirrored: // Grr... CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); break; default: CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); break; } // And now we just create a new UIImage from the drawing context CGImageRef cgimg = CGBitmapContextCreateImage(ctx); UIImage *img = [UIImage imageWithCGImage:cgimg]; CGContextRelease(ctx); CGImageRelease(cgimg); return img; } @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/UIImageView+HUWebImage.h ================================================ // // UIImageView+HUWebImage.h // HUPhotoBrowser // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import @interface UIImageView (HUWebImage) - (void)hu_setImageWithURL:(nullable NSURL *)url; - (void)hu_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder; - (void)hu_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable void(^)(UIImage * __nullable image, NSError * __nullable error, NSURL * __nullable imageUrl))completed; @end ================================================ FILE: HUPhotoBrowser/HUWebImageDownloader/UIImageView+HUWebImage.m ================================================ // // UIImageView+HUWebImage.m // HUPhotoBrowser // // Created by mac on 16/2/25. // Copyright (c) 2016年 hujewelz. All rights reserved. // #import "UIImageView+HUWebImage.h" #import "HUWebImageDownloadOperation.h" #import "HUWebImageDownloader.h" #import #import "hu_const.h" static char *loadOperationKey = "loadOperationKey"; static char imageURLKey; @implementation UIImageView (HUWebImage) - (void)hu_setImageWithURL:(nullable NSURL *)url { [self hu_setImageWithURL:url placeholderImage:nil]; } - (void)hu_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { [self hu_setImageWithURL:url placeholderImage:placeholder completed:nil]; } - (void)hu_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable void (^)(UIImage *, NSError *, NSURL *))completed { if (url == nil) { return; } self.image = nil; self.image = placeholder; [self hu_cancelImageDownloadOperationForKey:@"downloadimage"]; objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); __weak __typeof(self) wself = self; HUWebImageDownloadOperation *operation = [HUWebImageDownloader downloadImageWithURL:url completed:^(UIImage *image, NSError *error, NSURL *imageUrl) { __strong __typeof (wself) sself = wself; if (!sself) { return ; } if (![[sself hu_imageURL].absoluteString isEqualToString:url.absoluteString]) { return; } dispatch_async_main({ if (image) { sself.image = image; [sself setNeedsLayout]; } else { sself.image = placeholder; [sself setNeedsLayout]; } if (completed) { completed(image, error, imageUrl); } }) }]; if (operation) { [self hu_setImageDownloadOperation:operation forKey:@"downloadimage"]; } } - (void)hu_setImageDownloadOperation:(id)operation forKey:(NSString *)key { if (key == nil) { return ; } [self hu_cancelImageDownloadOperationForKey:key]; NSMutableDictionary *operations = [self operationDict]; [operations setObject:operation forKey:key]; } - (void)hu_cancelImageDownloadOperationForKey:(NSString *)key { NSMutableDictionary *operations = [self operationDict]; id operation = operations[key]; if ([operation isKindOfClass:[HUWebImageDownloadOperation class]]) { [operation cancel]; } [operations removeObjectForKey:key]; } - (NSMutableDictionary *)operationDict { NSMutableDictionary *operations = objc_getAssociatedObject(self, loadOperationKey); if (operations) { return operations; } operations = [NSMutableDictionary dictionary]; objc_setAssociatedObject(self, loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return operations; } - (NSURL *)hu_imageURL { return objc_getAssociatedObject(self, &imageURLKey); } @end ================================================ FILE: HUPhotoBrowser/UIView+frame.h ================================================ // // UIView+Extension.h // 微博 // // Created by jewelz on 15/4/23. // Copyright (c) 2015年 yangtzeu. All rights reserved. // #import @interface UIView (frame) @property (assign, nonatomic) CGFloat x; @property (assign, nonatomic) CGFloat y; @property (assign, nonatomic) CGFloat width; @property (assign, nonatomic) CGFloat height; @property (assign, nonatomic) CGSize size; @property (assign, nonatomic) CGPoint origion; @end ================================================ FILE: HUPhotoBrowser/UIView+frame.m ================================================ // // UIView+Extension.m // 微博 // // Created by jewelz on 15/4/23. // Copyright (c) 2015年 yangtzeu. All rights reserved. // #import "UIView+frame.h" @implementation UIView (frame) - (void)setX:(CGFloat)x { CGRect frame = self.frame; frame.origin.x = x; self.frame = frame; } - (CGFloat)x { return self.frame.origin.x; } - (void)setY:(CGFloat)y { CGRect frame = self.frame; frame.origin.y = y; self.frame = frame; } - (CGFloat)y { return self.frame.origin.y; } - (void)setWidth:(CGFloat)width { CGRect frame = self.frame; frame.size.width = width; self.frame = frame; } - (CGFloat)width { return self.frame.size.width; } - (void)setHeight:(CGFloat)height { CGRect frame = self.frame; frame.size.height = height; self.frame = frame; } - (CGFloat)height { return self.frame.size.height; } - (void)setSize:(CGSize)size { CGRect frame = self.frame; frame.size = size; self.frame = frame; } - (CGSize)size { return self.frame.size; } - (void)setOrigion:(CGPoint)origion { CGRect frame = self.frame; frame.origin = origion; self.frame = frame; } - (CGPoint)origion { return self.frame.origin; } @end ================================================ FILE: HUPhotoBrowser/hu_const.h ================================================ // // const.h // HUPhotoBrowser // // Created by mac on 16/2/24. // Copyright (c) 2016年 jinhuadiqigan. All rights reserved. // #ifndef HUPhotoBrowser_const_h #define HUPhotoBrowser_const_h #define kScreenRect [UIScreen mainScreen].bounds #define kScreenWidth [UIScreen mainScreen].bounds.size.width #define kScreenHeight [UIScreen mainScreen].bounds.size.height #define kScreenRatio kScreenWidth / kScreenHeight #define kScreenMidX CGRectGetMaxX(kScreenRect) #define kScreenMidY CGRectGetMaxY(kScreenRect) #define dispatch_async_main(block) if ([NSThread isMainThread]) { \ block;\ } else { \ dispatch_async(dispatch_get_main_queue(), ^{ \ block; \ }); \ } \ #endif ================================================ FILE: HUPhotoBrowser.podspec ================================================ # # Be sure to run `pod spec lint HUPhotoBrowser.podspec' to ensure this is a # valid spec and to remove all comments including this before submitting the spec. # # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ # Pod::Spec.new do |s| s.name = "HUPhotoBrowser" s.version = "1.4.5" s.summary = "photo browser for ios, which can browse Photo library and web image" s.homepage = "https://github.com/hujewelz/HUPhotoBrowser" s.license = "MIT" s.author = { "Jewelz Hu" => "https://github.com/hujewelz/HUPhotoBrowser" } s.platform = :ios, "7.0" s.source = { :git => "https://github.com/hujewelz/HUPhotoBrowser.git", :tag => s.version.to_s } s.source_files = "HUPhotoBrowser/**/*.{h,m}" s.requires_arc = true s.frameworks = "UIKit", "Photos", "AssetsLibrary" s.public_header_files = "HUPhotoBrowser/HUPhotoBrowser.h","HUPhotoBrowser/HUWebImageDownloader/HUWebImage.h", "HUPhotoBrowser/HUWebImageDownloader/{UIImageView+HUWebImage,HUWebImageDownloader}.h" s.dependency "SVProgressHUD" end ================================================ FILE: HUPhotoBrowser.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 040622691C7E93D0005653C1 /* libHUPhotoBrowser.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0406225D1C7E93D0005653C1 /* libHUPhotoBrowser.a */; }; 040624741C7EEF60005653C1 /* HUPhotoBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 040624711C7EEF60005653C1 /* HUPhotoBrowser.m */; }; 040624751C7EEF60005653C1 /* HUPhotoBrowserCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 040624731C7EEF60005653C1 /* HUPhotoBrowserCell.m */; }; 044D06641CD35F41005BDFF2 /* HUAlbum.m in Sources */ = {isa = PBXBuildFile; fileRef = 044D06531CD35F41005BDFF2 /* HUAlbum.m */; }; 044D06651CD35F41005BDFF2 /* HUAlbumCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 044D06551CD35F41005BDFF2 /* HUAlbumCell.m */; }; 044D06661CD35F41005BDFF2 /* HUAlbumsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 044D06581CD35F41005BDFF2 /* HUAlbumsViewController.m */; }; 044D06671CD35F41005BDFF2 /* HUImagePickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 044D065A1CD35F41005BDFF2 /* HUImagePickerCell.m */; }; 044D06681CD35F41005BDFF2 /* HUImagePickerRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 044D065D1CD35F41005BDFF2 /* HUImagePickerRootViewController.m */; }; 044D06691CD35F41005BDFF2 /* HUImagePickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 044D065F1CD35F41005BDFF2 /* HUImagePickerViewController.m */; }; 044D066A1CD35F41005BDFF2 /* HUPhotoHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 044D06611CD35F41005BDFF2 /* HUPhotoHelper.m */; }; 048D4E5A1CD05FB80042B958 /* HUWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 048D4E531CD05FB80042B958 /* HUWebImageDownloader.m */; }; 048D4E5B1CD05FB80042B958 /* HUWebImageDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 048D4E551CD05FB80042B958 /* HUWebImageDownloadOperation.m */; }; 048D4E5C1CD05FB80042B958 /* UIImage+HUExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 048D4E571CD05FB80042B958 /* UIImage+HUExtension.m */; }; 048D4E5D1CD05FB80042B958 /* UIImageView+HUWebImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 048D4E591CD05FB80042B958 /* UIImageView+HUWebImage.m */; }; 513CFE841CD4B5F700341995 /* HUToast.m in Sources */ = {isa = PBXBuildFile; fileRef = 513CFE811CD4B5F700341995 /* HUToast.m */; }; 513CFE851CD4B5F700341995 /* UIView+frame.m in Sources */ = {isa = PBXBuildFile; fileRef = 513CFE831CD4B5F700341995 /* UIView+frame.m */; }; 51B662261E7F80AB00397C5D /* HUPhotoBrowser.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 040624701C7EEF60005653C1 /* HUPhotoBrowser.h */; }; 51B662271E7F80AB00397C5D /* HUImagePickerViewController.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 044D065E1CD35F41005BDFF2 /* HUImagePickerViewController.h */; }; 51B662281E7F80AB00397C5D /* HUWebImageDownloader.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 048D4E521CD05FB80042B958 /* HUWebImageDownloader.h */; }; 51B662291E7F80AB00397C5D /* UIImageView+HUWebImage.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 048D4E581CD05FB80042B958 /* UIImageView+HUWebImage.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 0406226A1C7E93D0005653C1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 040622551C7E93D0005653C1 /* Project object */; proxyType = 1; remoteGlobalIDString = 0406225C1C7E93D0005653C1; remoteInfo = HUPhotoBrowser; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 0406225B1C7E93D0005653C1 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "include/$(PRODUCT_NAME)"; dstSubfolderSpec = 16; files = ( 51B662261E7F80AB00397C5D /* HUPhotoBrowser.h in CopyFiles */, 51B662271E7F80AB00397C5D /* HUImagePickerViewController.h in CopyFiles */, 51B662281E7F80AB00397C5D /* HUWebImageDownloader.h in CopyFiles */, 51B662291E7F80AB00397C5D /* UIImageView+HUWebImage.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 0406225D1C7E93D0005653C1 /* libHUPhotoBrowser.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHUPhotoBrowser.a; sourceTree = BUILT_PRODUCTS_DIR; }; 040622681C7E93D0005653C1 /* HUPhotoBrowserTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HUPhotoBrowserTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0406226E1C7E93D0005653C1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 040622AF1C7E94A6005653C1 /* hu_const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hu_const.h; sourceTree = ""; }; 040624701C7EEF60005653C1 /* HUPhotoBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUPhotoBrowser.h; sourceTree = ""; }; 040624711C7EEF60005653C1 /* HUPhotoBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUPhotoBrowser.m; sourceTree = ""; }; 040624721C7EEF60005653C1 /* HUPhotoBrowserCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUPhotoBrowserCell.h; sourceTree = ""; }; 040624731C7EEF60005653C1 /* HUPhotoBrowserCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUPhotoBrowserCell.m; sourceTree = ""; }; 044D06521CD35F41005BDFF2 /* HUAlbum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUAlbum.h; sourceTree = ""; }; 044D06531CD35F41005BDFF2 /* HUAlbum.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUAlbum.m; sourceTree = ""; }; 044D06541CD35F41005BDFF2 /* HUAlbumCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUAlbumCell.h; sourceTree = ""; }; 044D06551CD35F41005BDFF2 /* HUAlbumCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUAlbumCell.m; sourceTree = ""; }; 044D06561CD35F41005BDFF2 /* HUAlbumCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HUAlbumCell.xib; sourceTree = ""; }; 044D06571CD35F41005BDFF2 /* HUAlbumsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUAlbumsViewController.h; sourceTree = ""; }; 044D06581CD35F41005BDFF2 /* HUAlbumsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUAlbumsViewController.m; sourceTree = ""; }; 044D06591CD35F41005BDFF2 /* HUImagePickerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUImagePickerCell.h; sourceTree = ""; }; 044D065A1CD35F41005BDFF2 /* HUImagePickerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUImagePickerCell.m; sourceTree = ""; }; 044D065B1CD35F41005BDFF2 /* HUImagePickerCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HUImagePickerCell.xib; sourceTree = ""; }; 044D065C1CD35F41005BDFF2 /* HUImagePickerRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUImagePickerRootViewController.h; sourceTree = ""; }; 044D065D1CD35F41005BDFF2 /* HUImagePickerRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUImagePickerRootViewController.m; sourceTree = ""; }; 044D065E1CD35F41005BDFF2 /* HUImagePickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUImagePickerViewController.h; sourceTree = ""; }; 044D065F1CD35F41005BDFF2 /* HUImagePickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUImagePickerViewController.m; sourceTree = ""; }; 044D06601CD35F41005BDFF2 /* HUPhotoHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUPhotoHelper.h; sourceTree = ""; }; 044D06611CD35F41005BDFF2 /* HUPhotoHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUPhotoHelper.m; sourceTree = ""; }; 044D06621CD35F41005BDFF2 /* pick_checked@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pick_checked@2x.png"; sourceTree = ""; }; 044D06631CD35F41005BDFF2 /* pick_checked@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pick_checked@3x.png"; sourceTree = ""; }; 048D4E511CD05FB80042B958 /* HUWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUWebImage.h; sourceTree = ""; }; 048D4E521CD05FB80042B958 /* HUWebImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUWebImageDownloader.h; sourceTree = ""; }; 048D4E531CD05FB80042B958 /* HUWebImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUWebImageDownloader.m; sourceTree = ""; }; 048D4E541CD05FB80042B958 /* HUWebImageDownloadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUWebImageDownloadOperation.h; sourceTree = ""; }; 048D4E551CD05FB80042B958 /* HUWebImageDownloadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUWebImageDownloadOperation.m; sourceTree = ""; }; 048D4E561CD05FB80042B958 /* UIImage+HUExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+HUExtension.h"; sourceTree = ""; }; 048D4E571CD05FB80042B958 /* UIImage+HUExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+HUExtension.m"; sourceTree = ""; }; 048D4E581CD05FB80042B958 /* UIImageView+HUWebImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImageView+HUWebImage.h"; sourceTree = ""; }; 048D4E591CD05FB80042B958 /* UIImageView+HUWebImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImageView+HUWebImage.m"; sourceTree = ""; }; 513CFE801CD4B5F700341995 /* HUToast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HUToast.h; sourceTree = ""; }; 513CFE811CD4B5F700341995 /* HUToast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HUToast.m; sourceTree = ""; }; 513CFE821CD4B5F700341995 /* UIView+frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+frame.h"; sourceTree = ""; }; 513CFE831CD4B5F700341995 /* UIView+frame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+frame.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0406225A1C7E93D0005653C1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 040622651C7E93D0005653C1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 040622691C7E93D0005653C1 /* libHUPhotoBrowser.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 040622541C7E93D0005653C1 = { isa = PBXGroup; children = ( 0406225F1C7E93D0005653C1 /* HUPhotoBrowser */, 0406226C1C7E93D0005653C1 /* HUPhotoBrowserTests */, 0406225E1C7E93D0005653C1 /* Products */, ); sourceTree = ""; }; 0406225E1C7E93D0005653C1 /* Products */ = { isa = PBXGroup; children = ( 0406225D1C7E93D0005653C1 /* libHUPhotoBrowser.a */, 040622681C7E93D0005653C1 /* HUPhotoBrowserTests.xctest */, ); name = Products; sourceTree = ""; }; 0406225F1C7E93D0005653C1 /* HUPhotoBrowser */ = { isa = PBXGroup; children = ( 040624701C7EEF60005653C1 /* HUPhotoBrowser.h */, 040624711C7EEF60005653C1 /* HUPhotoBrowser.m */, 040624721C7EEF60005653C1 /* HUPhotoBrowserCell.h */, 040624731C7EEF60005653C1 /* HUPhotoBrowserCell.m */, 040622AF1C7E94A6005653C1 /* hu_const.h */, 513CFE801CD4B5F700341995 /* HUToast.h */, 513CFE811CD4B5F700341995 /* HUToast.m */, 513CFE821CD4B5F700341995 /* UIView+frame.h */, 513CFE831CD4B5F700341995 /* UIView+frame.m */, 044D06511CD35F41005BDFF2 /* HUPhotoPicker */, 048D4E501CD05FB80042B958 /* HUWebImageDownloader */, ); path = HUPhotoBrowser; sourceTree = ""; }; 0406226C1C7E93D0005653C1 /* HUPhotoBrowserTests */ = { isa = PBXGroup; children = ( 0406226D1C7E93D0005653C1 /* Supporting Files */, ); path = HUPhotoBrowserTests; sourceTree = ""; }; 0406226D1C7E93D0005653C1 /* Supporting Files */ = { isa = PBXGroup; children = ( 0406226E1C7E93D0005653C1 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 044D06511CD35F41005BDFF2 /* HUPhotoPicker */ = { isa = PBXGroup; children = ( 044D065E1CD35F41005BDFF2 /* HUImagePickerViewController.h */, 044D065F1CD35F41005BDFF2 /* HUImagePickerViewController.m */, 044D065C1CD35F41005BDFF2 /* HUImagePickerRootViewController.h */, 044D065D1CD35F41005BDFF2 /* HUImagePickerRootViewController.m */, 044D06571CD35F41005BDFF2 /* HUAlbumsViewController.h */, 044D06581CD35F41005BDFF2 /* HUAlbumsViewController.m */, 044D06541CD35F41005BDFF2 /* HUAlbumCell.h */, 044D06551CD35F41005BDFF2 /* HUAlbumCell.m */, 044D06561CD35F41005BDFF2 /* HUAlbumCell.xib */, 044D06591CD35F41005BDFF2 /* HUImagePickerCell.h */, 044D065A1CD35F41005BDFF2 /* HUImagePickerCell.m */, 044D065B1CD35F41005BDFF2 /* HUImagePickerCell.xib */, 044D06521CD35F41005BDFF2 /* HUAlbum.h */, 044D06531CD35F41005BDFF2 /* HUAlbum.m */, 044D06601CD35F41005BDFF2 /* HUPhotoHelper.h */, 044D06611CD35F41005BDFF2 /* HUPhotoHelper.m */, 044D06621CD35F41005BDFF2 /* pick_checked@2x.png */, 044D06631CD35F41005BDFF2 /* pick_checked@3x.png */, ); path = HUPhotoPicker; sourceTree = ""; }; 048D4E501CD05FB80042B958 /* HUWebImageDownloader */ = { isa = PBXGroup; children = ( 048D4E511CD05FB80042B958 /* HUWebImage.h */, 048D4E521CD05FB80042B958 /* HUWebImageDownloader.h */, 048D4E531CD05FB80042B958 /* HUWebImageDownloader.m */, 048D4E541CD05FB80042B958 /* HUWebImageDownloadOperation.h */, 048D4E551CD05FB80042B958 /* HUWebImageDownloadOperation.m */, 048D4E561CD05FB80042B958 /* UIImage+HUExtension.h */, 048D4E571CD05FB80042B958 /* UIImage+HUExtension.m */, 048D4E581CD05FB80042B958 /* UIImageView+HUWebImage.h */, 048D4E591CD05FB80042B958 /* UIImageView+HUWebImage.m */, ); path = HUWebImageDownloader; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 0406225C1C7E93D0005653C1 /* HUPhotoBrowser */ = { isa = PBXNativeTarget; buildConfigurationList = 040622711C7E93D0005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowser" */; buildPhases = ( 040622591C7E93D0005653C1 /* Sources */, 0406225A1C7E93D0005653C1 /* Frameworks */, 0406225B1C7E93D0005653C1 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = HUPhotoBrowser; productName = HUPhotoBrowser; productReference = 0406225D1C7E93D0005653C1 /* libHUPhotoBrowser.a */; productType = "com.apple.product-type.library.static"; }; 040622671C7E93D0005653C1 /* HUPhotoBrowserTests */ = { isa = PBXNativeTarget; buildConfigurationList = 040622741C7E93D0005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowserTests" */; buildPhases = ( 040622641C7E93D0005653C1 /* Sources */, 040622651C7E93D0005653C1 /* Frameworks */, 040622661C7E93D0005653C1 /* Resources */, ); buildRules = ( ); dependencies = ( 0406226B1C7E93D0005653C1 /* PBXTargetDependency */, ); name = HUPhotoBrowserTests; productName = HUPhotoBrowserTests; productReference = 040622681C7E93D0005653C1 /* HUPhotoBrowserTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 040622551C7E93D0005653C1 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0720; ORGANIZATIONNAME = hujewelz; TargetAttributes = { 0406225C1C7E93D0005653C1 = { CreatedOnToolsVersion = 6.4; }; 040622671C7E93D0005653C1 = { CreatedOnToolsVersion = 6.4; }; }; }; buildConfigurationList = 040622581C7E93D0005653C1 /* Build configuration list for PBXProject "HUPhotoBrowser" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 040622541C7E93D0005653C1; productRefGroup = 0406225E1C7E93D0005653C1 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 0406225C1C7E93D0005653C1 /* HUPhotoBrowser */, 040622671C7E93D0005653C1 /* HUPhotoBrowserTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 040622661C7E93D0005653C1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 040622591C7E93D0005653C1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 044D06661CD35F41005BDFF2 /* HUAlbumsViewController.m in Sources */, 044D066A1CD35F41005BDFF2 /* HUPhotoHelper.m in Sources */, 040624741C7EEF60005653C1 /* HUPhotoBrowser.m in Sources */, 513CFE851CD4B5F700341995 /* UIView+frame.m in Sources */, 048D4E5A1CD05FB80042B958 /* HUWebImageDownloader.m in Sources */, 040624751C7EEF60005653C1 /* HUPhotoBrowserCell.m in Sources */, 048D4E5B1CD05FB80042B958 /* HUWebImageDownloadOperation.m in Sources */, 048D4E5D1CD05FB80042B958 /* UIImageView+HUWebImage.m in Sources */, 044D06681CD35F41005BDFF2 /* HUImagePickerRootViewController.m in Sources */, 044D06671CD35F41005BDFF2 /* HUImagePickerCell.m in Sources */, 044D06641CD35F41005BDFF2 /* HUAlbum.m in Sources */, 044D06691CD35F41005BDFF2 /* HUImagePickerViewController.m in Sources */, 044D06651CD35F41005BDFF2 /* HUAlbumCell.m in Sources */, 513CFE841CD4B5F700341995 /* HUToast.m in Sources */, 048D4E5C1CD05FB80042B958 /* UIImage+HUExtension.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 040622641C7E93D0005653C1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 0406226B1C7E93D0005653C1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0406225C1C7E93D0005653C1 /* HUPhotoBrowser */; targetProxy = 0406226A1C7E93D0005653C1 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 0406226F1C7E93D0005653C1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 040622701C7E93D0005653C1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 040622721C7E93D0005653C1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 040622731C7E93D0005653C1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; 040622751C7E93D0005653C1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = HUPhotoBrowserTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hujewelz.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 040622761C7E93D0005653C1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = HUPhotoBrowserTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hujewelz.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 040622581C7E93D0005653C1 /* Build configuration list for PBXProject "HUPhotoBrowser" */ = { isa = XCConfigurationList; buildConfigurations = ( 0406226F1C7E93D0005653C1 /* Debug */, 040622701C7E93D0005653C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 040622711C7E93D0005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowser" */ = { isa = XCConfigurationList; buildConfigurations = ( 040622721C7E93D0005653C1 /* Debug */, 040622731C7E93D0005653C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 040622741C7E93D0005653C1 /* Build configuration list for PBXNativeTarget "HUPhotoBrowserTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 040622751C7E93D0005653C1 /* Debug */, 040622761C7E93D0005653C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 040622551C7E93D0005653C1 /* Project object */; } ================================================ FILE: HUPhotoBrowser.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: HUPhotoBrowser.xcodeproj/project.xcworkspace/xcshareddata/HUPhotoBrowser.xccheckout ================================================ IDESourceControlProjectFavoriteDictionaryKey IDESourceControlProjectIdentifier D0727199-8C7A-438B-A052-108CA74B7080 IDESourceControlProjectName project IDESourceControlProjectOriginsDictionary 3E54BB6501640F2F1E4E23A6F020501F2858AB48 https://github.com/hujewelz/HUPhotoBrowser.git IDESourceControlProjectPath HUPhotoBrowser.xcodeproj/project.xcworkspace IDESourceControlProjectRelativeInstallPathDictionary 3E54BB6501640F2F1E4E23A6F020501F2858AB48 ../.. IDESourceControlProjectURL https://github.com/hujewelz/HUPhotoBrowser.git IDESourceControlProjectVersion 111 IDESourceControlProjectWCCIdentifier 3E54BB6501640F2F1E4E23A6F020501F2858AB48 IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey 3E54BB6501640F2F1E4E23A6F020501F2858AB48 IDESourceControlWCCName HUPhotoBrowser ================================================ FILE: HUPhotoBrowser.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/HUPhotoBrowser.xcscheme ================================================ ================================================ FILE: HUPhotoBrowser.xcodeproj/xcuserdata/jewelz.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState HUPhotoBrowser.xcscheme orderHint 0 SuppressBuildableAutocreation 0406225C1C7E93D0005653C1 primary 040622671C7E93D0005653C1 primary ================================================ FILE: HUPhotoBrowser.xcodeproj/xcuserdata/mac.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist ================================================ ================================================ FILE: HUPhotoBrowser.xcodeproj/xcuserdata/mac.xcuserdatad/xcschemes/HUPhotoBrowser.xcscheme ================================================ ================================================ FILE: HUPhotoBrowser.xcodeproj/xcuserdata/mac.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState HUPhotoBrowser.xcscheme orderHint 0 SuppressBuildableAutocreation 0406225C1C7E93D0005653C1 primary 040622671C7E93D0005653C1 primary ================================================ FILE: HUPhotoBrowserTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 Jewelz Hu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # HUPhotoBrowser [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/hujewelz/HUPhotoBrowser/master/LICENSE) [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/HUPhotoBrowser.svg)](https://img.shields.io/cocoapods/v/HUPhotoBrowser.svg) ⚠️最新的版本不再集成[HUPhotoPicker](https://github.com/hujewelz/HUPhotoPicker)了,需要使用的同学可以指定版本为 `1.2.5`,推荐单独使用[HUPhotoPicker](https://github.com/hujewelz/HUPhotoPicker) **HUPhotoBrowser** ios图片浏览器,支持浏览本地图片及网络图片,暂不支持浏览视频及gif,使用起来非常简单,只需要一行代码。 **HUImagePickerViewController** 图片选择器,你可以像使用`UIImagePickerController`一样的使用它,支持图片多选。 ![image](https://github.com/hujewelz/HUPhotoBrowser/blob/master/screenshot/2016-04-3008_57_13.gif) ## PhotoBrowser的使用 在需要用到的地方 `#import ` HUPhotoBrowser支持本地图片浏览 [HUPhotoBrowser showFromImageView:cell.imageView withImages:self.images atIndex:indexPath.row]; HUPhotoBrowser同时支持网络图片浏览 [HUPhotoBrowser showFromImageView:cell.imageView withURLStrings:_URLStrings placeholderImage:[UIImage imageNamed:@"placeholder"] atIndex:indexPath.row dismiss:nil]; 在需要浏览的图片的点击事件中调用即可: ```Objective-C - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { PhotoCell *cell = (PhotoCell *)[collectionView cellForItemAtIndexPath:indexPath]; if (_localImage) { [HUPhotoBrowser showFromImageView:cell.imageView withImages:self.originalImages atIndex:indexPath.row]; } else { [HUPhotoBrowser showFromImageView:cell.imageView withURLStrings:_URLStrings placeholderImage:[UIImage imageNamed:@"placeholder"] atIndex:indexPath.row dismiss:nil]; } } ``` 你还可以获取到当前浏览到的图片 ```Objective-C [HUPhotoBrowser showFromImageView:cell.imageView withImages:self.images placeholderImage:nil atIndex:indexPath.row dismiss:^(UIImage *image, NSInteger index) { }]; ``` ## 安装 1. [CocoaPods](https://cocoapods.org/)安装: ``` pod 'HUPhotoBrowser' ``` 2. 下载ZIP包,将`HUPhotoBrowser`资源文件拖到工程中。 3. 将`HUPhotoBrowser.xcodeproj`工程文件和`HUPhotoBrowser`源文件一同拖入工程目录下,在工程中右键选择 "Add Files to ...",选择`HUPhotoBrowser.xcodeproj`。 ![](http://image18-c.poco.cn/mypoco/myphoto/20170320/12/18436043320170320121521061.jpg?542x710_120) 然后在 "Build Settings -> Header Search Paths" 中添加源文件路径。 ## 其他 为了不影响您项目中导入的其他第三方库,本库没有导入任何其他的第三方内容,可以放心使用。在使用前,您可以查看[示例程序](https://github.com/hujewelz/HUPhotoBrowser/tree/master/Example) * 如果在使用过程中遇到BUG,希望你能Issues我,谢谢(或者尝试下载最新的框架代码看看BUG修复没有) * 如果您有什么建议可以Issues我,谢谢 * 后续我会持续更新,为它添加更多的功能,欢迎star :)