Ali Abdul Jabbar
Ali Abdul Jabbar

Reputation: 3

Expanding Cell Transition

I'm following https://github.com/RabbitMC/inbox-replica to make Objective-C version of inbox replica transition but I'm stuck at the code where I cannot make the Objective-C code.

Here's the Swift code:

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let duration = transitionDuration(transitionContext)
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let containerView = transitionContext.containerView()


    var foregroundViewController = toViewController
    var backgroundViewController = fromViewController

    if type == .Dismissing {
        foregroundViewController = fromViewController
        backgroundViewController = toViewController
    }

    // get target view
    var targetViewController = backgroundViewController
    if let navController = targetViewController as? UINavigationController {
        targetViewController = navController.topViewController!
    }

    let targetViewMaybe = (targetViewController as? ExpandingTransitionPresentingViewController)?.expandingTransitionTargetViewForTransition(self)

And here's my Objective-C code:

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *containerView = [transitionContext containerView];

    UIViewController *foregroundViewController = toViewController;
    UIViewController *backgroundViewController = fromViewController;

    if (type == Dismissing) {
        foregroundViewController = fromViewController;
        backgroundViewController = toViewController;
    }

    //get the target view
    UIViewController *targetViewController = backgroundViewController;
    if ([targetViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController *navController = (UINavigationController *)targetViewController;
        targetViewController = navController.topViewController;
    }

    UIView *targetViewMaybe = ([targetViewController conformsToProtocol:@protocol(ExpandingTransitionPresentingViewController)])?[targetViewController expandingTransitionTargetViewForTransition:self]:assert(targetViewMaybe != nil);

Now the problem comes at the point where I had to call protocol method on targetViewController which is a UIViewController but compiler prompts me with the error:

UIViewController does not have visible interface that declares the selector 'expandingTransitionTargetViewForTransition'

Upvotes: 0

Views: 254

Answers (1)

rmaddy
rmaddy

Reputation: 318804

The cause of the problem is that targetViewController is of type UIViewController. But you attempt to call a method from some protocol. The solution is to cast the pointer to the appropriate type after checking it actually conforms to the protocol.

Do yourself a favor and avoid long, hard to read and impossible to debug lines like the last one:

UIView *targetViewMaybe = ([targetViewController conformsToProtocol:@protocol(ExpandingTransitionPresentingViewController)])?[targetViewController expandingTransitionTargetViewForTransition:self]:assert(targetViewMaybe != nil);

Split it into something manageable. The following fixes the issue and makes the code much easier to read and debug:

if ([targetViewController conformsToProtocol:@protocol(ExpandingTransitionPresentingViewController)]) {
    id<ExpandingTransitionPresentingViewController> controller = (id<ExpandingTransitionPresentingViewController>)targetViewController;
    UIView *targetView = [controller expandingTransitionTargetViewForTransition:self];
    // Do something with targetView
} else {
    // Handle as needed
}

Upvotes: 1

Related Questions