我有一个名为MainViewController的ViewController,它充当应用程序的中心页面。这个MainViewController有6个属性,是其他viewControllers的实例
lazy var shelvesView: ShelvesViewController = {
return ShelvesViewController()
}()
lazy var goalsView: GoalsViewController = {
return GoalsViewController()
}()
lazy var shoppingView: ShoppingListViewController = {
return ShoppingListViewController()
}()
lazy var tipsView: TipsViewController = {
return TipsViewController()
}()
lazy var myDenView: MyDenViewController = {
return MyDenViewController()
}()
lazy var settingsview: SettingsViewController = {
return SettingsViewController()
}()
当mainViewController加载时,它开始于shelfViewController放置在mainViewControllers自定义NavBar下面,就像这样
func setupShelvesView() {
shelvesView.willMove(toParentViewController: self)
addChildViewController(shelvesView)
self.view.addSubview(shelvesView.view)
shelvesView.view.frame = CGRect(x: 0, y: view.frame.height * 0.08, width: view.frame.width, height: view.frame.height - (view.frame.height * 0.08))
shelvesView.didMove(toParentViewController: self)
globalCurrentView = 1
}
我还有一个菜单可以在这个mainViewController上滑动,其中包含用户可以导航到的不同页面的列表。当用户切换到新页面时,比如goalViewController,shelfViewController将在屏幕上显示动画,从parentViewController(MainViewController)中删除,goalViewController将被初始化,移动到MainViewController并在与屏幕视图相同的框架中动画显示。无论何时我从菜单中切换VC,我都会使用这种方法。
func changeVCfrom(OldVC oldVC: UIViewController, newVC: UIViewController) {
let newStartFrame = CGRect(x: 0 + self.view.frame.width, y: 0, width: view.frame.width, height: view.frame.height - (view.frame.height * 0.08))
let newEndframe = CGRect(x: 0, y: view.frame.height * 0.08, width: view.frame.width, height: view.frame.height - (view.frame.height * 0.08))
let oldfinishFrame = CGRect(x: 0 - self.view.frame.width, y: 0, width: self.view.frame.width, height: self.view.frame.height)
oldVC.willMove(toParentViewController: nil)
self.addChildViewController(newVC)
newVC.view.frame = newStartFrame
transition(from: oldVC, to: newVC, duration: 0.2, options: [.curveEaseOut], animations: {
oldVC.view.frame = oldfinishFrame
newVC.view.frame = newEndframe
}, completion: { (success) in
oldVC.willMove(toParentViewController: nil)
oldVC.view.removeFromSuperview()
oldVC.removeFromParentViewController()
newVC.willMove(toParentViewController: self)
self.view.addSubview(newVC.view)
})
}
这里的问题是我已经以编程方式完成了所有视图,并且任何上面有一个tableView属性的viewControllers(延迟属性)都有内存泄漏。任何时候VC离开MainViewController时,用于tableView的内存都没有被处理,并且只要它再次分配给MainViewController,就会再次分配更多的内存。
截至目前,这就是我如何设置我的tableViews
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
setupObjects()
tableView.register(ShelfTableViewCell.self, forCellReuseIdentifier: "shelfCell")
}
func setupTableView() {
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
setupTableViewConstraints()
}
func setupTableViewConstraints() {
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
}
我知道我需要将我的tableviews设置为弱,无主或以某种方式让tableview在屏幕外完全取消分配。但无论我尝试什么,我得到的错误遍布我无法解决的地方或我的ViewController无法加载tableview。我为这个冗长的问题道歉,但对此的任何帮助都将非常感激。
答案 0 :(得分:0)
当您的子视图控制器离开屏幕时,表视图不会被取消分配。
您的MainViewController拥有其他视图控制器。是的,他们很懒,但是一旦他们第一次被召唤,他们就会被他们拥有的表格一起初始化。
只需在屏幕外移动子视图控制器即可解除分配。您所做的只是更改框架并将其作为MainViewController的子视图控制器删除。由于它们仍然在内存中,因此表视图仍然在内存中。
如果你真的想在每次控制器离开屏幕时解除分配表格视图,你可以设置
self.tableView = nil
这里不应该有一个保留周期,因为tableView的数据源和委托属性是weak
,这意味着它们不会增加视图控制器的引用计数。
答案 1 :(得分:0)
在桌面上上下滚动时,我的内存会急剧上升。结果我设置了dequeReusableCell错误。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ShelfTableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: "shelfCell")
tableView.dequeueReusableCell(withIdentifier: "shelfCell", for: indexPath)
if let shelf = UserController.shared.user?.shelves?[indexPath.row] as? Shelf {
cell.shelf = shelf
return cell
} else {
return UITableViewCell()
}
}
基本上发生的事情是每次点击viewWillAppear时我都会重新加载运行此代码的tableViewData
let cell = ShelfTableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: "shelfCell")
tableView.dequeueReusableCell(withIdentifier: "shelfCell", for: indexPath)
导致内存泄漏
用以下代码替换上面的代码解决了问题
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "shelfCell", for: indexPath) as! ShelfTableViewCell
if let shelf = UserController.shared.user?.shelves?[indexPath.row] as? Shelf {
cell.shelf = shelf
return cell
} else {
return UITableViewCell()
}
}