:发送到解除分配的实例的消息
在模拟器中模拟内存警告时,我的应用程序崩溃,出现错误:
[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文件工具我得到以下跟踪:
这不是唯一发生这种事故的地方。 在我使用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
不能从主线程之外的任何其他线程访问。
一般来说,这可能会发生这些原因:
- 您正在使用
__unsafe_unretained
variables。 - 您正在使用
unsafe_unretained
属性。 - 你正在使用非ARC
- 您正在同一时间从不同的线程访问相同的variables
- 您正在同时访问来自不同线程的同一个
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议通过代理链,通知或阻止冒泡。