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:
Instruments show "_NSContiguousstring" memory leak when scrolling UITableView
- UILabel and memory leak
- Generating UILabel inside a UIView / Memory leak
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.
First setting
won't remove or make the label text nil as the label already took a copy of it
second setting
is not enough you have to
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.
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:
Change
var label: UILabel?
tovar label: MyLabel?
And
label = UILabel()
tolabel = 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: