【发布时间】:2012-09-22 08:39:35
【问题描述】:
那么,viewDidUnload 自 iOS 6 起已弃用,我现在需要做什么?
删除它,将didReceiveMemoryWarning中的所有内容迁移出去,或者离开它,在didReceiveMemoryWarning中不做任何事情?
【问题讨论】:
标签: ios
那么,viewDidUnload 自 iOS 6 起已弃用,我现在需要做什么?
删除它,将didReceiveMemoryWarning中的所有内容迁移出去,或者离开它,在didReceiveMemoryWarning中不做任何事情?
【问题讨论】:
标签: ios
简短的回答是,在许多情况下,您不需要更改任何内容。而且,您肯定不想简单地将viewDidUnload 的所有内容迁移到didReceiveMemoryWarning。
一般来说,我们大多数人都会在viewDidUnload 中设置IBOutlet 对nil 的引用(主要是因为Interface Builder 会为我们设置)并进行一般的内存释放(例如清除缓存、释放didReceiveMemoryWarning 中易于重新创建的模型数据等)。如果您是这样做的,那么您可能不需要任何代码更改。
根据 iOS 6 viewDidUnload 文档:
在内存不足的情况下不再清除视图,因此永远不会调用此方法。
因此,您确实不想将IBOutlet 对nil 的引用设置移动到任何地方,因为不再清除视图。在didReceiveMemoryWarning 中将它们设置为nil 或类似的东西是没有意义的。
但是,如果您通过在viewDidUnload 中释放易于重新创建的模型对象、清空缓存等来响应低内存事件,那么这些东西肯定应该移至didReceiveMemoryWarning。但话说回来,我们大多数人已经有了它。
最后,如果你释放 didReceiveMemoryWarning 中的任何东西,只要确保你的代码在你弹回时不依赖于它们在 viewDidLoad 中重新创建,因为它不会被调用(因为视图本身,从未卸载过)。
正如 applefreak 所说,这取决于您在 viewDidUnload 中所做的事情。如果您用viewDidUnload 中的明确示例更新您的问题,我们可能会提供不那么抽象的建议。
【讨论】:
简短回答:
永远不要使用 -didReceiveMemoryWarning 进行平衡拆除,因为它可能永远不会或多次调用。如果您在 -viewDidLoad 中进行了设置,请将清理代码放在 -dealloc 中。
长答案:
要给出一个笼统的答案并不容易,因为这确实取决于具体情况。但是,有两个重要的事实需要说明:
1. -viewDidUnload 已被弃用,实际上从 iOS6 及更高版本开始从未调用过。所以,如果你有你的清理代码,你的应用会在这些操作系统版本下泄漏
2。 -didReceiveMemoryWarning 可能会被调用多次或从不调用。因此,对于您在其他地方创建的对象进行平衡拆卸来说,这是一个非常糟糕的地方
我的答案是查看您使用属性的常见情况,例如:
@property (strong) UIView *myCustomView // <-- this is what I'm talking about
@property (assign) id *myDelegate
在这里您必须进行一些清理,因为您创建并拥有 customView 或 InterfaceBuilder 创建了它,但您保留了它。在 iOS 6 之前,您可能会这样做:
- (void)viewDidLoad {
self.myCustomView = [[UIView alloc] initWithFrame:…];
}
- (void)viewDidUnload { // <-- deprecated!
[myCustomView removeFromSuperView];
self.myCustomView = nil;
}
...因为(再次)myCustomView 是保留财产,由您创建和拥有,因此您必须小心并在最后“释放”它(将其设置为 nil)。
在 iOS 6 中,替换 -viewDidUnload 并将保留属性设置为 nil 的最佳位置可能是 -dealloc。还有viewWillAppear 和viewDidDisappear,但这些与视图/控制器的生命周期无关,而是显示周期(另一方面,-...appear 方法非常适合取消/注册通知侦听器!)。因此,在每次显示之前和之后创建和销毁视图可能并不合适。 dealloc 是我们唯一可以确定在控制器生命周期结束时调用的方法。请注意,如果您使用 ARC,则不得致电 [super dealloc]:
- (void)dealloc {
self.myCustomView = nil;
}
但是,如果您使用viewDidLoad 进行一些可以在内存不足的情况下释放的视图相关设置,那么其他显示如何处理内存不足情况的帖子是完全有效的。在这种情况下,您也可以使用 dealloc,但您必须检查您的视图是否仍然存在。
也许查看 ViewController 的一般生命周期也很有帮助:
这是视图控制器的生命周期(斜体表示这些方法可能会被多次调用):
- init:ViewController 已加载,尚无可用的界面元素 (IBOutlet)(全部为零)
- viewDidLoad:nib/storyboard 已经加载,所有对象都可用。用户什么都看不到
- viewWillAppear:即将显示视图
- viewDidAppear:视图在屏幕上
- viewWillDisappear:视图即将消失
- viewDidDisappear:视图刚刚从窗口中移除
- viewDidUnload:在 iOS6/7 中从不调用
- didReceiveMemoryWarning:您不知道是否、何时以及多久调用一次。在 iOS6 之前它可能会卸载视图,在 iOS6 之后它只是清除屏幕外缓存或什么都不做
- dealloc:viewController 即将被销毁
所以,总而言之,有多种可能性;现在去哪里真的取决于在哪里初始化了什么:
【讨论】:
viewWillAppear 可能更好地描述为“视图将(或可能)显示”,viewWillDisappear 最好描述为“视图将(或可能)被删除”。对于动态转换,我们不再保证viewWillAppear 后面会跟着viewDidAppear,也不能保证viewWillDisappear 后面会跟着viewDidDisappear。
myCustomView 示例中,我希望没有人这样做,因为这只是解决方案的一半:即使在iOS 5 中,他们也必须在@ 中执行release 的东西987654340@ 也是,因为 viewDidUnload 从未被称为“最后”,而只是在您推送/呈现另一个视图的内存压力下。 viewDidUnload 在您刚刚关闭控制器时从未被调用,仅在内存压力情况下。因此,他们不会将 release 的 myCustomView 转移到 dealloc,而是无论如何它都需要在那里。
dealloc 不会在任何对象(例如某种通知程序)持有对此 viewController 的强引用时被调用!
如果您需要知道您的 UIViewController 是否正在关闭,您可以将此代码添加到您的 viewWillDisappear:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self isBeingDismissed] || [self isMovingFromParentViewController])
{
// Do your viewDidUnload stuff
}
}
它不会与 viewDidUnload 在视图控制器生命周期中同时调用一次,但在大多数情况下可以满足您的需求!
【讨论】:
取决于您在viewDidUnload 中所做的事情,但您可以使用didReceiveMemoryWarning 或dealloc 来发布数据。见this。
【讨论】:
viewDidUnload 中的内容,但如果由于 iOS 6 有任何需要移动到 dealloc 的内容,我会感到震惊。通常,当我们使用一个视图控制器,然后关闭/弹出它,viewDidUnload 永远不会被调用(它只在内存不足的情况下使用),所以希望viewDidUnload 中没有例行清理,他们也不会在dealloc 中清理!如果有人用viewDidUnload 代替dealloc 做这种事情,那么他们手上的问题就更大了。
viewDidUnload 的目的。但是在回答您的问题时,是的,您可以在dealloc 中提供此类内容,但viewWillDisappear 可能更好。最重要的是,如果您的通信管理器保持对您的视图控制器的强引用,那么您绝对不应该尝试取消订阅dealloc(因为您将有一个强引用循环;dealloc 将永远不会被调用)。这类事情必须在其他地方完成,例如viewWillDisappear.
在大多数典型情况下,可以使用此方法代替旧的 viewDidUnload。
// The completion handler, if provided, will be invoked after the dismissed controller's viewDidDisappear: callback is invoked.
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion NS_AVAILABLE_IOS(5_0);
Swift 2017 语法:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
if (yourChildViewController != nil) {
print("good thing we did this!")
}
yourChildViewControllerProperty = nil
super.dismiss(animated: flag, completion: completion)
}
【讨论】: