iOS ऐप त्रुटि - सबव्यू के रूप में स्वयं को जोड़ नहीं सकता


157

मुझे यह क्रैश रिपोर्ट मिली, लेकिन मुझे नहीं पता कि इसे कैसे डीबग करना है।

Fatal Exception NSInvalidArgumentException
Can't add self as subview
0 ...    CoreFoundation  __exceptionPreprocess + 130
1    libobjc.A.dylib     objc_exception_throw + 38
2    CoreFoundation  -[NSException initWithCoder:]
3    UIKit   -[UIView(Internal) _addSubview:positioned:relativeTo:] + 110
4    UIKit   -[UIView(Hierarchy) addSubview:] + 30
5    UIKit   __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 1196
6    UIKit   +[UIView(Animation) performWithoutAnimation:] + 72
7    UIKit   -[_UINavigationParallaxTransition animateTransition:] + 732
8    UIKit   -[UINavigationController _startCustomTransition:] + 2616
9    UIKit   -[UINavigationController _startDeferredTransitionIfNeeded:] + 418
10   UIKit   -[UINavigationController __viewWillLayoutSubviews] + 44
11   UIKit   -[UILayoutContainerView layoutSubviews] + 184
12   UIKit   -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 346
13   QuartzCore  -[CALayer layoutSublayers] + 142
14   QuartzCore  CA::Layer::layout_if_needed(CA::Transaction*) + 350
15   QuartzCore  CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16
16   QuartzCore  CA::Context::commit_transaction(CA::Transaction*) + 228
17   QuartzCore  CA::Transaction::commit() + 314
18   QuartzCore  CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 56

IOS वर्जन 7.0.3 है। किसी को भी इस अजीब दुर्घटना का अनुभव?

अपडेट करें:

मुझे नहीं पता कि मेरे कोड में यह क्रैश कहां हुआ है, इसलिए मैं यहां कोड पोस्ट नहीं कर सकता, क्षमा करें।

दूसरा अद्यतन

नीचे उत्तर देखें।


3
क्या आप हमें अपना कोड दिखा सकते हैं?
डेविड गोल्ज़ुसर

43
क्षमा करें, लेकिन मुझे आपका ओवररिएक्शन समझ में नहीं आया। स्टैक त्रुटि समस्या पर स्पष्ट है। इसलिए पहले, आप उपयोगकर्ता को उसके द्वारा पूछे गए अधिक कोड डाल सकते हैं (केवल 1h प्रश्न पूछा गया है और आप इसे तुरंत बंद करने के लिए कहते हैं)। जब से मेरा उत्तर स्पष्ट हुआ है, तब से मुझे बिना किसी कारण के गिरावट का सामना करना पड़ा। सवाल है "कोई भी इस अजीब दुर्घटना का अनुभव करता है?"। और मैंने बताया कि उसे यह क्यों मिला। भले ही यह विशेष रूप से इसके कोड में स्थित नहीं है।
तानकेरेड चेज़लेट

9
यह प्रश्न एक सही है। उपयोगकर्ता कठबोली इस स्थिति में त्रुटि का सटीक कोड देते हैं। क्योंकि वह नहीं जानता कि किस दृश्य में कुछ गलत हो रहा है
रविन्द्र बागले

16
हम Crashlytics का उपयोग करते हैं और हमारे पास 30 से अधिक उपयोगकर्ता हैं, जिन्होंने हमारे ऐप को "स्वयं को उप-वर्ग के रूप में जोड़ नहीं सकते" निश्चित रूप से हमारे पास कोड नहीं है जो स्वयं को एक उप-भाग के रूप में जोड़ने का प्रयास करता है। बैकट्रेस से हमारे ऐप का कोई संदर्भ नहीं है।
रिची हयात

49
फिर से खोलने के लिए मतदान; इसे बंद करने वाले लोग ज्यादा iOS देव नहीं करते हैं, जाहिरा तौर पर, क्योंकि यह iOS7 द्वारा पेश की गई एक आम समस्या है और iOS6 पर ठीक होने वाले ऐप्स का एक पूरा गुच्छा मार रहा है (मैंने इसे विभिन्न कंपनियों से कई परियोजनाओं पर देखा है)। यह अफ़सोस की बात है कि यह सवाल Google पर एक शीर्ष हिट है, लेकिन कुछ ही दूरदर्शी लोगों ने इसे बंद कर दिया।
एडम

जवाबों:


51

मैं कुछ इसी तरह के आधार पर अनुमान लगा रहा हूं जिसे मैंने हाल ही में डीबग किया था ... यदि आप एनिमेटेड के साथ एक व्यू कंट्रोलर को धक्का देते हैं (या पॉप): हाँ, यह अभी पूरा नहीं होता है, और खराब चीजें होती हैं यदि आप एनीमेशन से पहले एक और धक्का या पॉप करते हैं पूरा करता है। आप आसानी से परीक्षण कर सकते हैं कि क्या यह वास्तव में आपके पुश और पॉप ऑपरेशन को एनिमेटेड रूप से बदलकर मामला है: NO (ताकि वे समकालिक रूप से पूरा हो) और यह देखते हुए कि दुर्घटना को समाप्त करता है या नहीं। यदि यह वास्तव में आपकी समस्या है और आप एनीमेशन को चालू करना चाहते हैं, तो UINavigationControllerDelegate प्रोटोकॉल को लागू करने के लिए सही रणनीति है। इसमें निम्नलिखित विधि शामिल है, जिसे एनीमेशन पूरा होने के बाद कहा जाता है:

navigationController:didShowViewController:animated:

मूल रूप से आप कुछ कोड को इस विधि में आवश्यकतानुसार स्थानांतरित करना चाहते हैं ताकि यह सुनिश्चित हो सके कि कोई अन्य कार्रवाई जो कि नेविगेशनकंट्रोलर स्टैक में बदलाव का कारण नहीं बन सकती है जब तक कि एनीमेशन समाप्त नहीं हो जाता है और स्टैक अधिक परिवर्तनों के लिए तैयार है।


IOS 4 के बारे में वापस-कुछ ऐसा ही मैंने अपने एक ऐप - IIRC में कुछ इसी तरह से देखा, अगर आप एनिमेटेड पॉप करते हैं और फिर एनिमेटेड को धकेल दिया तो UI कोड बुरी तरह से मैक्ड हो जाएगा। बैक टू बैक दो एनिमेटेड पुश / पॉप ऑपरेशंस को कभी नहीं बदलने के लिए समाप्त हुआ। बेशक, सभी अंतर्निहित तर्क तब से फिर से लिखे गए हैं, लेकिन यह विश्वास करना मुश्किल नहीं है कि एक समान बग अभी भी नहीं है।
हॉट लिक्स

मेरी भी यही समस्या थी। मेरे मामले में ऐसा इसलिए हुआ क्योंकि ऐप ने एक निर्देश को अंजाम दिया जो पुश व्यू कॉन्ट्रोलर को [newViewController setLabelTitle:...]कॉल करने के बाद नए व्यू कंट्रोलर के यूआई को बदल देता है Animated:YES.और मैंने सेट सेटेलबेलिट विधि को नए व्यू कॉन्ट्रोलर पर viewDidLoad में स्थानांतरित कर दिया। मुझे सुराग देने के लिए धन्यवाद।
jeprubio

खुशी है कि मदद की! अच्छा मुद्दा यह है कि नए ViewController के लिए कोड को स्थानांतरित करना भी एक विकल्प है यदि आप जानते हैं कि यह किस वर्ग का होगा। अधिक से अधिक मैं UINavigationControllerDelegate प्रोटोकॉल के विभिन्न तरीकों को किसी भी मामले में पकड़ना उपयोगी समझता हूं। और मैंने पाया है कि iOS8 में ईवेंट अलग-अलग ऑर्डर में आग लगाते हैं, और कुछ चीजें जो कम या ज्यादा सिंक्रोनस हुआ करती थीं, अब बैकग्राउंड पर असिंक्रोनस रूप से काम करने के लिए तेजी से लेकिन शेड्यूल की गई चीजों को बनाते हैं, जिससे बहुत सारे नए टाइमिंग बग्स बन जाते हैं। धन्यवाद, Apple!
रॉब

14

हमने इस मुद्दे को भी प्राप्त करना शुरू कर दिया, और संभावना बहुत अधिक थी कि हमारी समस्या के कारण हमारी समस्या थी।

हमारे मामले में, हमें कुछ मामलों में पीछे के अंत से डेटा खींचना था, जिसका मतलब था कि उपयोगकर्ता कुछ टैप कर सकता है और फिर नव धक्का आने से पहले थोड़ी देरी होगी। यदि कोई उपयोगकर्ता तेजी से चारों ओर टैप कर रहा था, तो वे एक ही व्यू कंट्रोलर से दो नेवी पुश के साथ समाप्त हो सकते हैं, जिससे यह बहुत अपवाद हो गया।

हमारा समाधान UINavigationController पर एक श्रेणी है जो पुश / पॉप को रोकता है जब तक कि शीर्ष vc समय में दिए गए बिंदु से एक ही न हो।

.h फ़ाइल:

@interface UINavigationController (SafePushing)

- (id)navigationLock; ///< Obtain "lock" for pushing onto the navigation controller

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated navigationLock:(id)navigationLock; ///< Uses a horizontal slide transition. Has no effect if the view controller is already in the stack. Has no effect if navigationLock is not the current lock.
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated navigationLock:(id)navigationLock; ///< Pops view controllers until the one specified is on top. Returns the popped controllers. Has no effect if navigationLock is not the current lock.
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated navigationLock:(id)navigationLock; ///< Pops until there's only a single view controller left on the stack. Returns the popped controllers. Has no effect if navigationLock is not the current lock.

@end

.m फ़ाइल:

@implementation UINavigationController (SafePushing)

- (id)navigationLock
{
    return self.topViewController;
}

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated navigationLock:(id)navigationLock
{
    if (!navigationLock || self.topViewController == navigationLock) 
        [self pushViewController:viewController animated:animated];
}

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated navigationLock:(id)navigationLock
{
    if (!navigationLock || self.topViewController == navigationLock)
        return [self popToRootViewControllerAnimated:animated];
    return @[];
}

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated navigationLock:(id)navigationLock
{
    if (!navigationLock || self.topViewController == navigationLock)
        return [self popToViewController:viewController animated:animated];
    return @[];
}

@end

अब तक यह हमारे लिए समस्या का समाधान हो गया है। उदाहरण:

id lock = _dataViewController.navigationController.navigationLock;
[[MyApi sharedClient] getUserProfile:_user.id success:^(MyUser *user) {
    ProfileViewController *pvc = [[ProfileViewController alloc] initWithUser:user];
    [_dataViewController.navigationController pushViewController:pvc animated:YES navigationLock:lock];
}];

मूल रूप से, नियम यह है: इससे पहले कि कोई भी गैर-उपयोगकर्ता संबंधित देरी संबंधित नौसेना नियंत्रक से ताला पकड़ ले, और इसे पॉप या पुश करने के लिए कॉल में शामिल करें।

यह शब्द "लॉक" थोड़ा खराब हो सकता है क्योंकि इसमें यह लिखा हो सकता है कि लॉक का कुछ ऐसा रूप है जिसे अनलॉक करने की आवश्यकता है, लेकिन चूंकि कहीं भी "अनलॉक" विधि नहीं है, यह शायद ठीक है।

(एक सिडेनोट के रूप में, "नॉन यूजर रिलेटेड डिले" किसी भी तरह की देरी है जो कोड का कारण बन रहा है, अर्थात कुछ भी अतुल्यकालिक। किसी नेवी कंट्रोलर पर टैप करने वाले यूजर्स को एनिमेटेड रूप से पुश किया जाता है और उन्हें नेविगेशन लॉक करने की कोई आवश्यकता नहीं है। मामलों।)


चूंकि आपने कहा था कि आप इस समाधान की कोशिश कर रहे थे, क्या यह आपके लिए समस्या का हल है?
माइक डी

अब तक हां। समस्या का पुनरुत्थान नहीं हुआ है। मैं जवाब अपडेट कर दूंगा।
कलले

4
मैंने आपके आधार पर एक संशोधित संस्करण का उपयोग किया: gist.github.com/mdewolfe/9369751 । लगता है, इसे ठीक कर लिया है।
माइक डी

2
@ यह समाधान पुश / पॉप के लिए काम करता है। लेकिन अगर मैं सीग का उपयोग करता हूं तो इस त्रुटि को कैसे हल किया जाए?
गीक

@ क्या आप इसे लागू करने में मेरी मदद कर सकते हैं? देखें stackoverflow.com/q/23247713/1323014 THX
मर्कारौजो

12

यह कोड समस्या का समाधान करता है: https://gist.github.com/nonamelive/9334458

यह एक निजी एपीआई का उपयोग करता है, लेकिन मैं पुष्टि कर सकता हूं कि यह ऐप स्टोर सुरक्षित है। (इस कोड का उपयोग करने वाले मेरे एक ऐप को ऐप स्टोर द्वारा अनुमोदित किया गया है।)

@interface UINavigationController (DMNavigationController)

- (void)didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

@end

@interface DMNavigationController ()

@property (nonatomic, assign) BOOL shouldIgnorePushingViewControllers;

@end

@implementation DMNavigationViewController

#pragma mark - Push

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (!self.shouldIgnorePushingViewControllers)
    {
        [super pushViewController:viewController animated:animated];
    }

    self.shouldIgnorePushingViewControllers = YES;
}

#pragma mark - Private API

// This is confirmed to be App Store safe.
// If you feel uncomfortable to use Private API, you could also use the delegate method navigationController:didShowViewController:animated:.
- (void)didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [super didShowViewController:viewController animated:animated];
    self.shouldIgnorePushingViewControllers = NO;
}

यह अब तक का सबसे अच्छा समाधान रहा है, कुछ अन्य के साथ मैं अभी भी बेतरतीब ढंग से डबल पुश मुद्दा प्राप्त करूंगा या मुझे एक स्थिर नेविगेशन नियंत्रक मिलेगा।
नीला

यह कोड मेरे लिए संकलन नहीं है, क्या कुछ गायब है?
मैक्सिमे बी

8

मैं अपने ऐप में इस दुर्घटना के बारे में अधिक जानकारी का वर्णन करूंगा और इसे उत्तर के रूप में चिह्नित करूंगा।

मेरे ऐप में UINavigationController है रूट कंट्रोलर के साथ UITableViewController है जिसमें नोट ऑब्जेक्ट्स की एक सूची है। नोट ऑब्जेक्ट html में एक सामग्री गुण है। एक नोट चुनें डिटेल कंट्रोलर के पास जाएगी।

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //get note object
    DetailViewController *controller = [[DetailViewController alloc] initWithNote:note];
    [self.navigationController pushViewController:controller animated:YES];
}

विस्तार नियंत्रक

इस नियंत्रक के पास एक UIWebView है, रूट नियंत्रक से पारित नोट सामग्री को प्रदर्शित करें।

- (void)viewDidLoad
{
    ...
    [_webView loadHTMLString:note.content baseURL:nil];
    ...
}

यह नियंत्रक वेबव्यू नियंत्रण का प्रतिनिधि है। यदि नोट में लिंक हैं, तो एक लिंक टैप करें इन-ऐप वेब ब्राउज़र पर जाएगा।

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    WebBrowserViewController *browserController = [[WebBrowserViewController alloc] init];
    browserController.startupURL = request.URL;
    [self.navigationController pushViewController:webViewController animated:YES];
    return NO;
}

मुझे उपरोक्त दुर्घटना की रिपोर्ट प्रतिदिन प्राप्त हुई। मुझे नहीं पता कि मेरे कोड में यह दुर्घटना कहां हुई। एक उपयोगकर्ता की मदद से कुछ जांच के बाद, मैं आखिरकार इस दुर्घटना को ठीक करने में सक्षम था। यह html सामग्री दुर्घटना का कारण बनेगी:

...
<iframe src="http://google.com"></iframe>
...

डिटेल कंट्रोलर के व्यूडीडालैड मेथड में, मैंने इस html को वेबव्यू कंट्रोल पर लोड किया, ठीक उसके बाद, ऊपर के डेलिगेट मेथड को तुरंत रिक्वेस्ट के साथ बुलाया गया ।URL iframe का सोर्स (google.com) है। यह प्रतिनिधि पद्धति viewDidLoad => क्रैश के दौरान pushViewController विधि कहती है!

मैंने नेविगेशन क्रैश की जाँच करके इस क्रैश को ठीक किया:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if (navigationType != UIWebViewNavigationTypeOther)
    {
        //go to web browser controller
    }
}

उम्मीद है की यह मदद करेगा


1
यह जब से कहा जाता है एनीमेशन के बिना नियंत्रक पुश करने के लिए एक अच्छा विकल्प नहीं होगा viewDidLoad?
रिवेरा

6

मेरे पास एक ही मुद्दा था, जो मेरे लिए बस काम कर रहा था वह एनिमेटेड बदल रहा था: हां एनिमेटेड के लिए: नहीं।

ऐसा लगता है कि एनीमेशन समय पर पूरा नहीं होने के कारण मुद्दा था।

आशा है कि यह किसी की मदद करता है।


3

इस बग को पुन: उत्पन्न करने के लिए, एक ही समय में दो दृश्य नियंत्रक को धकेलने का प्रयास करें। या एक ही समय में धक्का और पॉपिंग। उदाहरण:

यहां छवि विवरण दर्ज करें मैंने एक श्रेणी बनाई है जो इन कॉलों को स्वीकार करती है और उन्हें यह सुनिश्चित करके सुरक्षित बनाती है कि कोई अन्य धक्का नहीं लग रहा है जबकि एक प्रगति पर है। बस अपने प्रोजेक्ट में कोड कॉपी करें और विधि स्विज़लिंग के कारण आप जाना अच्छा होगा।

#import "UINavigationController+Consistent.h"
#import <objc/runtime.h>
/// This char is used to add storage for the isPushingViewController property.
static char const * const ObjectTagKey = "ObjectTag";

@interface UINavigationController ()
@property (readwrite,getter = isViewTransitionInProgress) BOOL viewTransitionInProgress;

@end

@implementation UINavigationController (Consistent)

- (void)setViewTransitionInProgress:(BOOL)property {
    NSNumber *number = [NSNumber numberWithBool:property];
    objc_setAssociatedObject(self, ObjectTagKey, number , OBJC_ASSOCIATION_RETAIN);
}


- (BOOL)isViewTransitionInProgress {
    NSNumber *number = objc_getAssociatedObject(self, ObjectTagKey);

    return [number boolValue];
}


#pragma mark - Intercept Pop, Push, PopToRootVC
/// @name Intercept Pop, Push, PopToRootVC

- (NSArray *)safePopToRootViewControllerAnimated:(BOOL)animated {
    if (self.viewTransitionInProgress) return nil;
    if (animated) {
        self.viewTransitionInProgress = YES;
    }
    //-- This is not a recursion, due to method swizzling the call below calls the original  method.
    return [self safePopToRootViewControllerAnimated:animated];

}


- (NSArray *)safePopToViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if (self.viewTransitionInProgress) return nil;
    if (animated) {
        self.viewTransitionInProgress = YES;
    }
    //-- This is not a recursion, due to method swizzling the call below calls the original  method.
    return [self safePopToViewController:viewController animated:animated];
}


- (UIViewController *)safePopViewControllerAnimated:(BOOL)animated {
    if (self.viewTransitionInProgress) return nil;
    if (animated) {
        self.viewTransitionInProgress = YES;
    }
    //-- This is not a recursion, due to method swizzling the call below calls the original  method.
    return [self safePopViewControllerAnimated:animated];
}



- (void)safePushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    self.delegate = self;
    //-- If we are already pushing a view controller, we dont push another one.
    if (self.isViewTransitionInProgress == NO) {
        //-- This is not a recursion, due to method swizzling the call below calls the original  method.
        [self safePushViewController:viewController animated:animated];
        if (animated) {
            self.viewTransitionInProgress = YES;
        }
    }
}


// This is confirmed to be App Store safe.
// If you feel uncomfortable to use Private API, you could also use the delegate method navigationController:didShowViewController:animated:.
- (void)safeDidShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    //-- This is not a recursion. Due to method swizzling this is calling the original method.
    [self safeDidShowViewController:viewController animated:animated];
    self.viewTransitionInProgress = NO;
}


// If the user doesnt complete the swipe-to-go-back gesture, we need to intercept it and set the flag to NO again.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    id<UIViewControllerTransitionCoordinator> tc = navigationController.topViewController.transitionCoordinator;
    [tc notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        self.viewTransitionInProgress = NO;
        //--Reenable swipe back gesture.
        self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController;
        [self.interactivePopGestureRecognizer setEnabled:YES];
    }];
    //-- Method swizzling wont work in the case of a delegate so:
    //-- forward this method to the original delegate if there is one different than ourselves.
    if (navigationController.delegate != self) {
        [navigationController.delegate navigationController:navigationController
                                     willShowViewController:viewController
                                                   animated:animated];
    }
}


+ (void)load {
    //-- Exchange the original implementation with our custom one.
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(pushViewController:animated:)), class_getInstanceMethod(self, @selector(safePushViewController:animated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(didShowViewController:animated:)), class_getInstanceMethod(self, @selector(safeDidShowViewController:animated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(popViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopViewControllerAnimated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToRootViewControllerAnimated:)), class_getInstanceMethod(self, @selector(safePopToRootViewControllerAnimated:)));
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(popToViewController:animated:)), class_getInstanceMethod(self, @selector(safePopToViewController:animated:)));
}

@end

इस समाधान के साथ एक समस्या यह है कि यदि आप कॉल करते हैं popToRootViewControllerया popToViewController:जब आप पहले से ही रूट व्यू कंट्रोलर पर हैं या व्यू कॉन्ट्रोलर पर पॉप अप होते हैं, तो didShowViewControllerउसे कॉल नहीं किया जाएगा और यह अंदर फंस जाएगा viewTransitionInProgress
divergio

1
क्या आप इन पंक्तियों की व्याख्या कर सकते हैं: self.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)viewController; [self.interactivePopGestureRecognizer setEnabled:YES]; पहचानकर्ता कब अक्षम हो गया था? और आप कैसे जानते हैं कि प्रतिनिधि होना चाहिए? उन पंक्तियों के साथ, मेरे लिए यह एक बार पॉपिंग के बाद पॉप इशारे को तोड़ देता है।
गोताखोर

मैंने इसे लागू करने की कोशिश की और थोड़ी देर के बाद यह नेविगेशन नियंत्रक को बंद कर दिया, शायद @divergio ने इसका उल्लेख किया।
17

2

बस इस मुद्दे का अनुभव भी है। मुझे तुम मेरे कोड दिखाने दें:

override func viewDidLoad() { 
  super.viewDidLoad()

  //First, I create a UIView
  let firstFrame = CGRect(x: 50, y: 70, height: 200, width: 200)
  let firstView = UIView(frame: firstFrame)
  firstView.addBackgroundColor = UIColor.yellow
  view.addSubview(firstView) 

  //Now, I want to add a subview inside firstView
  let secondFrame = CGRect(x: 20, y:50, height: 15, width: 35)
  let secondView = UIView(frame: secondFrame)
  secondView.addBackgroundColor = UIColor.green
  firstView.addSubView(firstView)
 }

इस लाइन के कारण त्रुटि सामने आती है:

firstView.addSubView(firstView)

आप सबव्यू में स्वयं को नहीं जोड़ सकते। मैं करने के लिए कोड की लाइन बदल दिया है:

firstView.addSubView(secondView)

त्रुटि दूर हो गई और मैं दोनों के विचारों को देख पा रहा था। बस सोचा था कि यह किसी को भी मदद करेगा जो एक उदाहरण देखना चाहता था।


मैंने भी इस दृष्टिकोण की कोशिश की, लेकिन स्टैकट्रेस अलग होगा और वास्तव में आपके कोड की लाइन दिखाएगा जिससे दुर्घटना हो सकती है। मेरा मानना ​​है कि स्रोत का मुद्दा सवाल से अलग है।
बेन

1

"AddSubview" के लिए अपना कोड खोजें।

आपने जिन स्थानों को इस पद्धति का नाम दिया है उनमें से एक में आपने इस विधि का उपयोग करके अपने स्वयं के उप-दृश्य सरणी में एक दृश्य जोड़ने का प्रयास किया।

उदाहरण के लिए:

[self.view addSubview:self.view];

या:

[self.myLabel addSubview:self.myLabel];

आपको अपनी त्रुटि मिली सुनकर खुशी हुई, और अब मुझे समझ में आया कि आपने "स्वयं को उप-वर्ग के रूप में नहीं जोड़ा" क्यों प्राप्त किया। उस बिंदु पर जहां आपका View2 आपके नेविगेशन कंट्रोलर का रूट व्यू कंट्रोलर था, जिसे आपने View2 को धक्का दिया था, जो इस [View2.view addSubview:View2.view]प्रकार था: इस प्रकार, स्वयं को सबव्यू के रूप में जोड़ना।
मिशाल शट्ज १४'१४ z:

1

मुझे लगता है कि किसी भी बिंदु पर एनीमेशन के साथ व्यू कंट्रोलर्स को पुश / पॉपिंग करना पूरी तरह से ठीक होना चाहिए और एसडीके को विनम्रता से हमारे लिए कॉल की कतार को संभालना चाहिए।

इसलिए यह नहीं है और सभी समाधान बाद के धकेलों को नजरअंदाज करने की कोशिश करते हैं, जिसे एक बग माना जा सकता है क्योंकि अंतिम नेविगेशन स्टैक वह नहीं है जो कोड का इरादा था।

मैंने इसके बजाय एक पुश कॉल कतार लागू की:

// SafeNavigationController.h

@interface SafeNavigationController : UINavigationController
@end

 

// SafeNavigationController.m

#define timeToWaitBetweenAnimations 0.5

@interface SafeNavigationController ()

@property (nonatomic, strong) NSMutableArray * controllersQueue;
@property (nonatomic)         BOOL animateLastQueuedController;
@property (nonatomic)         BOOL pushScheduled;
@property (nonatomic, strong) NSDate * lastAnimatedPushDate;

@end

@implementation SafeNavigationController

- (void)awakeFromNib
{
    [super awakeFromNib];

    self.controllersQueue = [NSMutableArray array];
}

- (void)pushViewController:(UIViewController *)viewController
                  animated:(BOOL)animated
{
    [self.controllersQueue addObject:viewController];
    self.animateLastQueuedController = animated;

    if (self.pushScheduled)
        return;

    // Wait for push animation to finish
    NSTimeInterval timeToWait = self.lastAnimatedPushDate ? timeToWaitBetweenAnimations + [self.lastAnimatedPushDate timeIntervalSinceNow] : 0.0;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((timeToWait > 0.0 ? timeToWait : 0.0) * NSEC_PER_SEC)),
                   dispatch_get_main_queue(), ^
                   {
                       [self pushQueuedControllers];

                       self.lastAnimatedPushDate = self.animateLastQueuedController ? [NSDate date] : nil;
                       self.pushScheduled = NO;
                   });
    self.pushScheduled = YES;
}

- (void)pushQueuedControllers
{
    for (NSInteger index = 0; index < (NSInteger)self.controllersQueue.count - 1; index++)
    {
        [super pushViewController:self.controllersQueue[index]
                         animated:NO];
    }
    [super pushViewController:self.controllersQueue.lastObject
                     animated:self.animateLastQueuedController];

    [self.controllersQueue removeAllObjects];
}

@end

यह धक्का और चबूतरे के मिश्रित कतारों को नहीं संभालता है, लेकिन हमारे अधिकांश क्रैश को ठीक करने के लिए यह एक अच्छा स्टार्टर है।

Gist: https://gist.github.com/rivera-ernesto/0bc628be1e24ff5x4ee


मैं आपके समाधान की कोशिश कर रहा हूं जो बहुत अच्छा लगता है, लेकिन मुझे समस्या हो रही है। जब एक के बाद एक एनिमेटेड NO के साथ 2 व्यू कंट्रोलर्स को पुश किया जाता है, तो मैं बहुत संक्षेप में पहले एक को देखता हूं। ऐसा पहले नहीं हुआ था। किसी भी विचार मैं इसे ठीक करने के लिए क्या कर सकता हूं?
जनवरी

मैं एक ऐसी परियोजना बनाने की कोशिश कर रहा हूं जो लगातार इस तरह की दुर्घटना का कारण बन सकती है (मेरी वास्तविक परियोजना इस तरह दुर्घटना की रिपोर्ट प्राप्त करती है)। मैंने एक नैविगेशन कंट्रोलर, रूट कंट्रोलर और एक बटन के साथ एक साधारण ऐप किया, जो कि नेव स्टैक पर 4 नए व्यू कंट्रोलर को तुरंत धक्का देता है, और फिर पिछले एक को पॉप करता है। किसी विशेष उपवर्ग या किसी भी चीज़ के बिना यह वास्तव में ठीक काम करता है। क्या हाल ही में Apple ने इसे ठीक किया?
क्रूजिन्ग

1

पार्टी के लिए देर से आने के लिए क्षमा करें। मेरे पास हाल ही में यह समस्या थी जिसमें एक ही समय में एक से अधिक व्यू कंट्रोलर को पुश करने के कारण मेरा नेविगेशनबार भ्रष्ट स्थिति में चला जाता है। ऐसा इसलिए होता है क्योंकि दूसरे दृश्य नियंत्रक को धक्का दिया जाता है जबकि पहला दृश्य नियंत्रक अभी भी एनिमेट कर रहा है। गैर-जवाब से संकेत लेते हुए मैं अपने सरल समाधान के साथ आया जो मेरे मामले में काम करता है। आपको बस उप- UINavigationControllerदृश्य की जरूरत है और pushViewController विधि को ओवरराइड करें और जांचें कि क्या पिछला व्यू कंट्रोलर एनीमेशन अभी तक समाप्त हो गया है। आप अपनी कक्षा को एक प्रतिनिधि UINavigationControllerDelegateबनाकर और प्रतिनिधि को स्थापित करके एनीमेशन को पूरा करने के लिए सुन सकते हैं self

मैंने चीजों को सरल बनाने के लिए यहां एक जिस्ट अपलोड किया है ।

बस यह सुनिश्चित करें कि आपने अपने स्टोरीबोर्ड में इस नए वर्ग को नेविगेशनकंट्रोलर के रूप में सेट किया है।


अब तक ऐसा लगता है कि मैं जिस ऐप पर काम कर रहा था, उस पर क्रैश को ठीक कर दिया है ... इसके अलावा, समाधान बिंदु के बारे में बहुत सीधा और स्पष्ट है: पहला व्यूकंट्रोलर एनीमेशन अभी तक पूरा नहीं हुआ था। समान समस्या वाले लोगों को इसकी जाँच करनी चाहिए।
अलास्का

0

@RobP महान संकेत के आधार पर मैंने ऐसी समस्याओं को रोकने के लिए UINavigationController उपवर्ग बनाया । यह धक्का और / या पॉपिंग को संभालता है और आप सुरक्षित रूप से निष्पादित कर सकते हैं:

[self.navigationController pushViewController:vc1 animated:YES];
[self.navigationController pushViewController:vc2 animated:YES];
[self.navigationController pushViewController:vc3 animated:YES];
[self.navigationController popViewControllerAnimated:YES];

यदि 'acceptConflistingCommands' ध्वज को सही है (डिफ़ॉल्ट रूप से) उपयोगकर्ता vc1, vc2, vc3 के एनिमेटेड पुशिंग को देखेगा और फिर vc3 के एनिमेटेड पॉपिंग को देखेगा। यदि 'acceptConflistingCommands' गलत है, तो vc1 को पूरी तरह से धकेलने तक सभी पुश / पॉप अनुरोधों को छोड़ दिया जाएगा - इसलिए अन्य 3 कॉलों को छोड़ दिया जाएगा।


क्या वे आदेश वास्तव में परस्पर विरोधी हैं? मैंने इस दुर्घटना को देखने के लिए बस एक त्वरित नई परियोजना को एक साथ फेंक दिया, जैसा कि आपके ऊपर (लेकिन स्विफ्ट में) कोड का उपयोग करके किया गया है, और यह वास्तव में प्रत्येक पुश को निष्पादित करता है, और पॉप, सभी क्रम में। एक के बाद एक। दुर्घटना नहीं। बिना किसी उपवर्ग का उपयोग किए। सिर्फ सेब की नियमित UINavigationController।
क्रूज़ह

यह वास्तव में ObjC और iOS 7 के साथ दुर्घटनाग्रस्त हो गया था। मैं पुष्टि नहीं कर सकता कि क्या यह अभी भी होता है। क्या आप वाकई animated:trueध्वज के साथ कमांड निष्पादित कर रहे हैं ?
hris.to

हां मैं एनिमेटेड: सच्चे ध्वज का उपयोग कर रहा था।
क्रूजसिंह

0

nonamelive का घोल कमाल का है। लेकिन अगर आप निजी UINavigationControllerDelegateएपि का उपयोग नहीं करना चाहते हैं, तो आप केवल विधि प्राप्त कर सकते हैं। और आप एनिमेटेड YESको बदल सकते हैं NO। यहां कोड का एक नमूना है, आप इसे विरासत में ले सकते हैं। आशा है कि यह उपयोगी है:)

https://github.com/antrix1989/ANNavigationController


0

मैंने इस समस्या को बहुत खोजा था, यह शायद एक ही समय में दो या अधिक वीसी को धक्का दे रहा है, जो धक्का देने वाली एनीमेशन समस्या का कारण बनता है, आप इसे संदर्भित कर सकते हैं: सबटव्यू के रूप में स्वयं को जोड़ नहीं सकते 崩溃 a a

बस सुनिश्चित करें कि एक ही समय में संक्रमण प्रगति पर एक कुलपति है। सौभाग्य।


0

कभी-कभी आपने गलती से अपने स्वयं के दृश्य में एक दृश्य जोड़ने की कोशिश की।

halfView.addSubview(halfView)

इसे अपने उप दृश्य में बदलें।

halfView.addSubview(favView)

0

मुझे भी इस समस्या का सामना करना पड़ा। जब मैंने फायरबेस लॉग विश्लेषण किया, तो मैंने पाया कि यह समस्या केवल तब होती है जब ऐप ठंडा होता है। इसलिए मैंने एक डेमो लिखा जो इस दुर्घटना को पुन: उत्पन्न कर सकता है।

मैंने यह भी पाया कि जब विंडो का रूट व्यूकंट्रोलर प्रदर्शित होता है, तो कई पुश करने से फिर से वही समस्या नहीं होगी। (आप AppDelegate.swift में testColdStartUp (rootNav) टिप्पणी कर सकते हैं, और TestColdStartUp () ViewController.swift में टिप्पणी कर सकते हैं)

ps: मैंने अपने ऐप में इस दुर्घटना के दृश्य का विश्लेषण किया। जब उपयोगकर्ता ऐप को ठंडा करने के लिए पुश अधिसूचना पर क्लिक करता है, तो ऐप अभी भी लॉन्च पेज पर है और कूदने के लिए एक और पुश क्लिक करता है। इस समय, ऐप क्रैश दिखाई दे सकता है। मेरा वर्तमान समाधान ऐप जंप पेज को खोलने के लिए पुश या यूनिवर्सल लिंक कोल्ड स्टार्ट को कैश करने के लिए है, प्रदर्शन करने के लिए rootviewcontroller की प्रतीक्षा करें और फिर निष्पादन में देरी करें।


-2

अंतिम नेविगेशन एनीमेशन को पूरा करने के लिए, विलंब विधि का उपयोग करके अपने नेविगेशन की कोशिश करें,

[self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay:<#(NSTimeInterval)#>]


-2

इसमें एक दृश्य को एक स्व के रूप में नहीं जोड़ा जा सकता है।

विचार एक अभिभावक-बच्चे के पदानुक्रम को बनाए रखता है इसलिए यदि आप एक दृश्य को अपने आप में एक अपवाद के रूप में जोड़ दें तो यह अपवाद होगा।

यदि कोई वर्ग UIViewController है तो उसका विचार प्राप्त करने के लिए आप self.view का उपयोग करें।

यदि एक वर्ग उविएव क्लास है तो उसका विचार जानने के लिए आप स्वयं का उपयोग करें।


-3

यदि आप UiViewController क्लास होने जा रहे हैं, तो आप सबव्यू के रूप में स्वयं को जोड़ नहीं सकते। यदि आप UiView क्लास होने जा रहा है, तो आप सबव्यू के रूप में स्वयं को जोड़ सकते हैं।


-9

यदि आप किसी दृश्य में सबव्यू जोड़ना पसंद करते हैं तो आप इसे इस तरह से कर सकते हैं;

UIView *mainview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)]; //Creats the mainview
    UIView *subview = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; //Creates the subview, you can use any kind of Views (UIImageView, UIWebView, UIView…)

    [mainview addSubview:subview]; //Adds subview to mainview

अच्छा किया, यह कोड का एक अच्छा टुकड़ा है। अब आप मुझे बता सकते हैं कि इस सवाल का क्या करना है और यह कैसे हल करता है?
पोपिये

@Popeye क्या आपके पास बेहतर विचार है?
डेविड गोल्ज़ुसर

नहीं, क्योंकि उन्होंने समस्या को दोहराने के लिए पर्याप्त जानकारी / कोड प्रदान नहीं किया है। इसलिए इसका कोई तरीका नहीं है कि इसका उत्तर दिया जा सके, यह सिर्फ आपके कहने के बारे में बताता है कि कैसे कुछ ऐसा करना है जिसका उनके मुद्दे से कोई लेना-देना नहीं है।
पोपिये

2
मुझे लगता है कि इस मुद्दे को बंद करने के लिए यह उनके लिए बहुत अधिक उपयोगी था। समझ गया! वास्तव में StackOverflow पर किसी की मदद करने के लिए डेविड जी के लिए +1। काश मैं -1 आपके करीबी वोट कर सकता हूँ !!! यह अभी भी उपयोगकर्ताओं के लिए हो रहा है और यह सभी के लिए iOS7 में एक बग हो सकता है। इसलिए सिर्फ इसलिए कि कोई आपत्तिजनक कोड पोस्ट नहीं कर सकता है, इसका मतलब यह नहीं है कि प्रश्न अन्य उपयोगकर्ताओं के लिए मान्य और मूल्यवान नहीं है। यहां तक ​​कि अगर यह देखना है कि अन्य लोग बिना किसी तार्किक कारण के ही मुद्दे को देख रहे हैं तो वे इसे क्यों देख रहे हैं। -र्रह
रिची हयात
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.