:发送到解除分配的实例的消息

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

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

这发生在我打电话的应用程序的某个地方:

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

之后模拟记忆警告。

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

配置工具与NSZombie启用屏幕截图

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

我在其他地方有非常类似的问题,我在这里发布了另一个问题,但没有find合理的解决scheme: 类似的问题

最后经过几天的调查,我发现了所有这些崩溃的原因,包括“iOS内存警告发送到释放的UIViewController”

问题出自PHAirViewController项目。 我还没有find一个真正的原因,但只是注释掉- (void)dealloc PHAirViewController.m文件中的- (void)dealloc函数做了魔术。

我在运行仪器检测NSZombies时遇到的主要问题。 所有的痕迹都指向像UINavigationController,UIImagePickerViewController等系统类…因此,我开始禁用父控制器ARC。 在一些地方,但有些地方没有。

经过大量的巫术,我发现每个类(包括系统类)都实现了UIViewCOntroller(PHAirViewController) Category ,尽pipe- (void)dealloc函数总是被调用来解除它们。

现在唯一剩下的就是了解为什么这个函数产生NSZombies。 有趣的是,只是评论它的内容(只有一行: self.phSwipeHandler = nil )并没有相同的效果。

Quickfix: insert assert([NSThread isMainThread]); 到代码中访问appDelegate.window.rootViewController各个地方。 这应该为写入和读取访问属性! 这将揭示罪魁祸首。 appDelegate.window.rootViewController不能从主线程之外的任何其他线程访问。

一般来说,这可能会发生这些原因:

  1. 您正在使用__unsafe_unretainedvariables。
  2. 您正在使用unsafe_unretained属性。
  3. 你正在使用非ARC
  4. 您正在同一时间从不同的线程访问相同的variables
  5. 您正在同时访问来自不同线程的同一个nonatomic ,非weak性质

1和2的修复很简单:只要不使用unsafe_unretained了。

3的修复是:使用ARC来代替。

修复4和5:改为使用atomic属性,或同步访问您的iVars。 (请注意,您不能直接从primefaces属性访问iVars,因为这会打破primefaces性。)或者,只能从一个线程使用该属性,例如仅从主线程使用该属性。

在你的例子中,我假设问题#5适用。 罪魁祸首应该是一些非主线程从UIWindow访问rootViewController

您可能正在代码中使用assign或__unsafe_unretained属性。 代表应该总是弱types的,以便在释放时对委托对象的引用是无效的。

另外,请拨打:

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

…从你的应用程序中的另一个类是有点味道。 我曾经有过很多次 这意味着你有循环依赖。 您的应用程序委托依赖于使用此代码的类(如果不是直接传递的话),并且此类依赖于您的应用程序委托。 看看你的仪器跟踪,看起来你已经采用委托模式,否则你有一些解耦的经验。 我会build议通过代理链,通知或阻止冒泡。