Merge branch 'bugfix/delegate_decoding' into 'develop'

Bugfix/delegate decoding

See merge request BPHV_MIPS/mvm_core!115
This commit is contained in:
Pfeil, Scott Robert 2020-10-09 15:48:30 -04:00
commit c44ce8e068
5 changed files with 63 additions and 9 deletions

View File

@ -16,8 +16,12 @@ extension JSONDecoder: AnyDecoder {}
extension PropertyListDecoder: AnyDecoder {}
extension Data {
public func decode<T: Decodable>(using decoder: AnyDecoder = JSONDecoder()) throws -> T {
return try decoder.decode(T.self, from: self)
public func decode<T: Decodable>(using decoder: AnyDecoder = JSONDecoder(), delegateObject: DelegateObject? = nil) throws -> T {
if let decoder = decoder as? JSONDecoder {
return try decoder.decode(T.self, from: self, delegateObject: delegateObject)
} else {
return try decoder.decode(T.self, from: self)
}
}
}
@ -35,10 +39,10 @@ extension KeyedDecodingContainerProtocol {
}
extension Decodable {
public static func decode(jsonDict: [String: Any]) throws -> Self {
public static func decode(jsonDict: [String: Any], delegateObject: DelegateObject? = nil) throws -> Self {
let jsonData = try JSONSerialization.data(withJSONObject: jsonDict)
do {
return try jsonData.decode()
return try jsonData.decode(delegateObject: delegateObject)
} catch {
throw JSONError.other(error: error)
}
@ -73,6 +77,14 @@ public extension JSONDecoder {
}
userInfo.updateValue(delegateObject, forKey: key)
}
/// Decodes a top-level value of the given type from the given JSON representation, and adds the delegate object if provided.
func decode<T>(_ type: T.Type, from data: Data, delegateObject: DelegateObject?) throws -> T where T : Decodable {
if let delegateObject = delegateObject {
try add(delegateObject: delegateObject)
}
return try decode(T.self, from: data)
}
}
public extension Decoder {

View File

@ -116,6 +116,9 @@
// Use this to pop to the root of the stack. If no navigation controller is provided, will use the main one in app delegate.
- (void)popToRootAnimated:(BOOL)animated navigationController:(nullable UINavigationController *)navigationController delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
/// Returns the view controllers of the navigation controller. Takes into account navigation controller animation states.
- (nullable NSArray<UIViewController *> *)getViewControllersForNavigationController:(nullable UINavigationController *)navigationController;
#pragma mark - Presentation Simple
// Use this to present.

View File

@ -263,6 +263,27 @@
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (nullable NSArray<UIViewController *> *)getViewControllersForNavigationController:(nullable UINavigationController *)navigationController {
// Check if we are currently animating.
NSInteger index = [self.navigationQueue.operations indexOfObjectPassingTest:^BOOL(__kindof MVMCoreNavigationOperation * _Nonnull operation, NSUInteger idx, BOOL * _Nonnull stop) {
if (operation.isExecuting) {
*stop = YES;
return YES;
} else {
return NO;
}
}];
if (index != NSNotFound) {
MVMCoreNavigationOperation *operation = [self.navigationQueue.operations objectAtIndex:index];
if (operation.navigationObject.navigationController == navigationController && operation.futureViewControllers) {
// Return the future state if animating.
return operation.futureViewControllers;
}
}
return navigationController.viewControllers;
}
#pragma mark - Presentation Simple
- (void)presentViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated {

View File

@ -15,8 +15,12 @@
@interface MVMCoreNavigationOperation : MVMCoreOperation <UINavigationControllerDelegate>
@property (nonnull, strong, nonatomic) MVMCoreNavigationObject *navigationObject;
@property (nullable, weak, nonatomic) NSObject<MVMCorePresentationDelegateProtocol> *delegate;
/// Used to keep track of future view controller state because .viewControllers is not reliable during animation.
@property (nullable, strong, nonatomic) NSArray <UIViewController *>*futureViewControllers;
- (nullable instancetype)initWithNavigationObject:(nonnull MVMCoreNavigationObject *)navigationObject;
@end

View File

@ -17,7 +17,6 @@
@interface MVMCoreNavigationOperation ()
@property (strong, nonatomic) MVMCoreNavigationObject *navigationObject;
@property (strong, nonatomic) id animatedTransitioning;
@end
@ -95,7 +94,7 @@
switch (self.navigationObject.navigationType) {
case NavigationTypePush:
{
[self.navigationObject.navigationController pushViewController:self.navigationObject.viewController animated:self.navigationObject.animated];
[self pushViewController];
}
break;
case NavigationTypeSet:
@ -114,7 +113,7 @@
} else {
// Just push
[self.navigationObject.navigationController pushViewController:self.navigationObject.viewController animated:self.navigationObject.animated];
[self pushViewController];
}
}
break;
@ -129,13 +128,15 @@
} else {
// Just push
[self.navigationObject.navigationController pushViewController:self.navigationObject.viewController animated:self.navigationObject.animated];
[self pushViewController];
}
}
break;
case NavigationTypePop:
{
if (self.navigationObject.navigationController.viewControllers.count > 1) {
// Although the post animation state is currently fine with pop, store anyway as a precaution
self.futureViewControllers = [self.navigationObject.navigationController.viewControllers subarrayWithRange:NSMakeRange(0, self.navigationObject.navigationController.viewControllers.count - 1)];
[self.navigationObject.navigationController popViewControllerAnimated:self.navigationObject.animated];
} else {
[self markAsFinished];
@ -179,6 +180,10 @@
}
if (self.navigationObject.viewController && (self.navigationObject.viewController != self.navigationObject.navigationController.topViewController)) {
// Store post animation state.
NSInteger index = [[self.navigationObject.navigationController viewControllers] indexOfObject:self.navigationObject.viewController];
self.futureViewControllers = [self.navigationObject.navigationController.viewControllers subarrayWithRange:NSMakeRange(0, index + 1)];
[self.navigationObject.navigationController popToViewController:self.navigationObject.viewController animated:self.navigationObject.animated];
} else {
[self markAsFinished];
@ -188,6 +193,9 @@
case NavigationTypePopToRoot:
{
if (self.navigationObject.navigationController.viewControllers.count > 1) {
// Store post animation state.
self.futureViewControllers = @[self.navigationObject.navigationController.viewControllers.firstObject];
[self.navigationObject.navigationController popToRootViewControllerAnimated:self.navigationObject.animated];
} else {
[self markAsFinished];
@ -202,8 +210,14 @@
}]];
}
- (void)pushViewController {
// Although the post animation state is currently fine with push, store anyway as a precaution
self.futureViewControllers = [self.navigationObject.navigationController.viewControllers arrayByAddingObject:self.navigationObject.viewController];
[self.navigationObject.navigationController pushViewController:self.navigationObject.viewController animated:self.navigationObject.animated];
}
- (void)setViewControllers:(NSArray *)viewControllers {
self.futureViewControllers = viewControllers;
if (![self.navigationObject.navigationController.viewControllers isEqualToArray:viewControllers]) {
[self.navigationObject.navigationController setViewControllers:viewControllers animated:self.navigationObject.animated];
} else {