iOS应用程序错误 - 无法将自身添加为子视图

9 浏览
0 Comments

iOS应用程序错误 - 无法将自身添加为子视图

我收到了这个崩溃报告,但我不知道如何调试它。\n严重异常NSInvalidArgumentException\n无法将自身添加为子视图\n0 ... CoreFoundation __exceptionPreprocess + 130\n1 libobjc.A.dylib objc_exception_throw + 38\n2 CoreFoundation -[NSException initWithCoder:]\n3 UIKit -[UIView(Internal) _addSubview:positioned:relativeTo:] + 110\n4 UIKit -[UIView(Hierarchy) addSubview:] + 30\n5 UIKit __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 1196\n6 UIKit +[UIView(Animation) performWithoutAnimation:] + 72\n7 UIKit -[_UINavigationParallaxTransition animateTransition:] + 732\n8 UIKit -[UINavigationController _startCustomTransition:] + 2616\n9 UIKit -[UINavigationController _startDeferredTransitionIfNeeded:] + 418\n10 UIKit -[UINavigationController __viewWillLayoutSubviews] + 44\n11 UIKit -[UILayoutContainerView layoutSubviews] + 184\n12 UIKit -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 346\n13 QuartzCore -[CALayer layoutSublayers] + 142\n14 QuartzCore CA::Layer::layout_if_needed(CA::Transaction*) + 350\n15 QuartzCore CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 16\n16 QuartzCore CA::Context::commit_transaction(CA::Transaction*) + 228\n17 QuartzCore CA::Transaction::commit() + 314\n18 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 56\niOS版本为7.0.3。\n有人遇到过这个奇怪的崩溃吗?\n更新:\n我不知道我的代码中的哪个部分导致了这个崩溃,所以我无法在这里贴出代码,抱歉。\n第二次更新\n请参见下面的答案。

0
0 Comments

iOS app错误-无法将自己添加为子视图(Can't add self as subview)是由于在导航控制器中重复推送视图控制器引起的。下面是解决此问题的代码以及解决方法。

UINavigationController+DMNavigationController.h
@interface UINavigationController (DMNavigationController)
- (void)didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
@end
@interface DMNavigationController ()
@property (nonatomic, assign) BOOL shouldIgnorePushingViewControllers;
@end
@implementation DMNavigationController
#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;
}
@end

这段代码解决了问题,它通过使用一个私有API来实现。但我可以确认这是App Store安全的(我的一个应用程序使用了这段代码并通过了App Store的审核)。

这是目前为止最好的解决方案,其他一些解决方案可能仍然会出现随机推送两次的问题,或者导航控制器会冻结。

如果这段代码在您的项目中无法编译,可能是有一些代码缺失。

0
0 Comments

iOS app error - Can't add self as subview

最近我们也遇到了这个问题,很有可能是由于同样的问题导致的。

在我们的情况下,有时需要从后端获取数据,这意味着用户可能点击某个按钮,然后在导航推送发生之前会有一点延迟。如果用户快速点击多个按钮,可能会出现两次从同一个视图控制器进行导航推送的情况,从而触发这个异常。

我们的解决方案是给UINavigationController添加一个类别,阻止在顶部视图控制器不是特定时间点的同一个视图控制器时进行推送/弹出操作。

.h文件:

 
UINavigationController (SafePushing)
- (id)navigationLock; /// 获取导航控制器的“锁”
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated navigationLock:(id)navigationLock; /// 使用水平滑动转场。如果视图控制器已经在堆栈中,则不会产生任何效果。如果navigationLock不是当前的锁,则不会产生任何效果。
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated navigationLock:(id)navigationLock; /// 弹出视图控制器,直到指定的视图控制器位于顶部。返回被弹出的视图控制器。如果navigationLock不是当前的锁,则不会产生任何效果。
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated navigationLock:(id)navigationLock; /// 弹出直到堆栈上只剩下一个视图控制器为止。返回被弹出的视图控制器。如果navigationLock不是当前的锁,则不会产生任何效果。

.m文件:

 
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 @[];
}

到目前为止,这似乎已经解决了我们的问题。示例代码如下:

 
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];
}];

基本上,规则是:在任何非用户相关的延迟之前,从相关的导航控制器获取一个锁,并在推送/弹出调用中包含它。

“锁”一词可能有点不合适,因为可能会暗示需要解锁的某种形式的锁定,但由于没有任何“解锁”方法,所以可能没关系。

(作为旁注,“非用户相关的延迟”是指代码引起的任何延迟,即任何异步操作。用户点击一个正在进行动画推送的导航控制器不计算在内,因此对于这些情况无需使用navigationLock:版本。)

你说你正在尝试这个解决方案,它对你解决了问题吗?

到目前为止,是的。问题没有再次出现。我会更新答案。

我根据你的修改版本进行了使用:gist.github.com/mdewolfe/9369751。看起来已经解决了问题。

这个解决方案适用于推送/弹出操作。但是,如果我使用segue,如何解决这个错误?

你能帮我实现吗?请看 stackoverflow.com/q/23247713/1323014 谢谢。

0
0 Comments

iOS应用程序错误 - 无法将自身添加为子视图

最近我遇到了类似的问题,根据我的猜测...

如果你使用Animated:YES推送(或弹出)一个视图控制器,它不会立即完成,如果在动画完成之前进行了另一个推送或弹出操作,就会出现问题。你可以通过将推送和弹出操作临时改为Animated:NO(以便它们同步完成),然后观察是否消除了崩溃来轻松测试这是否是问题所在。

如果这确实是你的问题,并且你希望重新启用动画,则正确的策略是实现UINavigationControllerDelegate协议。

其中包含以下方法,该方法在动画完成后调用:

navigationController:didShowViewController:animated:

基本上,你希望将一些代码根据需要移动到此方法中,以确保在动画完成并且堆栈已准备好进行更多更改之前不会发生可能导致导航控制器堆栈更改的其他操作。

大约在iOS 4版本中,我们的一个应用程序中出现了类似的问题 - 如果你以动画方式弹出然后立即以动画方式推送,UI代码将会出现严重错误。最后,我们只是改变了从不连续进行两个动画推送/弹出操作的方式。当然,自那时以来,所有的底层逻辑都已被重写,但是很容易相信类似的错误仍然存在。

我遇到了相同的问题。在我的情况下,这是因为在调用带有Animated:YES的pushViewController之后,应用程序执行了一个改变新视图控制器UI的指令[newViewController setLabelTitle:...]。我通过将setLabelTitle方法移动到新视图控制器的viewDidLoad中解决了这个问题。谢谢你给了我一个线索。

很高兴能帮到你!如果你知道将使用哪个类,将代码移动到新的视图控制器也是一个选择。不管怎样,我越来越发现捕获UINavigationControllerDelegate协议的各种方法非常有用。我还发现,在iOS 8中,事件的触发顺序不同,一些以前几乎是同步的操作现在会快速返回,但会在后台异步地安排任务,从而创建了许多新的时间错误,比如这些。谢谢,Apple!

0