【发布时间】:2016-11-15 17:02:14
【问题描述】:
我已经在Swift 编程了几个月了。最近,我更加关注Swift 作为一种语言的工作原理。
因此,最近在阅读apple documentation on Automatic Reference Counting(ARC) 时,我遇到了以下几行:
这个在上面:
在大多数情况下,这意味着内存管理在 Swift 中“正常工作”,您不需要自己考虑内存管理。当不再需要类实例时,ARC 会自动释放这些实例使用的内存。
在下一段中,以下内容:
为了实现这一点,每当您将类实例分配给属性、常量或变量时,该属性、常量或变量都会对该实例进行强引用。该引用被称为“强”引用,因为它牢牢控制该实例,并且只要该强引用仍然存在,就不允许释放它。
我对这种情况的动态有些困惑。我在使用情节提要时注意到,您设置了对弱的引用,因此该类看起来像这样,我也称之为案例 1:
案例 1
class SomeClass : UIViewController {
@IBOutlet weak var nameLabel : UILabel!
override func viewDidLoad() {
nameLabel.text = "something."
}
}
这里,标签与 ViewController 是一对一的弱引用,一旦 Controller 改变,引用就会被破坏(内存释放),因为它是弱的。因此,没有与内存相关的问题。
如果上述陈述是错误的或松散的,请原谅我。如果有人证实或反驳我的假设,我会很高兴。
我的问题是关于第二种情况,我不使用情节提要,类如下所示:
案例 2
class SomeClass : UIViewController {
var nameLabel : UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
view.addSubView(nameLabel)
// view.addConstraints...
}
}
对于上面的情况,我的假设是ViewController和label有一对一的强引用,ViewController里面的view也和label有强引用。如果class改变/label被移除subview ..那么我认为内存不会被释放。或者至少视图控制器将保持对标签的强引用(根据文档)。
我通过从视图的子视图中删除标签并打印出标签来确认这一点(它给了我一个 UILabel 实例,其框架为 0 原点和 0 大小。)因此一个实例不是 nil。
我能从中收集到的唯一信息是,虽然标签已从 UIView 中删除,但它仍然保持与控制器的强引用,因此在内存中处于永久状态。我说的对吗?
如果是这样的话。我应该如何防止我的代码出现此类内存问题?更大的问题是,如果我像这样声明我的变量,我会在将它添加为控制器中主视图的子视图时得到一个 nil。
weak var nameLabel : UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
如果像第二种情况那样声明变量会导致永久强引用,我应该如何声明它们而不是出现内存问题?
总之,我的问题是:
如果没有使用storyboard outlet,并且变量被强引用到视图控制器,这些引用会导致内存问题吗?
如果是这样,我必须关注什么code declaration practice?
如果不是这样,请提供深思熟虑的论据和有效的解释来反驳它。
再次,如果我在任何地方不正确,请原谅我。
提前谢谢你。
【问题讨论】:
-
最佳实践问题通常不适合 Stack Overflow,因为答案只能基于意见,而不是事实。
-
@JAL 这个问题是具体的,并要求对上述问题的最佳解决方案,这个问题并不要求回答者从几个备选方案中提供最佳解决方案。但是我已经编辑了标题。
-
使用对 IBOutlets 的强引用意味着如果从 superview 中删除它们,它们仍将保留。这是否是一个问题取决于应用程序的要求。如果您有一些从层次结构中删除的视图,并且您需要保留一个引用以便以后重用它,那么它应该是一个强引用。另一方面,如果您希望视图在从视图中删除时被释放,那么引用应该是弱的。这与任何其他变量完全相同。
标签: ios swift memory-management automatic-ref-counting