问题描述
我有一个由10个元素组成的UItableView.我打开仪器来捕获内存泄漏,并在滚动tableView时开始出现内存泄漏.在仪器"中,我试图找出导致泄漏的原因,但无法弄清楚,它对整个泄漏都说"_NScontiguousstring".
I have a UItableView which consist of 10 element. I opened Instruments to catch the memory leaks and when I scroll tableView, It started to give memory leaks. In Instruments I tried to find which causes the leaks but can't figure out, It says "_NScontiguousstring" for whole leaks.
我找到了一些Objective-C解决方案,它们在"CellForRowAt"函数中检查单元格是否为零.我认为这对Swift没用,但是我尝试了,并且按预期进行了.
I found some solutions for Objective-C which they check If cell is nil in "CellForRowAt" function. I don't think it is useful for Swift but I tried and as expected It doesn't work.
我的问题是什么会导致这种内存泄漏?
My question is what can cause this kind of memory leak?
我测试过的设备;
11.3.1上的iPhone X
iPhone X on 11.3.1
iPhone 6 11.2.5控制器类;
iPhone 6 11.2.5Controller Class;
class TableViewController: UITableViewController {
let teamModel = TeamModel(uid: "adsada", name: "First Team ", idea: "idea 1", slogan: "Slogan 1", university: "dasda", image: "info", isActive: true)
let teamModel2 = TeamModel(uid: "adsada", name: "Team 2", idea: "idea 2", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel3 = TeamModel(uid: "adsada", name: "Team 3", idea: "idea 3", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel4 = TeamModel(uid: "adsada", name: "Team 4", idea: "idea 4", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel5 = TeamModel(uid: "adsada", name: "Team 5", idea: "idea 5", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel6 = TeamModel(uid: "adsada", name: "Team 6", idea: "idea 6", slogan: "adasd", university: "dasda", image: "info", isActive: true)
let teamModel7 = TeamModel(uid: "adsada", name: "Team 7", idea: "idea 7", slogan: "adasd", university: "dasda", image: "info", isActive: true)
var data: [TeamModel] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(mainTableCell.self, forCellReuseIdentifier: "mainTableCell")
data = [teamModel,teamModel2,teamModel3,teamModel4,teamModel5,teamModel6,teamModel7]
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mainTableCell", for: indexPath) as! mainTableCell
let cell_data = data[indexPath.row]
cell.cell_data = cell_data
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
}
单元格类;
class mainTableCell: UITableViewCell{
var cell_data: TeamModel?{
didSet{
guard let unwrappedCell = cell_data else { return }
if let url = unwrappedCell.imageURL{
profileImage.image = UIImage(named: "info")
} else{
self.profileImage.image = UIImage(named: "info")
}
self.teamLbl.text = unwrappedCell.name
mainBackground.backgroundColor = UIColor.gray
}
}
let mainBackground: UIView = {
let v = UIView()
v.layer.cornerRadius = 8
v.layer.masksToBounds = true
return v
}()
var isVoteable: Bool = false
//let shadowView = ShadowView()
let profileImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.layer.masksToBounds = true
return imageView
}()
let teamLbl: UILabel = {
let label = UILabel()
label.textColor = UIColor.black
label.numberOfLines = 1
label.adjustsFontSizeToFitWidth = true
return label
}()
let myVoteLbl: UILabel = {
let l = UILabel()
l.text = "Oyum: --"
return l
}()
let voteBtn: UIButton = {
let b = UIButton(type: .custom)
b.setImage(UIImage(named: "info"), for: .normal)
return b
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
func setupViews() {
self.backgroundColor = UIColor.white
self.mainBackground.addSubview(profileImage)
self.mainBackground.addSubview(teamLbl)
self.mainBackground.addSubview(voteBtn)
self.mainBackground.addSubview(myVoteLbl)
//self.addSubview(shadowView)
self.addSubview(mainBackground)
self.backgroundColor = UIColor.clear
profileImage.translatesAutoresizingMaskIntoConstraints = false
teamLbl.translatesAutoresizingMaskIntoConstraints = false
voteBtn.translatesAutoresizingMaskIntoConstraints = false
myVoteLbl.translatesAutoresizingMaskIntoConstraints = false
mainBackground.translatesAutoresizingMaskIntoConstraints = false
//shadowView.translatesAutoresizingMaskIntoConstraints = false
}
override func layoutSubviews() {
super.layoutSubviews()
// self.setCircularImageView()
mainBackground.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 10, leftConstant: 10, bottomConstant: 10, rightConstant: 10, widthConstant: 0, heightConstant: 0)
// shadowView.anchor(self.topAnchor, left: self.leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: 0, heightConstant: 0)
profileImage.anchor(nil, left: self.mainBackground.leftAnchor, bottom: nil, right: nil, topConstant: 0, leftConstant: 10, bottomConstant: 0, rightConstant: 0, widthConstant: 60, heightConstant: 60)
profileImage.anchorCenterYToSuperview()
teamLbl.anchor(self.mainBackground.topAnchor, left: profileImage.rightAnchor, bottom: nil, right: self.voteBtn.leftAnchor, topConstant: 20, leftConstant: 20, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 40)
myVoteLbl.anchor(nil, left: profileImage.rightAnchor, bottom: self.mainBackground.bottomAnchor, right: nil, topConstant: 0, leftConstant: 20, bottomConstant: 20, rightConstant: 0, widthConstant: 0, heightConstant: 0)
voteBtn.anchor(nil, left: nil, bottom: nil, right: self.mainBackground.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 80, heightConstant: 80)
voteBtn.anchorCenterYToSuperview()
}
func setCircularImageView() {
self.profileImage.layer.cornerRadius = CGFloat(roundf(Float(self.profileImage.frame.size.width / 2.0)))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
我在下面的答案中添加了prepareForReuse方法,但是现在单元格仅显示白色.难道我做错了什么?
I add prepareForReuse method regarding to below answer but now cells show just white. Am I doing something wrong?
override func prepareForReuse() {
super.prepareForReuse()
teamLbl.text = ""
myVoteLbl.text = ""
profileImage.image = nil
}
我还使cell_data变量为"weak var cell_data:TeamModel?",并在prepareForReuse()方法中将其无效,但是仍然有相同的泄漏发生.
I also make cell_data variable "weak var cell_data: TeamModel? and nil it in prepareForReuse() method but still same leaks are coming.
完整项目;
https://github.com/emreond/TableView-Memory-Leak-Project
我发现,当我添加if检查并更改cell_data的didst内部的属性时,某些单元格视图看上去已损坏.例如,当我更改cell_data内的teamLbl文本颜色时.在某些单元格中,它看起来很破损.
EDIT 3: I found that when I add If check and change attributes inside didst of cell_data, some cells views look ruined. For example when I change teamLbl text color inside cell_data. In some cells, It looks ruined.
当我评论锚代码以参考@Darp的答案进行检查时,(我在屏幕上看不到任何东西,也没有任何约束)它仍然继续泄漏.
EDIT 4: When I comment anchor codes to check with reference of @Darp's answer,(I don't have anything seen on screen and don't have any constraint) It still continue to give leak.
我仍在处理此泄漏,但找不到任何解决方案.实际上,当我在屏幕上查看tableView时看到内存中的内容时,我发现内存中只有8个单元格看起来很正确.
EDIT 5: I'm still working on this leak but can't find any solution. Actually when I look what is in memory when tableView is on screen, I see that only 8 cell is on memory which looks like correct.
推荐答案
我对_NSContiguousString
有相同的问题.即使在只有一个标签的空应用程序中,它也显示48个字节的泄漏.
I have the same problem with _NSContiguousString
. Even in an empty application with just one label, it shows a leak of 48 bytes.
我不确定,但是我猜测泄漏的原因可能是与NSString桥接(我在堆栈跟踪的顶部也看到了[_SwiftNativeNSStringBase retain]
.)
I am not sure, but I have a guess that the reason for leaking might be bridging with NSString (I see also [_SwiftNativeNSStringBase retain]
on the top of the stack trace).
我发现NSString本身可能被视为作为泄漏对象由Instruments提出,因为它已被实现为Singleton.
I've found out that NSString itself might be considered as a leaking object by the Instruments because it has been implemented as a Singleton.
我自己的问题在这里:将文本分配给UILabel(iOS,Swift 4,XCode9)时出现内存泄漏
My own question is here: Memory leaks when assigning text to UILabel (iOS, Swift 4, XCode9)
这篇关于仪器显示"_NSContiguousstring";滚动UITableView时发生内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!