我的应用程序在模拟器中模拟内存警告时崩溃,错误:
[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运行配置文件工具我得到以下跟踪:
这不是唯一有这种崩溃的地方。在我使用UINavigationController作为视图控制器的包装器的每个地方,我将它作为模态视图呈现,在模拟内存警告后,我得到了这个崩溃。
我在其他地方遇到过非常类似的问题,我在这里发布了另一个问题,但找不到合理的解决方案:Similar issue
答案 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
。
通常,有以下原因可能会发生这种情况:
__unsafe_unretained
变量。unsafe_unretained
财产。nonatomic
,非weak
属性 1和2的修复很简单:不再使用unsafe_unretained
。
3的修正是:改用ARC。
4和5的修复:改为使用atomic
属性,或同步对iVar的访问权限。 (请注意,您不能直接从原子属性访问iVars,因为这会破坏原子性。)或者,仅从一个线程使用该属性,例如仅来自主线程。
在您的示例中,我认为问题#5适用。罪魁祸首应该是来自rootViewController
的一些非主线程访问UIWindow
。
答案 2 :(得分:0)
您可能在代码中的某处使用了assign或__unsafe_unretained属性。委托应始终属于弱类型,以便在释放时对委托对象的引用为止。
另外,请致电:
[((WPRAppDelegate*) [UIApplication sharedApplication].delegate) startWithFlash];
...来自你应用中的另一个类内部有点气味。我有过很多次了。这意味着你有循环依赖。您的应用程序委托依赖于使用此代码的类(传递,如果不是直接),并且此类依赖于您的应用程序委托。看看你的仪器跟踪,看起来你已经采用了委托模式,所以你有一些解耦的经验。我建议通过委托链,通知或阻止来冒充该消息。