将文本分配给UILabel(iOS,Swift 4,XCode9)时内存泄漏 [英] Memory leaks when assigning text to UILabel (iOS, Swift 4, XCode9)

查看:209
本文介绍了将文本分配给UILabel(iOS,Swift 4,XCode9)时内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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






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





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



    所以,我的问题是:




    • 如何消除此内存泄漏现在和未来?

    • 我应该仅在.xib / .storyboard文件中创建UI元素吗?



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



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



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



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

    解决方案

    也许我错了,但我认为:



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



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

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

    //尝试释放内存
    textForLabel = nil
    label = nil // 1

    您的视图中有1个引用到您的对象标签。在你做label = nil之前,调用label?.removeFromSuperview()。我想比你有0个引用 - >它会去掉。



    编辑:



    添加UILabel的下面的子类进入你的代码:

      class MyLabel:UILabel {
    deinit {
    print(我走了! )
    }
    }

    更改 var label :UILabel? var标签:MyLabel?





    label = UILabel() label = MyLabel()



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



    Edit2:打印出我走了!在一个空的项目中只有代码:

      import UIKit 

    class ViewController:UIViewController {

    var标签:MyLabel?

    覆盖func viewDidLoad(){
    super.viewDidLoad()

    label = MyLabel()
    view.addSubview(label!)
    让textForLabel:String? =你好
    标签?.text = textForLabel

    //编辑:在@ J.Doe和@ Sh-Khan回答之后添加,但它仍在泄漏
    标签? removeFromSuperview()
    label = nil


    }
    }

    class MyLabel:UILabel {
    deinit {
    打印(我走了!)
    }
    }


    I've been working on a new app with no storyboard. All went fine until I tested my application with Instruments: it leaked every time I assigned a string to a label. When I worked with a storyboard, I didn't have leaks like that.

    I have read the following resources to find the answer:

    The most popular opinion is that is an Instruments bug, but it looks like a too obvious approach to me.

    The leak reproduces in an empty application. In the root view controller:

    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()
    
       }
    }
    

    While testing this app in Instruments on a real device (iPhone SE 11.2) I see the following:

    When I click on _NSContiguousString, I see that memory leak appears in [UILabel setText:].

    I tried to set label as weak, but then it becomes nil when I try to add it as a subview.

    So, my questions are:

    • how I can eliminate this memory leak now and in the future?
    • should I create UI elements only in .xib/.storyboard files for that reason?

    I am new to iOS development, so I think that I'm missing something obvious. I will highly appreciate any help or advice.

    EDIT: According to @Sh-Khan and @J.Doe answers (thank you guys so much!), I added label.removeFromSuperview(), but there is still a leak.

    EDIT2: With @J.Doe help, I learned that UILabel gets released from memory by calling removeFromSuperview and setting it to nil afterwards. The memory leak in Instruments remained, but I mark his answer accepted because that's what I wanted to know.

    PS: After reading about NSString retain count I think the reason of memory leak might be the fact I am using a string literal that cannot be released, according to the discussion.

    解决方案

    Maybe I am wrong, but I think this:

    Weak will not increase the reference counter. Therefore, assigning a object label to a weak var label, does not make sense. This is because weak var label will be nil, because the object you created does not have any reference (and therefore it will deinitialize)

    Let's count how many reference you have in your code to your created object Label.

    label = UILabel() // 1
    view.addSubview(label!) // 2
    var textForLabel: String? = "Hello"
    label?.text = textForLabel
    
    //attempt to free the memory
    textForLabel = nil
    label = nil // 1
    

    You have 1 reference left in your view to your object Label. Before you do label = nil, call label?.removeFromSuperview(). I think than you have 0 references -> it will deinit.

    edit:

    Add below subclass of UILabel into your code:

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

    Change var label: UILabel? to var label: MyLabel?

    And

    label = UILabel() to label = MyLabel()

    And check to logs. Do you see the print "I am gone!"?

    Edit2: this prints "I am gone!" in a empty project with this only as code:

    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!")
        }
    }
    

    这篇关于将文本分配给UILabel(iOS,Swift 4,XCode9)时内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆