ট্রানজিশনবিউথ ভিউ-র অভ্যন্তরে রুটভিউ কনট্রোলার পরিবর্তন করার সময় দেখানো হচ্ছে


97

একটি মেমরি ফুটো তদন্ত করার সময় আমি setRootViewController:একটি স্থানান্তর অ্যানিমেশন ব্লকের ভিতরে কল করার কৌশল সম্পর্কিত একটি সমস্যা আবিষ্কার করেছি :

[UIView transitionWithView:self.window
                  duration:0.5
                   options:UIViewAnimationOptionTransitionFlipFromLeft
                animations:^{ self.window.rootViewController = newController; }
                completion:nil];

যদি পুরানো ভিউ কন্ট্রোলার (একটিকে প্রতিস্থাপিত করা হচ্ছে) বর্তমানে অন্য ভিউ কন্ট্রোলার উপস্থাপন করছে তবে উপরের কোডটি ভিউ হায়ারার্কি থেকে উপস্থাপিত ভিউটিকে সরিয়ে দেয় না।

অর্থাৎ, ক্রিয়াকলাপের এই ক্রমটি ...

  1. এক্স রুট ভিউ কন্ট্রোলার হয়ে ওঠে
  2. এক্স ওয়াইকে উপস্থাপন করে যাতে ওয়াইয়ের দৃষ্টিভঙ্গি পর্দায় থাকে
  3. transitionWithView:জেডকে নতুন রুট ভিউ কন্ট্রোলার তৈরি করতে ব্যবহার করা হচ্ছে

... ব্যবহারকারীর কাছে ঠিক আছে, তবে ডিবাগ ভিউ হায়ারার্কি সরঞ্জামটি প্রকাশ করবে যে ওয়াইয়ের দৃষ্টিভঙ্গিটি এখনও জেড এর দৃশ্যের পিছনে রয়েছে, এ এর ​​মধ্যে UITransitionView। এটি, উপরের তিনটি ধাপের পরে, ভিউয়ের স্তরক্রমটি হ'ল:

  • ইউআই উইন্ডো
    • ইউআইটি ট্রান্সভিশনভিউ
      • ইউআইভিউ (আপনার দর্শন)
    • ইউআইভিউ (জেড ভিউ)

আমার সন্দেহ হয় এটি একটি সমস্যা কারণ, রূপান্তরের সময় এক্স এর ভিউটি আসলে চিত্রক্রমের অংশ নয়।

আমি যদি এর dismissViewControllerAnimated:NOআগেই এক্সে প্রেরণ করি transitionWithView:তবে ফলাফলের ভিউয়ের স্তরক্রমটি হ'ল:

  • ইউআই উইন্ডো
    • ইউআইভিউ (এক্স ভিউ)
    • ইউআইভিউ (জেড ভিউ)

যদি আমি dismissViewControllerAnimated:এক্সকে (YES বা NO) প্রেরণ করি তবে completion:ব্লকের মধ্যে রূপান্তরটি সম্পাদন করুন , তারপরে দর্শনক্রমক্রমটি সঠিক। দুর্ভাগ্যক্রমে, এটি অ্যানিমেশনটিতে হস্তক্ষেপ করে। যদি বরখাস্ত অ্যানিমেট করা হয়, এটি সময় নষ্ট করে; যদি অ্যানিমেটিং না হয় তবে এটি ভাঙা দেখায়।

আমি অন্য কয়েকটি পদ্ধতির চেষ্টা করছি (উদাহরণস্বরূপ, আমার রুট ভিউ নিয়ন্ত্রক হিসাবে পরিবেশন করার জন্য একটি নতুন ধারক ভিউ কন্ট্রোলার শ্রেণি তৈরি করা) তবে কার্যকর এমন কোনও কিছুই খুঁজে পাইনি। আমি যেতে যেতে এই প্রশ্ন আপডেট করব।

চূড়ান্ত লক্ষ্য হ'ল উপস্থাপিত দৃশ্য থেকে সরাসরি নতুন রুট ভিউ নিয়ন্ত্রকের দিকে রূপান্তর করা এবং বিপথগামী দৃষ্টিভঙ্গি ছাড়াই।


আমার বর্তমানে এই একই সমস্যা রয়েছে
অ্যালেক্স

আমি কেবল একই সমস্যার মুখোমুখি হয়েছি
জামাল জাফর

কোনও ভাগ্য কি এর একটি শালীন সমাধান খুঁজে পাচ্ছেন? এখানে ঠিক একই সমস্যা।
ডেভিড বাইজ

@ ডেভিডবায়েজ আমি রুট পরিবর্তন করার আগে সমস্ত ভিউ কন্ট্রোলারকে আক্রমণাত্মকভাবে বরখাস্ত করার জন্য লিখনের কোডটি ছিন্ন করেছি। যদিও এটি আমার অ্যাপ্লিকেশনটির সাথে খুব নির্দিষ্ট। এটি পোস্ট করার পর থেকে আমি ভাবছিলাম যে অদলবদল করা UIWindowজিনিস হ'ল তবে পরীক্ষার জন্য খুব বেশি সময় পেল না।
বেনজাদো

উত্তর:


119

আমি সম্প্রতি একটি একই সমস্যা ছিল। UITransitionViewসমস্যাটি সমাধান করার জন্য আমাকে উইন্ডো থেকে ম্যানুয়ালি মুছে ফেলতে হয়েছিল, তারপরে এটির অবনমিত হওয়া নিশ্চিত করতে পূর্বের রুট ভিউ নিয়ন্ত্রণকারীকে বরখাস্ত করুন call

সমাধানটি খুব সুন্দর নয় তবে আপনি যদি প্রশ্ন পোস্ট করার পরে আরও ভাল কোনও উপায় না খুঁজে পান তবে এটিই কেবল কাজ করার সন্ধান পেয়েছি! আপনার আসল প্রশ্ন থেকে viewControllerঠিক এই newController

UIViewController *previousRootViewController = self.window.rootViewController;

self.window.rootViewController = viewController;

// Nasty hack to fix http://stackoverflow.com/questions/26763020/leaking-views-when-changing-rootviewcontroller-inside-transitionwithview
// The presenting view controllers view doesn't get removed from the window as its currently transistioning and presenting a view controller
for (UIView *subview in self.window.subviews) {
    if ([subview isKindOfClass:NSClassFromString(@"UITransitionView")]) {
        [subview removeFromSuperview];
    }
}
// Allow the view controller to be deallocated
[previousRootViewController dismissViewControllerAnimated:NO completion:^{
    // Remove the root view in case its still showing
    [previousRootViewController.view removeFromSuperview];
}];

আমি আশা করি এটি আপনার সমস্যাটিও ঠিক করতে সহায়তা করে, এটি গাধাটির মধ্যে একটি পরম ব্যথা!

সুইফট 3.0

(অন্যান্য সুইফ্ট সংস্করণগুলির সম্পাদনার ইতিহাস দেখুন)

Implementationচ্ছিক UIWindowরূপান্তরটি পাস করার অনুমতি দেওয়ার জন্য এক্সটেনশন হিসাবে উত্তম প্রয়োগের জন্য ।

extension UIWindow {

    /// Fix for http://stackoverflow.com/a/27153956/849645
    func set(rootViewController newRootViewController: UIViewController, withTransition transition: CATransition? = nil) {

        let previousViewController = rootViewController

        if let transition = transition {
            // Add the transition
            layer.add(transition, forKey: kCATransition)
        }

        rootViewController = newRootViewController

        // Update status bar appearance using the new view controllers appearance - animate if needed
        if UIView.areAnimationsEnabled {
            UIView.animate(withDuration: CATransaction.animationDuration()) {
                newRootViewController.setNeedsStatusBarAppearanceUpdate()
            }
        } else {
            newRootViewController.setNeedsStatusBarAppearanceUpdate()
        }

        if #available(iOS 13.0, *) {
            // In iOS 13 we don't want to remove the transition view as it'll create a blank screen
        } else {
            // The presenting view controllers view doesn't get removed from the window as its currently transistioning and presenting a view controller
            if let transitionViewClass = NSClassFromString("UITransitionView") {
                for subview in subviews where subview.isKind(of: transitionViewClass) {
                    subview.removeFromSuperview()
                }
            }
        }
        if let previousViewController = previousViewController {
            // Allow the view controller to be deallocated
            previousViewController.dismiss(animated: false) {
                // Remove the root view in case its still showing
                previousViewController.view.removeFromSuperview()
            }
        }
    }
}

ব্যবহার:

window.set(rootViewController: viewController)

বা

let transition = CATransition()
transition.type = kCATransitionFade
window.set(rootViewController: viewController, withTransition: transition)

6
ধন্যবাদ এটা কাজ করেছে. আপনি যদি আরও ভাল পদ্ধতির সন্ধান করেন তবে শেয়ার করুন
জামাল জাফর

8
এটি প্রদর্শিত হবে যে ভিউগুলি উপস্থাপন করেছে এমন রুট ভিউ কন্ট্রোলারের পরিবর্তে (বা কোনও ইউআইওয়াইন্ডো যা এখনও ভিউ কন্ট্রোলারদের উপস্থাপন করেছে তা ডিলোক করার চেষ্টা করছে) এর ফলে মেমোরি ফাঁস হবে। আমার কাছে মনে হচ্ছে একটি ভিউ কন্ট্রোলার উপস্থাপন করা উইন্ডোটির সাথে একটি রক্ষণাবেক্ষণ লুপ তৈরি করে এবং নিয়ন্ত্রণকারীদের বরখাস্ত করার একমাত্র উপায় আমি এটি ভেঙে ফেলি। আমি মনে করি কিছু অভ্যন্তরীণ সমাপ্তি ব্লকের উইন্ডোটির একটি দৃ strong় উল্লেখ রয়েছে।
কার্ল লিন্ডবার্গ 3'15

সুইস ২.০ তে রূপান্তর করার পরে এনএসক্লাসফ্রমস্ট্রিংয়ের ("ইউআইটিআরসিশনভিউ") এর সাথে একটি সমস্যা হয়েছিল
ইউজেন ব্রাজিনিটস

আইওএস 9 তে এখনও ঘটছে :( এছাড়াও আমি সুইফট 2.0
সমৃদ্ধ

4
@ ব্যবহারকারী023 আমি কোনও সমস্যা ছাড়াই অ্যাপ স্টোরটিতে জমা দেওয়া 2 বা 3 টি অ্যাপ্লিকেশনে এই সঠিক সমাধানটি ব্যবহার করেছি! আমি অনুমান করি যে আপনি কেবল স্ট্রিংয়ের বিরুদ্ধে ক্লাসের ধরণটি ভালভাবে পরীক্ষা করছেন (এটি কোনও স্ট্রিং হতে পারে)। UITransitionViewআপনার অ্যাপ্লিকেশনটিতে কোনও প্রত্যাখ্যানের কারণ কী হতে পারে তা সেই অ্যাপ্লিকেশনটির প্রতীকগুলির অংশ হিসাবে উঠেছে যা আমার মনে হয় অ্যাপ স্টোর যাচাই করতে ব্যবহার করে।
সমৃদ্ধ

5

আমি এই সমস্যার মুখোমুখি হয়েছি এবং এটি আমাকে পুরো দিনটির জন্য বিরক্ত করেছিল। আমি রিচ এর ইজেক্ট-সি সমাধানটি চেষ্টা করেছি এবং এটির পরে যখন আমি অন্য ভিউ কনট্রোলার উপস্থাপন করতে চাই তখন আমাকে একটি ফাঁকা ইউআইটি ট্রান্সভিশনভিউ দিয়ে অবরুদ্ধ করা হবে।

অবশেষে, আমি এইভাবে আবিষ্কার করেছি এবং এটি আমার পক্ষে কাজ করেছে।

- (void)setRootViewController:(UIViewController *)rootViewController {
    // dismiss presented view controllers before switch rootViewController to avoid messed up view hierarchy, or even crash
    UIViewController *presentedViewController = [self findPresentedViewControllerStartingFrom:self.window.rootViewController];
    [self dismissPresentedViewController:presentedViewController completionBlock:^{
        [self.window setRootViewController:rootViewController];
    }];
}

- (void)dismissPresentedViewController:(UIViewController *)vc completionBlock:(void(^)())completionBlock {
    // if vc is presented by other view controller, dismiss it.
    if ([vc presentingViewController]) {
        __block UIViewController* nextVC = vc.presentingViewController;
        [vc dismissViewControllerAnimated:NO completion:^ {
            // if the view controller which is presenting vc is also presented by other view controller, dismiss it
            if ([nextVC presentingViewController]) {
                [self dismissPresentedViewController:nextVC completionBlock:completionBlock];
            } else {
                if (completionBlock != nil) {
                    completionBlock();
                }
            }
        }];
    } else {
        if (completionBlock != nil) {
            completionBlock();
        }
    }
}

+ (UIViewController *)findPresentedViewControllerStartingFrom:(UIViewController *)start {
    if ([start isKindOfClass:[UINavigationController class]]) {
        return [self findPresentedViewControllerStartingFrom:[(UINavigationController *)start topViewController]];
    }

    if ([start isKindOfClass:[UITabBarController class]]) {
        return [self findPresentedViewControllerStartingFrom:[(UITabBarController *)start selectedViewController]];
    }

    if (start.presentedViewController == nil || start.presentedViewController.isBeingDismissed) {
        return start;
    }

    return [self findPresentedViewControllerStartingFrom:start.presentedViewController];
}

ঠিক আছে, আপনি [self setRootViewController:newViewController];যখন রুট ভিউ কন্ট্রোলার পরিবর্তন করতে চান তখন আপনাকে কেবল কল করতে হবে ।


ভালভাবে কাজ করে, তবে রুট ভিউ কন্ট্রোলারটি স্যুইচ করার আগে উপস্থিত ভিউ কন্ট্রোলারের একটি বিরক্তিকর ফ্ল্যাশ রয়েছে the dismissViewControllerAnimated:অ্যানিমেশনটির চেয়ে অ্যানিমেশনটি সম্ভবত কিছুটা ভাল। এড়াতে দেয় প্রেতাত্মা UITransitionViewযদিও দৃশ্য শ্রেণীবিন্যাসে গুলি।
pkamb

5

আমি একটি সাধারণ জিনিসটি চেষ্টা করি যা আইওএস 9.3 এ আমার জন্য কাজ করে: কেবলমাত্র পুরানো ভিউ কনট্রোলারের ভিউটি dismissViewControllerAnimatedসম্পূর্ণ হওয়ার সময় এর স্তরক্রম থেকে সরান ।

বেনজাদোর ব্যাখ্যা অনুসারে এক্স, ওয়াই এবং জেড ভিউতে কাজ করা যাক :

অর্থাৎ, ক্রিয়াকলাপের এই ক্রমটি ...

  1. এক্স রুট ভিউ কন্ট্রোলার হয়ে ওঠে
  2. এক্স ওয়াইকে উপস্থাপন করে যাতে ওয়াইয়ের দৃষ্টিভঙ্গি পর্দায় থাকে
  3. ট্রানজিশনভিথভিউ ব্যবহার করে: জেডকে নতুন রুট ভিউ কন্ট্রোলার তৈরি করতে

যা দেয়:

////
//Start point :

let X = UIViewController ()
let Y = UIViewController ()
let Z = UIViewController ()

window.rootViewController = X
X.presentViewController (Y, animated:true, completion: nil)

////
//Transition :

UIView.transitionWithView(window,
                          duration: 0.25,
                          options: UIViewAnimationOptions.TransitionFlipFromRight,
                          animations: { () -> Void in
                                X.dismissViewControllerAnimated(false, completion: {
                                        X.view.removeFromSuperview()
                                    })
                                window.rootViewController = Z
                           },
                           completion: nil)

আমার ক্ষেত্রে, এক্স এবং ওয়াই ভালভাবে ডিলোক এবং তাদের দৃষ্টিভঙ্গি হায়ারার্কিতে আর নেই!


0

অনুরূপ সমস্যা ছিল। আমার ক্ষেত্রে আমার কাছে একটি ভিউকন্ট্রোলার শ্রেণিবিন্যাস ছিল এবং শিশু দেখার নিয়ন্ত্রকের একজনের কাছে উপস্থাপিত ভিউ কন্ট্রোলার ছিল। যখন আমি পরিবর্তন করেছি তখন উইন্ডোজ রুট ভিউ কন্ট্রোলার কোনও কারণে, উপস্থাপিত ভিউ কন্ট্রোলারটি এখনও স্মৃতিতে ছিল। সুতরাং, আমি উইন্ডোজ রুট ভিউ নিয়ন্ত্রণকারী পরিবর্তন করার আগে সমাধানটি সমস্ত দর্শনীয় নিয়ামককে বরখাস্ত করা হয়েছিল।


-2

এই কোডটি ব্যবহার করার সময় আমি এই সমস্যাটিতে এসেছি:

if var tc = self.transitionCoordinator() {

    var animation = tc.animateAlongsideTransitionInView((self.navigationController as VDLNavigationController).filtersVCContainerView, animation: { (context:UIViewControllerTransitionCoordinatorContext!) -> Void in
        var toVC = tc.viewControllerForKey(UITransitionContextToViewControllerKey) as BaseViewController
        (self.navigationController as VDLNavigationController).setFilterBarHiddenWithInteractivity(!toVC.filterable(), animated: true, interactive: true)
    }, completion: { (context:UIViewControllerTransitionCoordinatorContext!) -> Void in

    })
}

এই কোডটি অক্ষম করা হচ্ছে, সমস্যাটি ঠিক করা হয়েছে। যখন ফিল্টারবারটি অ্যানিমেটেড হয়ে যায় তখনই কেবলমাত্র এই রূপান্তর অ্যানিমেশনটি সক্ষম করে আমি এই কাজটি পরিচালনা করতে সক্ষম হয়েছি।

এটি আপনি যে উত্তরটি সন্ধান করছেন তা সত্যিই নয়, তবে এটি আপনার সমাধান সন্ধানের জন্য আপনাকে সঠিক প্যাডে নিয়ে আসতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.