[UINavigationController retain]:发送给deallocated实例的消息

时间:2014-08-04 19:59:26

标签: ios objective-c automatic-ref-counting

我的应用程序在模拟器中模拟内存警告时崩溃,错误:

  

[UINavigationController retain]:发送到解除分配的实例的消息

我正在使用ARC。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
      UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
     _window = window;


    [self startWithFlash];

     return YES;
}

- (void)startWithFlash
{
    [self.window.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

    __weak typeof (self) weakSelf = self;

     WPRSplashViewController *splashViewController = [[WPRSplashViewController alloc] initWithNibName:@"WPRSplashView" bundle:nil doneCallback:^{
        [weakSelf startApplication];
    }];


     self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:splashViewController];

    [self.window makeKeyAndVisible];
}

- (void)startApplication
{    
     WPRMainViewController *mainViewController = [[WPRMainViewController alloc] init];
     UINavigationController * controller = [[UINavigationController alloc] initWithRootViewController:mainViewController];

     self.menuController = [[PHMenuViewController alloc] initWithRootViewController:controller
                                                                   atIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];

     self.window.rootViewController = self.menuController;

    [self.window makeKeyAndVisible];
}

当我打电话给app的某个地方时会发生这种情况:

  

[((WPRAppDelegate *)[UIApplication sharedApplication] .delegate)startWithFlash];

在模拟记忆警告之后。

启用NSZombie运行配置文件工具我得到以下跟踪:

Profile tools with NSZombie enabled screen shot

这不是唯一有这种崩溃的地方。在我使用UINavigationController作为视图控制器的包装器的每个地方,我将它作为模态视图呈现,在模拟内存警告后,我得到了这个崩溃。

我在其他地方遇到过非常类似的问题,我在这里发布了另一个问题,但找不到合理的解决方案:Similar issue

3 个答案:

答案 0 :(得分:4)

经过几天的调查后,我发现了所有这些崩溃的原因,包括"iOS memory warning sent to deallocated UIViewController"

中描述的崩溃

问题来自PHAirViewController项目。我仍然没有找到真正的原因,但只是在- (void)dealloc文件中评论PHAirViewController.m函数就行了神奇。

我在运行仪器检测NSZombies时遇到的主要问题。所有跟踪都指向系统类,如UINavigationController,UIImagePickerViewController等......由于这个原因,我开始为父控制器禁用ARC。它在某些地方有所帮助,但有些地方并没有帮助。

经过大量的伏都教后,我发现每个班级(包括系统班级)都在实施UIViewCOntroller(PHAirViewController) Category,虽然- (void)dealloc函数总是被要求解雇它们。

现在唯一剩下的就是理解为什么这个函数正在生成NSZombies。有趣的是,仅仅评论其内容(只有一行:self.phSwipeHandler = nil)不会产生同样的效果。

答案 1 :(得分:1)

Quickfix:assert([NSThread isMainThread]);插入您访问appDelegate.window.rootViewController的代码中的各个位置。这应该用于写入和读取属性!这将揭示罪魁祸首。不得从主线程以外的任何其他线程访问appDelegate.window.rootViewController

通常,有以下原因可能会发生这种情况:

  1. 您正在使用__unsafe_unretained变量。
  2. 您使用的是unsafe_unretained财产。
  3. 您使用的是非ARC
  4. 您正在同时从不同的线程访问同一个变量
  5. 您正在同时从不同的主题访问相同的nonatomic,非weak属性
  6. 1和2的修复很简单:不再使用unsafe_unretained

    3的修正是:改用ARC。

    4和5的修复:改为使用atomic属性,或同步对iVar的访问权限。 (请注意,您不能直接从原子属性访问iVars,因为这会破坏原子性。)或者,仅从一个线程使用该属性,例如仅来自主线程。

    在您的示例中,我认为问题#5适用。罪魁祸首应该是来自rootViewController的一些非主线程访问UIWindow

答案 2 :(得分:0)

您可能在代码中的某处使用了assign或__unsafe_unretained属性。委托应始终属于弱类型,以便在释放时对委托对象的引用为止。

另外,请致电:

[((WPRAppDelegate*) [UIApplication sharedApplication].delegate) startWithFlash];

...来自你应用中的另一个类内部有点气味。我有过很多次了。这意味着你有循环依赖。您的应用程序委托依赖于使用此代码的类(传递,如果不是直接),并且此类依赖于您的应用程序委托。看看你的仪器跟踪,看起来你已经采用了委托模式,所以你有一些解耦的经验。我建议通过委托链,通知或阻止来冒充该消息。