首页 > 解决方案 > 是什么导致 UIPageViewController 中的内存泄漏?

问题描述

我正在开发的新应用程序中遇到一些内存泄漏。内存泄漏在启动应用程序后不久就开始了,Xcode 泄漏指向 UIPageviewController 中 viewDidLoad 中的 SetViewControllers 方法。我一直无法弄清楚确切的原因是什么。

这是 UIPageViewController 的代码:

import UIKit

class OnboardingPageViewController: UIPageViewController, UIPageViewControllerDataSource {


    // Create viewcontroller array for pageview

    lazy var availableViewControllers: [UIViewController] = [vcOne, vcTwo, vcThree]


    lazy var vcOne: UIViewController = storyboard!.instantiateViewController(withIdentifier: "onboardingOne")

    lazy var vcTwo: UIViewController = storyboard!.instantiateViewController(withIdentifier: "onboardingTwo")

    lazy var vcThree: UIViewController = storyboard!.instantiateViewController(withIdentifier: "onboardingThree")


    deinit{
        print("ONBOARDING PAGEVIEW DEALLOCATED")
    }

    override func viewDidLoad() {
        super.viewDidLoad()


        dataSource = self

        unowned let firstVc = availableViewControllers[0]


        setViewControllers([firstVc], direction: .forward, animated: true, completion: nil)


    }



    // Func to create new viewController

    func newVc(_ viewControllerId: String) -> UIViewController{
    unowned let vc = storyboard!.instantiateViewController(withIdentifier: viewControllerId)
        return vc

    }


    // UIPageviewControllerDataSource protocol funcs

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let vcIndex = availableViewControllers.firstIndex(of: viewController) else {return nil}

        let previousVc = vcIndex - 1

        guard previousVc >= 0 else {return nil}

        guard availableViewControllers.count > previousVc else {return nil}

        return availableViewControllers[previousVc]
    }


    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let vcIndex = availableViewControllers.firstIndex(of: viewController) else {return nil}

        let nextVc = vcIndex + 1

        guard nextVc < availableViewControllers.count else {return nil}

        guard availableViewControllers.count > nextVc else {return nil}

        return availableViewControllers[nextVc]
    }
}

viewControllers 被声明为惰性变量,但我最初使用 newVc 函数在 availableViewControllers 数组中创建视图控制器。改后漏水无变化。

滚动页面后,内存泄漏增加了 100 多个新的。

每个 viewController 在情节提要中仅包含一个 ImageView。

我稍后在应用程序中有另一个 UIPageViewController 使用相同的逻辑,并且基于第一个的行为,它很可能也导致一些后来的应用程序泄漏。

编辑:数据源移动到父 vc。Edit2:数据源更改为 [String]

class LoginViewController: UIViewController, FUIAuthDelegate, UIPageViewControllerDataSource {

@IBOutlet weak var loginButton: UIButton!

//  lazy var db = Firestore.firestore()
//  lazy var uid = Auth.auth().currentUser!.uid


// let notice = Notice()
// unowned let appDelegate = UIApplication.shared.delegate as! AppDelegate

@IBOutlet weak var containerView: UIView!

// lazy var availableViewControllers: [UIViewController] = {[newVc("onboardingOne"), newVc("onboardingTwo"), newVc("onboardingThree")]}()

var availableViewControllers: [String] = ["onboardingOne", "onboardingTwo", "onboardingThree"]

weak var pvc: UIPageViewController!



deinit {
    print("LOGINVIEW Deinit RAN")
}



override func viewDidLoad() {
    super.viewDidLoad()

    let pvc = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
    pvc.dataSource = self
    self.addChild(pvc)
    self.containerView.addSubview(pvc.view)

    pvc.view.frame = CGRect(x: 0, y: 0, width: containerView.frame.width, height: containerView.frame.height)

    unowned let firstVc = storyboard!.instantiateViewController(withIdentifier: availableViewControllers[0])

    pvc.setViewControllers([firstVc], direction: .forward, animated: true, completion: nil)

    self.pvc = pvc

   // setupLoginButton()


  }

// Modify login/register Button

func setupLoginButton() {
    loginButton.layer.borderWidth = 0
    loginButton.layer.cornerRadius = 25
    loginButton.layer.shadowColor = UIColor.lightGray.cgColor
    loginButton.layer.shadowOffset = CGSize(width: 0, height: 4)
    loginButton.layer.shadowOpacity = 0.9

    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [UIColor.blue.cgColor, UIColor.init(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)]
    gradientLayer.startPoint = CGPoint(x: 0, y: 0)
    gradientLayer.endPoint = CGPoint(x: 1, y: 0)
    gradientLayer.frame = loginButton.bounds
    gradientLayer.cornerRadius = 25
    loginButton.layer.addSublayer(gradientLayer)
}

func newVc(_ viewControllerId: String) -> UIViewController{
    unowned let vc = storyboard!.instantiateViewController(withIdentifier: viewControllerId)
    return vc

}

// Login/register button pressed

@IBAction func loginButtonTouched(_ sender: Any) {

  /*  if appDelegate.connected == false {

        present(notice.networkAlert, animated: true, completion: nil)

    }

    else { */

    //Setup and get FirebaseUI for login/register (and set delegate)

    let authUI = FUIAuth.defaultAuthUI()
    let authViewController = authUI?.authViewController()
    authUI?.delegate = self

    // Present FirebaseUI

    present(authViewController!, animated: true, completion: nil)

 //   }
}


// Handle Firebase Auth result

func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {

    //Show error if one appeared

    guard error == nil else {
        print(error!.localizedDescription)
        return
    }

    // Make sure Authdataresult exists

    guard authDataResult != nil else { return }


    // Move to main screen with logged in user




}

// UIPageviewControllerDataSource protocol funcs

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
    guard let vcIndex = availableViewControllers.firstIndex(of: viewController.restorationIdentifier!) else {return nil}

    let previousVc = vcIndex - 1

    guard previousVc >= 0 else {return nil}

    guard availableViewControllers.count > previousVc else {return nil}

    return storyboard!.instantiateViewController(withIdentifier: availableViewControllers[previousVc])
}


func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
    guard let vcIndex = availableViewControllers.firstIndex(of: viewController.restorationIdentifier!) else {return nil}

    let nextVc = vcIndex + 1

    guard nextVc < availableViewControllers.count else {return nil}

    guard availableViewControllers.count > nextVc else {return nil}

    return storyboard!.instantiateViewController(withIdentifier: availableViewControllers[nextVc])
}

}

标签: iosswiftmemory-leaksuipageviewcontroller

解决方案


推荐阅读