将文本分配给UILabel(iOS,Swift 4,Xcode 9)时内存泄漏

时间:2018-05-12 13:20:14

标签: ios swift memory-leaks uilabel

我一直在开发一款没有故事板的新应用。一切顺利,直到我用仪器测试我的应用程序:每次我将一个字符串分配给标签时它就泄露了。当我使用故事板时,我没有那样的泄漏。

我已阅读以下资源以找到答案:

最流行的观点是,这是一个仪器bug,但对我来说它看起来是一个太明显的方法。

泄漏在空的应用程序中重现。在根视图控制器中:

class ViewController: UIViewController {

var label: UILabel?

override func viewDidLoad() {
    super.viewDidLoad()

    label = UILabel()
    view.addSubview(label!)
    var textForLabel: String? = "Hello"
    label?.text = textForLabel

    //attempt to free the memory
    textForLabel = nil
    label = nil

    //EDIT: added after @J.Doe and @Sh-Khan answers, but it's still leaking
    label.removeFromSuperview()

   }
}

在真实设备上的Instruments中测试此应用程序(iPhone SE 11.2)时,我看到以下内容:

enter image description here

当我点击_NSContiguousString时,我发现内存泄漏出现在[UILabel setText:]中。

enter image description here

我尝试将标签设置为弱,但是当我尝试将其添加为子视图时它变为零。

所以,我的问题是:

  • 我现在和将来如何消除这种内存泄漏?
  • 我应该仅在.xib / .storyboard文件中创建UI元素吗?

我是iOS开发的新手,所以我认为我错过了一些明显的东西。我将非常感谢任何帮助或建议。

编辑:根据@Sh-Khan@J.Doe的答案(非常感谢你们!),我添加了label.removeFromSuperview(),但仍有泄漏。

EDIT2:在@ J.Doe的帮助下,我了解到UILabel通过调用removeFromSuperview从内存中释放并在之后将其设置为nil。仪器中的内存泄漏仍然存在,但我接受了他的回答,因为这是我想知道的。

PS:在阅读了NSString retain count后,我认为内存泄漏的原因可能是我使用的字符串文字无法释放,根据讨论。

2 个答案:

答案 0 :(得分:2)

也许我错了,但我想这个:

弱不会增加参考计数器。因此,将对象标签分配给弱var标签是没有意义的。这是因为弱var标签将为nil,因为您创建的对象没有任何引用(因此它将取消初始化)

让我们计算您的代码中有多少引用到您创建的对象标签。

label = UILabel() // 1
view.addSubview(label!) // 2
var textForLabel: String? = "Hello"
label?.text = textForLabel

//attempt to free the memory
textForLabel = nil
label = nil // 1

您的视图中有1个引用到您的对象标签。在执行label = nil之前,请调用label?.removeFromSuperview()。我想比你有0个参考 - >它会消失。

编辑:

将UILabel的以下子类添加到您的代码中:

class MyLabel: UILabel {
    deinit {
        print("I am gone!")
    }
}

var label: UILabel?更改为var label: MyLabel?

label = UILabel()label = MyLabel()

并查看日志。你看到印刷品“我走了!”?

Edit2:打印出“我走了!”在一个空项目中,仅将其作为代码:

import UIKit

class ViewController: UIViewController {

    var label: MyLabel?

    override func viewDidLoad() {
        super.viewDidLoad()

        label = MyLabel()
        view.addSubview(label!)
        let textForLabel: String? = "Hello"
        label?.text = textForLabel

        //EDIT: added after @J.Doe and @Sh-Khan answers, but it's still leaking
        label?.removeFromSuperview()
        label = nil


    }
}

class MyLabel: UILabel {
    deinit {
        print("I am gone!")
    }
}

答案 1 :(得分:1)

首先设置

textForLabel = nil

不会删除或标签文字为零,因为标签已经带有副本

第二次设置

label = nil 

是不够的

label.removeFromSuperview()