diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index 6845002..f1d48bc 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -123,6 +123,8 @@ AFBB96ED1FBA4A260008D868 /* MFHardCodedServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96EA1FBA4A260008D868 /* MFHardCodedServerResponse.m */; }; AFC5FA161FFC2E2A00C244CF /* MVMCoreGlobalTopAlertDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFC5FA141FFC2E2A00C244CF /* MVMCoreGlobalTopAlertDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; AFC5FA1D1FFC39C700C244CF /* MVMCoreTopAlertViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFC5FA1C1FFC39C700C244CF /* MVMCoreTopAlertViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AFEA17A8209B6A1C00BC6740 /* MVMCoreBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AFEA17A6209B6A1C00BC6740 /* MVMCoreBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AFEA17A9209B6A1C00BC6740 /* MVMCoreBlockOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AFEA17A7209B6A1C00BC6740 /* MVMCoreBlockOperation.m */; }; AFED77A11FCCA29400BAE689 /* MVMCoreViewControllerNibMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AFED77991FCCA29300BAE689 /* MVMCoreViewControllerNibMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; AFED77A21FCCA29400BAE689 /* MVMCoreViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AFED779A1FCCA29300BAE689 /* MVMCoreViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; AFED77A31FCCA29400BAE689 /* MVMCoreViewControllerNibMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AFED779B1FCCA29300BAE689 /* MVMCoreViewControllerNibMappingObject.m */; }; @@ -251,6 +253,8 @@ AFBB96EA1FBA4A260008D868 /* MFHardCodedServerResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFHardCodedServerResponse.m; sourceTree = ""; }; AFC5FA141FFC2E2A00C244CF /* MVMCoreGlobalTopAlertDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreGlobalTopAlertDelegateProtocol.h; sourceTree = ""; }; AFC5FA1C1FFC39C700C244CF /* MVMCoreTopAlertViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreTopAlertViewProtocol.h; sourceTree = ""; }; + AFEA17A6209B6A1C00BC6740 /* MVMCoreBlockOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreBlockOperation.h; sourceTree = ""; }; + AFEA17A7209B6A1C00BC6740 /* MVMCoreBlockOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreBlockOperation.m; sourceTree = ""; }; AFED77991FCCA29300BAE689 /* MVMCoreViewControllerNibMappingObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewControllerNibMappingObject.h; sourceTree = ""; }; AFED779A1FCCA29300BAE689 /* MVMCoreViewControllerMappingObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewControllerMappingObject.h; sourceTree = ""; }; AFED779B1FCCA29300BAE689 /* MVMCoreViewControllerNibMappingObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreViewControllerNibMappingObject.m; sourceTree = ""; }; @@ -327,6 +331,8 @@ 881D268F1FCC9D180079C521 /* MVMCoreErrorObject.m */, 881D26921FCC9D180079C521 /* MVMCoreOperation.h */, 881D26901FCC9D180079C521 /* MVMCoreOperation.m */, + AFEA17A6209B6A1C00BC6740 /* MVMCoreBlockOperation.h */, + AFEA17A7209B6A1C00BC6740 /* MVMCoreBlockOperation.m */, AFBB96E71FBA4A260008D868 /* HardCodedServerResponse */, AFBB96AB1FBA3B590008D868 /* Helpers */, ); @@ -647,6 +653,7 @@ AFBB968B1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.h in Headers */, AF43A70B1FC4F415008E9347 /* MVMCoreCache.h in Headers */, AFBB965C1FBA3A570008D868 /* MFFreebeeHandler.h in Headers */, + AFEA17A8209B6A1C00BC6740 /* MVMCoreBlockOperation.h in Headers */, AF43A5831FBB66DE008E9347 /* MVMCoreConstants.h in Headers */, AFBB969A1FBA3A9A0008D868 /* MVMCoreAlertDelegateProtocol.h in Headers */, AFED77A81FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.h in Headers */, @@ -795,6 +802,7 @@ AF43A7071FC4D7A2008E9347 /* MVMCoreObject.m in Sources */, AFBB96B11FBA3B590008D868 /* MVMCoreDispatchUtility.m in Sources */, AFBB965B1FBA3A570008D868 /* FreeBeeUrlObject.m in Sources */, + AFEA17A9209B6A1C00BC6740 /* MVMCoreBlockOperation.m in Sources */, AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */, AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */, AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */, diff --git a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m index a4cbfb8..222a56e 100644 --- a/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m +++ b/MVMCore/MVMCore/AlertHandling/MVMCoreTopAlertOperation.m @@ -16,22 +16,16 @@ __block BOOL _paused; __block BOOL _displayed; __block BOOL _animating; - __block NSTimer *_dismissTimer; } @property (readwrite, getter=isPaused) BOOL paused; - @property (readwrite, getter=isDisplayed) BOOL displayed; - @property (readwrite, getter=isAnimating) BOOL animating; -@property (strong, nonatomic) NSTimer *dismissTimer; - // For thread safety @property (strong, nonatomic) dispatch_queue_t pausedQueue; @property (strong, nonatomic) dispatch_queue_t displayedQueue; @property (strong, nonatomic) dispatch_queue_t animatingQueue; -@property (strong, nonatomic) dispatch_queue_t timerQueue; @end @@ -44,7 +38,6 @@ self.pausedQueue = dispatch_queue_create("paused", DISPATCH_QUEUE_CONCURRENT); self.displayedQueue = dispatch_queue_create("displayed", DISPATCH_QUEUE_CONCURRENT); self.animatingQueue = dispatch_queue_create("animating", DISPATCH_QUEUE_CONCURRENT); - self.timerQueue = dispatch_queue_create("timer", DISPATCH_QUEUE_CONCURRENT); } return self; } @@ -102,20 +95,6 @@ }); } -- (NSTimer *)dismissTimer { - __block NSTimer *timer; - dispatch_sync(self.timerQueue, ^{ - timer = _dismissTimer; - }); - return timer; -} - -- (void)setDismissTimer:(NSTimer *)dismissTimer { - dispatch_barrier_async(self.timerQueue, ^{ - _dismissTimer = dismissTimer; - }); -} - - (void)main { // Always check for cancellation before launching the task. @@ -156,7 +135,14 @@ } else { dismissTime = TopAlertDismissTime; } - self.dismissTimer = [NSTimer scheduledTimerWithTimeInterval:dismissTime target:self selector:@selector(timerFinished) userInfo:nil repeats:NO]; + + __weak typeof(self) weakSelf = self; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(dismissTime * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (weakSelf.isFinished || [weakSelf checkAndHandleForCancellation]) { + return; + } + [weakSelf dismissAlertView:YES]; + }); } }]; } @@ -166,19 +152,9 @@ } } -- (void)timerFinished { - [self dismissAlertView:YES]; -} - - (void)cancel { [super cancel]; - // Kill the dismiss timer. - if (self.dismissTimer) { - [self.dismissTimer invalidate]; - self.dismissTimer = nil; - } - // Do nothing if animating. if (!self.isAnimating) { @@ -191,9 +167,7 @@ } - (void)dismissAlertView:(BOOL)andFinish { - - self.dismissTimer = nil; - + if (self.isDisplayed && !self.isAnimating) { // Dismisses. diff --git a/MVMCore/MVMCore/MVMCore.h b/MVMCore/MVMCore/MVMCore.h index 923a1bc..e3402cf 100644 --- a/MVMCore/MVMCore/MVMCore.h +++ b/MVMCore/MVMCore/MVMCore.h @@ -35,6 +35,7 @@ FOUNDATION_EXPORT const unsigned char MVMCoreVersionString[]; #import #import #import +#import // Mapping #import diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m index 45e9603..68f2f00 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m @@ -459,11 +459,12 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *imageData = nil; if (pathOrName.length > 0) { - if(pathOrName.length >=4 && [[pathOrName substringToIndex:4] isEqualToString:@"http"]) { + if (pathOrName.length >=4 && [[pathOrName substringToIndex:4] isEqualToString:@"http"]) { // Gets the full path NSURL *s7URL = [self handleS7Path:pathOrName useWidth:useWidth widthForS7:widthForS7 useHeight:useHeight heightForS7:heightForS7 format:format finalRect:CGRectNull flipImage:NO]; if (s7URL) { [self downloadImage:s7URL isGif:YES fallbackImageName:fallbackImageName completionHandler:completionHandler]; + return; } } else { // Try Local. Check in memory cache @@ -514,16 +515,15 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; } //download image -- (void)downloadImage:(NSURL *)s7URL isGif:(BOOL)isGif fallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler{ +- (void)downloadImage:(NSURL *)s7URL isGif:(BOOL)isGif fallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler { + NSURLCache *sharedCache = [NSURLCache sharedURLCache]; - NSURLSessionConfiguration *configure = [NSURLSessionConfiguration defaultSessionConfiguration]; - configure.URLCache = sharedCache; - NSURLSession *session = [NSURLSession sessionWithConfiguration:configure]; + NSURLSession *session = [MVMCoreSessionObject sharedGlobal].session; NSURLRequest *request = [NSURLRequest requestWithURL:s7URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:ImageTimeOut]; //use Freebee to download image first, then store image to cache NSCachedURLResponse *cachedResponse = [sharedCache cachedResponseForRequest:request]; if (!cachedResponse.data) { - cachedResponse = [[MFFreebeeHandler sharedHandler] freebee_dataWithImageURL:s7URL]; + cachedResponse = [[MFFreebeeHandler sharedHandler] freebee_dataWithContentsOfURL:s7URL]; if (cachedResponse) { //system stores cache based datatask and check cache based on response, //need to manually store cache for response @@ -533,10 +533,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; //call nsurlsession again, if image is cached by Freebee, the second session will grab image data from cache instead of making another server call NSURLSessionDownloadTask *downloadImageTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSData *data = [NSData dataWithContentsOfURL:location]; - NSCachedURLResponse *cachedreponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data]; + NSCachedURLResponse *cachedReponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data]; //system stores cache based datatask and check cache based on response, //need to manually store cache for response - [sharedCache storeCachedResponse:cachedreponse forRequest:request]; + [sharedCache storeCachedResponse:cachedReponse forRequest:request]; if (isGif) { [self checkImage:nil imageData:data fallbackImage:fallbackImageName completionHandler:completionHandler]; } else { @@ -544,12 +544,11 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; //check fallback image [self checkImage:image imageData:nil fallbackImage:fallbackImageName completionHandler:completionHandler]; } - }]; [downloadImageTask resume]; } -//check whehter get image or imageData, if not, return fallbackImage +//check whether get image or imageData, if not, return fallbackImage - (void)checkImage:(UIImage *)img imageData:(NSData *)imageData fallbackImage:(NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler{ // Set to the fallback image. BOOL isFallBackImage = NO; diff --git a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.h b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.h index a3e5bcd..32789d0 100644 --- a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.h +++ b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.h @@ -10,6 +10,7 @@ #import #import +@class MVMCoreOperation; @class MVMCoreNavigationObject; @class MVMCoreLoadObject; @@ -67,6 +68,9 @@ // Use this to pop to the root of the stack. - (void)popToRootAnimated:(BOOL)animated; +// Adds the navigation operation to the queue. +- (void)addNavigationOperation:(nonnull MVMCoreOperation *)operation; + // Removes all queued up items. - (void)cancelNavigation; diff --git a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.m b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.m index 727d97b..b6aa0aa 100644 --- a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.m +++ b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationHandler.m @@ -16,6 +16,7 @@ #import "MVMCoreRequestParameters.h" #import "MVMCoreErrorConstants.h" #import "MVMCoreLoggingHandler.h" +#import "MVMCoreLoadingOverlayHandler.h" @interface MVMCoreNavigationHandler () @@ -90,6 +91,10 @@ - (void)startNavigationWithNavigationObject:(MVMCoreNavigationObject *)navigationObject delegate:(nullable NSObject*)delegate completionHandler:(nullable void (^)(void))completionBlock { + // In case it takes some time to happen. + [[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] startLoading]; + navigationObject.stopLoadingOverlay = YES; + MVMCoreNavigationOperation *navigationOperation = [[MVMCoreNavigationOperation alloc] initWithNavigationObject:navigationObject]; navigationOperation.delegate = delegate; navigationOperation.completionBlock = completionBlock; @@ -165,7 +170,12 @@ - (void)popToRootAnimated:(BOOL)animated { MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopToRoot]; - [self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];} + [self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL]; +} + +- (void)addNavigationOperation:(nonnull MVMCoreOperation *)operation { + [self.navigationQueue addOperation:operation]; +} - (void)cancelNavigation { [self.navigationQueue cancelAllOperations]; diff --git a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationObject.h b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationObject.h index 71e7c72..527110f 100644 --- a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationObject.h +++ b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationObject.h @@ -20,6 +20,7 @@ @property (nonatomic) NavigationType navigationType; @property (nonatomic) BOOL animated; @property (nonatomic) BOOL tryToReplaceFirst; +@property (nonatomic) BOOL stopLoadingOverlay; - (nullable instancetype)initWithViewController:(nullable UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController viewControllers:(nullable NSArray *)viewControllers animated:(BOOL)animated tryToReplaceFirst:(BOOL)tryToReplaceFirst navigationType:(NavigationType)navigationType; diff --git a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m index 45d8647..a1fda67 100644 --- a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m +++ b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m @@ -11,6 +11,7 @@ #import "MVMCoreViewManagerProtocol.h" #import "MVMCoreViewControllerProtocol.h" #import "MVMCoreLoggingHandler.h" +#import "MVMCoreLoadingOverlayHandler.h" @interface MVMCoreNavigationOperation () @@ -133,6 +134,8 @@ { if (self.navigationObject.navigationController.viewControllers.count > 1) { [self.navigationObject.navigationController popViewControllerAnimated:self.navigationObject.animated]; + } else { + [self markAsFinished]; } } break; @@ -181,7 +184,11 @@ break; case NavigationTypePopToRoot: { - [self.navigationObject.navigationController popToRootViewControllerAnimated:self.navigationObject.animated]; + if (self.navigationObject.navigationController.viewControllers.count > 1) { + [self.navigationObject.navigationController popToRootViewControllerAnimated:self.navigationObject.animated]; + } else { + [self markAsFinished]; + } } break; default: @@ -205,11 +212,19 @@ - (void)markAsFinished { self.navigationObject.navigationController.delegate = nil; + if (self.navigationObject.stopLoadingOverlay) { + [[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:YES]; + self.navigationObject.stopLoadingOverlay = NO; + } [super markAsFinished]; } - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { - + if (self.navigationObject.stopLoadingOverlay) { + [[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:YES]; + self.navigationObject.stopLoadingOverlay = NO; + } + if (self.delegate && [self.delegate respondsToSelector:@selector(navigationController:willDisplayViewController:)]) { [self.delegate navigationController:navigationController willDisplayViewController:viewController]; } @@ -221,7 +236,6 @@ [self.delegate navigationController:navigationController displayedViewController:viewController]; } [self markAsFinished]; - } - (nullable id )navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { diff --git a/MVMCore/MVMCore/Utility/MVMCoreBlockOperation.h b/MVMCore/MVMCore/Utility/MVMCoreBlockOperation.h new file mode 100644 index 0000000..5096a20 --- /dev/null +++ b/MVMCore/MVMCore/Utility/MVMCoreBlockOperation.h @@ -0,0 +1,16 @@ +// +// MVMCoreBlockOperation.h +// MVMCore +// +// Created by Pfeil, Scott Robert on 5/3/18. +// Copyright © 2018 myverizon. All rights reserved. +// + +#import + +@interface MVMCoreBlockOperation : MVMCoreOperation + +// Start this operation with the block. This block needs to call mark as finished when finished. ++ (nullable instancetype)blockOperationWithBlock:(nonnull void (^)(MVMCoreBlockOperation * _Nonnull operation))block; + +@end diff --git a/MVMCore/MVMCore/Utility/MVMCoreBlockOperation.m b/MVMCore/MVMCore/Utility/MVMCoreBlockOperation.m new file mode 100644 index 0000000..f0fc8ce --- /dev/null +++ b/MVMCore/MVMCore/Utility/MVMCoreBlockOperation.m @@ -0,0 +1,36 @@ +// +// MVMCoreBlockOperation.m +// MVMCore +// +// Created by Pfeil, Scott Robert on 5/3/18. +// Copyright © 2018 myverizon. All rights reserved. +// + +#import "MVMCoreBlockOperation.h" + +@interface MVMCoreBlockOperation () + +@property (nonatomic, copy) void (^block)(MVMCoreBlockOperation * _Nonnull operation); + +@end + +@implementation MVMCoreBlockOperation + ++ (nullable instancetype)blockOperationWithBlock:(nonnull void (^)(MVMCoreBlockOperation * _Nonnull operation))block { + MVMCoreBlockOperation *operation = [[MVMCoreBlockOperation alloc] init]; + operation.block = block; + return operation; +} + +- (void)main { + + // Always check for cancellation before launching the task. + if ([self checkAndHandleForCancellation]) { + return; + } + + __weak typeof(self) weakSelf = self; + self.block(weakSelf); +} + +@end