From 23d00d40e12e443ba23ccc159f183514f1159470 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 11 Apr 2016 19:04:05 -0700 Subject: [PATCH] [New Example] 500pxgram - added UIActivityMonitor - added simple NSCache for UIKit tab --- examples/ASDKgram/Sample/AppDelegate.m | 7 ++-- examples/ASDKgram/Sample/PhotoFeedModel.m | 18 ++++++---- .../ASDKgram/Sample/PhotoFeedNodeController.m | 28 +++++++++++---- .../ASDKgram/Sample/PhotoFeedViewController.m | 27 ++++++++++++--- examples/ASDKgram/Sample/PhotoTableViewCell.m | 21 ++++-------- examples/ASDKgram/Sample/Utilities.h | 1 + examples/ASDKgram/Sample/Utilities.m | 34 +++++++++++++++++++ 7 files changed, 102 insertions(+), 34 deletions(-) diff --git a/examples/ASDKgram/Sample/AppDelegate.m b/examples/ASDKgram/Sample/AppDelegate.m index 3ca5ff44..dbb7233d 100644 --- a/examples/ASDKgram/Sample/AppDelegate.m +++ b/examples/ASDKgram/Sample/AppDelegate.m @@ -64,15 +64,16 @@ return YES; } -// UITabBarControllerDelegate -- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController; +#pragma mark - UITabBarControllerDelegate + +- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { if ([viewController isKindOfClass:[UINavigationController class]]) { NSArray *viewControllers = [(UINavigationController *)viewController viewControllers]; UIViewController *rootViewController = viewControllers[0]; if ([rootViewController conformsToProtocol:@protocol(PhotoFeedControllerProtocol)]) { // FIXME: the dataModel does not currently handle clearing data during loading properly -// [(id )rootViewController resetAllData]; +// [(id )rootViewController resetAllData]; } } } diff --git a/examples/ASDKgram/Sample/PhotoFeedModel.m b/examples/ASDKgram/Sample/PhotoFeedModel.m index 56cfb133..fb98b153 100644 --- a/examples/ASDKgram/Sample/PhotoFeedModel.m +++ b/examples/ASDKgram/Sample/PhotoFeedModel.m @@ -29,8 +29,9 @@ NSUInteger _totalItems; BOOL _fetchPageInProgress; BOOL _refreshFeedInProgress; - - CLLocationCoordinate2D _location; + NSURLSessionDataTask *_task; + + CLLocationCoordinate2D _location; NSUInteger _locationRadius; NSUInteger _userID; } @@ -123,7 +124,12 @@ - (void)clearFeed { _photos = [[NSMutableArray alloc] init]; - _ids = [[NSMutableArray alloc] init]; + _ids = [[NSMutableArray alloc] init]; + _currentPage = 0; + _fetchPageInProgress = NO; + _refreshFeedInProgress = NO; + [_task cancel]; + _task = nil; } - (void)requestPageWithCompletionBlock:(void (^)(NSArray *))block numResultsToReturn:(NSUInteger)numResults @@ -185,7 +191,7 @@ NSString *urlAdditions = [NSString stringWithFormat:@"&page=%lu&rpp=%lu%@", (unsigned long)nextPage, (long)numPhotos, imageSizeParam]; NSURL *url = [NSURL URLWithString:[_urlString stringByAppendingString:urlAdditions]]; NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; - NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + _task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (data) { NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; @@ -223,8 +229,8 @@ } _fetchPageInProgress = NO; }); - }]; // end task - [task resume]; + }]; + [_task resume]; } }); } diff --git a/examples/ASDKgram/Sample/PhotoFeedNodeController.m b/examples/ASDKgram/Sample/PhotoFeedNodeController.m index e512db8a..16f08ad5 100644 --- a/examples/ASDKgram/Sample/PhotoFeedNodeController.m +++ b/examples/ASDKgram/Sample/PhotoFeedNodeController.m @@ -20,8 +20,9 @@ @implementation PhotoFeedNodeController { - PhotoFeedModel *_photoFeed; - ASTableNode *_tableNode; + PhotoFeedModel *_photoFeed; + ASTableNode *_tableNode; + UIActivityIndicatorView *_activityIndicatorView; } #pragma mark - Lifecycle @@ -35,12 +36,10 @@ self.navigationItem.title = @"ASDK"; [self.navigationController setNavigationBarHidden:YES]; - _photoFeed = [[PhotoFeedModel alloc] initWithPhotoFeedModelType:PhotoFeedModelTypePopular - imageSize:[self imageSizeForScreenWidth]]; - [self refreshFeed]; - _tableNode.dataSource = self; _tableNode.delegate = self; + + _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; } return self; @@ -51,20 +50,35 @@ { [super loadView]; + _photoFeed = [[PhotoFeedModel alloc] initWithPhotoFeedModelType:PhotoFeedModelTypePopular imageSize:[self imageSizeForScreenWidth]]; + [self refreshFeed]; + + CGSize boundSize = self.view.bounds.size; + + [_activityIndicatorView sizeToFit]; + CGRect refreshRect = _activityIndicatorView.frame; + refreshRect.origin = CGPointMake((boundSize.width - _activityIndicatorView.frame.size.width) / 2.0, + (boundSize.height - _activityIndicatorView.frame.size.height) / 2.0); + _activityIndicatorView.frame = refreshRect; + + [self.view addSubview:_activityIndicatorView]; + self.view.backgroundColor = [UIColor whiteColor]; _tableNode.view.allowsSelection = NO; _tableNode.view.separatorStyle = UITableViewCellSeparatorStyleNone; _tableNode.view.leadingScreensForBatching = AUTO_TAIL_LOADING_NUM_SCREENFULS; // overriding default of 2.0 - } #pragma mark - helper methods - (void)refreshFeed { + [_activityIndicatorView startAnimating]; // small first batch [_photoFeed refreshFeedWithCompletionBlock:^(NSArray *newPhotos){ + [_activityIndicatorView stopAnimating]; + [self insertNewRowsInTableView:newPhotos]; [self requestCommentsForPhotos:newPhotos]; diff --git a/examples/ASDKgram/Sample/PhotoFeedViewController.m b/examples/ASDKgram/Sample/PhotoFeedViewController.m index d314a11c..1336ea5f 100644 --- a/examples/ASDKgram/Sample/PhotoFeedViewController.m +++ b/examples/ASDKgram/Sample/PhotoFeedViewController.m @@ -19,8 +19,9 @@ @implementation PhotoFeedViewController { - PhotoFeedModel *_photoFeed; - UITableView *_tableView; + PhotoFeedModel *_photoFeed; + UITableView *_tableView; + UIActivityIndicatorView *_activityIndicatorView; } #pragma mark - Lifecycle @@ -38,8 +39,7 @@ _tableView.delegate = self; _tableView.dataSource = self; - _photoFeed = [[PhotoFeedModel alloc] initWithPhotoFeedModelType:PhotoFeedModelTypePopular imageSize:[self imageSizeForScreenWidth]]; - [self refreshFeed]; + _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; } return self; @@ -50,19 +50,38 @@ { [super viewDidLoad]; + _photoFeed = [[PhotoFeedModel alloc] initWithPhotoFeedModelType:PhotoFeedModelTypePopular imageSize:[self imageSizeForScreenWidth]]; + [self refreshFeed]; + + CGSize boundSize = self.view.bounds.size; + [self.view addSubview:_tableView]; + _tableView.frame = self.view.bounds; _tableView.allowsSelection = NO; _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; [_tableView registerClass:[PhotoTableViewCell class] forCellReuseIdentifier:@"photoCell"]; + + [self.view addSubview:_activityIndicatorView]; + + [_activityIndicatorView sizeToFit]; + CGRect refreshRect = _activityIndicatorView.frame; + refreshRect.origin = CGPointMake((boundSize.width - _activityIndicatorView.frame.size.width) / 2.0, + (boundSize.height - _activityIndicatorView.frame.size.height) / 2.0); + _activityIndicatorView.frame = refreshRect; } #pragma mark - helper methods - (void)refreshFeed { + [_activityIndicatorView startAnimating]; + // small first batch [_photoFeed refreshFeedWithCompletionBlock:^(NSArray *newPhotos){ + + [_activityIndicatorView stopAnimating]; + [self insertNewRowsInTableView:newPhotos]; [self requestCommentsForPhotos:newPhotos]; diff --git a/examples/ASDKgram/Sample/PhotoTableViewCell.m b/examples/ASDKgram/Sample/PhotoTableViewCell.m index c5c86c23..a96883df 100644 --- a/examples/ASDKgram/Sample/PhotoTableViewCell.m +++ b/examples/ASDKgram/Sample/PhotoTableViewCell.m @@ -437,11 +437,9 @@ rect.size = [_photoDescriptionLabel sizeThatFits:CGSizeMake(availableWidth, CGFLOAT_MAX)]; _photoDescriptionLabel.frame = rect; - [[PINRemoteImageManager sharedImageManager] downloadImageWithURL:photo.URL - options:PINRemoteImageManagerDownloadOptionsSkipDecode - completion:^(PINRemoteImageManagerResult * _Nonnull result) { - _photoImageView.image = result.image; - }]; + [UIImage downloadImageForURL:photo.URL completion:^(UIImage *image) { + _photoImageView.image = image; + }]; [self downloadAndProcessUserAvatarForPhoto:photo]; [self loadCommentsForPhoto:photo]; @@ -467,15 +465,10 @@ - (void)downloadAndProcessUserAvatarForPhoto:(PhotoModel *)photo { - [[PINRemoteImageManager sharedImageManager] downloadImageWithURL:_photoModel.ownerUserProfile.userPicURL - options:PINRemoteImageManagerDownloadOptionsSkipDecode - processorKey:@"custom" - processor:^UIImage * _Nullable(PINRemoteImageManagerResult * _Nonnull result, NSUInteger * _Nonnull cost) { - CGSize profileImageSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); - return [result.image makeCircularImageWithSize:profileImageSize]; - } completion:^(PINRemoteImageManagerResult * _Nonnull result) { - _userAvatarImageView.image = result.image; - }]; + [UIImage downloadImageForURL:photo.URL completion:^(UIImage *image) { + CGSize profileImageSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); + _userAvatarImageView.image = [image makeCircularImageWithSize:profileImageSize]; + }]; } - (void)reverseGeocodeLocationForPhoto:(PhotoModel *)photo diff --git a/examples/ASDKgram/Sample/Utilities.h b/examples/ASDKgram/Sample/Utilities.h index cd05b36d..ce0c589c 100644 --- a/examples/ASDKgram/Sample/Utilities.h +++ b/examples/ASDKgram/Sample/Utilities.h @@ -16,6 +16,7 @@ @interface UIImage (Additions) + (UIImage *)followingButtonStretchableImageForCornerRadius:(CGFloat)cornerRadius following:(BOOL)followingEnabled; ++ (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *))block; - (UIImage *)makeCircularImageWithSize:(CGSize)size; diff --git a/examples/ASDKgram/Sample/Utilities.m b/examples/ASDKgram/Sample/Utilities.m index 93574aa1..06de1c1e 100644 --- a/examples/ASDKgram/Sample/Utilities.m +++ b/examples/ASDKgram/Sample/Utilities.m @@ -60,6 +60,40 @@ return followingBtnImageStretchable; } ++ (void)downloadImageForURL:(NSURL *)url completion:(void (^)(UIImage *))block +{ + static NSCache *simpleImageCache = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + simpleImageCache = [[NSCache alloc] init]; + simpleImageCache.countLimit = 10; + }); + + if (!block) { + return; + } + + // check if image is cached + UIImage *image = [simpleImageCache objectForKey:url]; + if (image) { + dispatch_async(dispatch_get_main_queue(), ^{ + block(image); + }); + } else { + // else download image + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (data) { + UIImage *image = [UIImage imageWithData:data]; + dispatch_async(dispatch_get_main_queue(), ^{ + block(image); + }); + } + }]; + [task resume]; + } +} + - (UIImage *)makeCircularImageWithSize:(CGSize)size { // make a CGRect with the image's size