瀏覽代碼

Merge pull request #655 from deltachat/memory-leak-buster

Memory leak buster
bjoern 5 年之前
父節點
當前提交
c87f3e2e31

+ 4 - 12
deltachat-ios/Controller/AccountSetupController.swift

@@ -73,16 +73,7 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
 
 
     // MARK: - the progress dialog
     // MARK: - the progress dialog
 
 
-    lazy var progressAlert: UIAlertController = {
-        let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
-        alert.addAction(UIAlertAction(
-            title: String.localized("cancel"),
-            style: .cancel,
-            handler: { _ in
-                self.dcContext.stopOngoingProcess()
-        }))
-        return alert
-    }()
+    weak var progressAlert: UIAlertController?
 
 
     // MARK: - cells
     // MARK: - cells
 
 
@@ -379,6 +370,7 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
 
 
     override func viewWillDisappear(_ animated: Bool) {
     override func viewWillDisappear(_ animated: Bool) {
         resignFirstResponderOnAllCells()
         resignFirstResponderOnAllCells()
+        configureProgressObserver = nil
     }
     }
 
 
     override func viewDidDisappear(_: Bool) {
     override func viewDidDisappear(_: Bool) {
@@ -590,7 +582,7 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
 
 
         print("oAuth-Flag when loggin in: \(dcContext.getAuthFlags())")
         print("oAuth-Flag when loggin in: \(dcContext.getAuthFlags())")
         dcContext.configure()
         dcContext.configure()
-        showProgressAlert(title: String.localized("login_header"))
+        showProgressAlert(title: String.localized("login_header"), dcContext: dcContext)
     }
     }
 
 
     @objc func closeButtonPressed() {
     @objc func closeButtonPressed() {
@@ -735,7 +727,7 @@ class AccountSetupController: UITableViewController, ProgressAlertHandler {
 
 
             if let file = dcContext.imexHasBackup(filePath: documents[0]) {
             if let file = dcContext.imexHasBackup(filePath: documents[0]) {
                 logger.info("restoring backup: \(file)")
                 logger.info("restoring backup: \(file)")
-                showProgressAlert(title: String.localized("import_backup_title"))
+                showProgressAlert(title: String.localized("import_backup_title"), dcContext: dcContext)
                 dcContext.imex(what: DC_IMEX_IMPORT_BACKUP, directory: file)
                 dcContext.imex(what: DC_IMEX_IMPORT_BACKUP, directory: file)
             }
             }
             else {
             else {

+ 3 - 1
deltachat-ios/Controller/EditSettingsController.swift

@@ -62,7 +62,9 @@ class EditSettingsController: UITableViewController, MediaPickerDelegate {
     override func viewDidLoad() {
     override func viewDidLoad() {
         super.viewDidLoad()
         super.viewDidLoad()
         title = String.localized("pref_profile_info_headline")
         title = String.localized("pref_profile_info_headline")
-        avatarSelectionCell.onAvatarTapped = onAvatarTapped
+        avatarSelectionCell.onAvatarTapped = { [unowned self] in
+            self.onAvatarTapped()
+        }
     }
     }
 
 
     override func viewWillDisappear(_ animated: Bool) {
     override func viewWillDisappear(_ animated: Bool) {

+ 0 - 1
deltachat-ios/Controller/QrCodeReaderController.swift

@@ -28,7 +28,6 @@ class QrCodeReaderController: UIViewController {
         return UIBarButtonItem(title: String.localized("cancel"), style: .done, target: self, action: #selector(closeButtonPressed(_:)))
         return UIBarButtonItem(title: String.localized("cancel"), style: .done, target: self, action: #selector(closeButtonPressed(_:)))
     }()
     }()
 
 
-
     private let supportedCodeTypes = [
     private let supportedCodeTypes = [
         AVMetadataObject.ObjectType.qr
         AVMetadataObject.ObjectType.qr
     ]
     ]

+ 35 - 40
deltachat-ios/Controller/WelcomeViewController.swift

@@ -17,40 +17,19 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
 
 
     private lazy var welcomeView: WelcomeContentView = {
     private lazy var welcomeView: WelcomeContentView = {
         let view = WelcomeContentView()
         let view = WelcomeContentView()
-        view.onLogin = {
-            [unowned self] in
+        view.onLogin = { [unowned self] in
             self.coordinator?.presentLogin()
             self.coordinator?.presentLogin()
         }
         }
-        view.onScanQRCode = {
-            [unowned self] in
+        view.onScanQRCode  = { [unowned self] in
             self.showQRReader()
             self.showQRReader()
         }
         }
         view.translatesAutoresizingMaskIntoConstraints = false
         view.translatesAutoresizingMaskIntoConstraints = false
         return view
         return view
     }()
     }()
 
 
-    private lazy var qrCordeReader: QrCodeReaderController = {
-        let controller = QrCodeReaderController()
-        controller.delegate = self
-        return controller
-    }()
-
-    private lazy var qrCodeReaderNav: UINavigationController = {
-        let nav = UINavigationController(rootViewController: qrCordeReader)
-        nav.modalPresentationStyle = .fullScreen
-        return nav
-    }()
-
-    lazy var progressAlert: UIAlertController = {
-        let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
-        alert.addAction(UIAlertAction(
-            title: String.localized("cancel"),
-            style: .cancel,
-            handler: { _ in
-                self.dcContext.stopOngoingProcess()
-        }))
-        return alert
-    }()
+    private var qrCodeReader: QrCodeReaderController?
+    private var qrCodeReaderNav: UINavigationController?
+    weak var progressAlert: UIAlertController?
 
 
     init(dcContext: DcContext) {
     init(dcContext: DcContext) {
         self.dcContext = dcContext
         self.dcContext = dcContext
@@ -59,7 +38,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
             self.coordinator?.handleQRAccountCreationSuccess()
             self.coordinator?.handleQRAccountCreationSuccess()
         }
         }
     }
     }
-    
+
     required init?(coder: NSCoder) {
     required init?(coder: NSCoder) {
         fatalError("init(coder:) has not been implemented")
         fatalError("init(coder:) has not been implemented")
     }
     }
@@ -83,9 +62,9 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
 
 
     override func viewDidDisappear(_ animated: Bool) {
     override func viewDidDisappear(_ animated: Bool) {
         let nc = NotificationCenter.default
         let nc = NotificationCenter.default
-
         if let configureProgressObserver = self.configureProgressObserver {
         if let configureProgressObserver = self.configureProgressObserver {
             nc.removeObserver(configureProgressObserver)
             nc.removeObserver(configureProgressObserver)
+            self.configureProgressObserver = nil
         }
         }
     }
     }
 
 
@@ -113,12 +92,22 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         frameGuide.widthAnchor.constraint(equalTo: contentGuide.widthAnchor).isActive = true
         frameGuide.widthAnchor.constraint(equalTo: contentGuide.widthAnchor).isActive = true
     }
     }
 
 
+    // MARK: - factory
+    private func makeQRReader() -> QrCodeReaderController {
+        let controller = QrCodeReaderController()
+        controller.delegate = self
+        return controller
+    }
+
     // MARK: - actions
     // MARK: - actions
 
 
-    private func showQRReader(completion onComplete: VoidFunction? = nil) {
-        present(qrCodeReaderNav, animated: true) {
-            onComplete?()
-        }
+    private func showQRReader() {
+        let qrReader = makeQRReader()
+        self.qrCodeReader = qrReader
+        let nav = UINavigationController(rootViewController: qrReader)
+        nav.modalPresentationStyle = .fullScreen
+        self.qrCodeReaderNav = nav
+        present(nav, animated: true)
     }
     }
 
 
     private func createAccountFromQRCode() {
     private func createAccountFromQRCode() {
@@ -129,7 +118,7 @@ class WelcomeViewController: UIViewController, ProgressAlertHandler {
         scannedQrCode = nil
         scannedQrCode = nil
         if success {
         if success {
             addProgressAlertListener(onSuccess: handleLoginSuccess)
             addProgressAlertListener(onSuccess: handleLoginSuccess)
-            showProgressAlert(title: String.localized("login_header"))
+            showProgressAlert(title: String.localized("login_header"), dcContext: dcContext)
             dcContext.configure()
             dcContext.configure()
         } else {
         } else {
             accountCreationErrorAlert()
             accountCreationErrorAlert()
@@ -167,7 +156,7 @@ extension WelcomeViewController: QrCodeReaderDelegate {
             title: String.localized("ok"),
             title: String.localized("ok"),
             style: .default,
             style: .default,
             handler: { [unowned self] _ in
             handler: { [unowned self] _ in
-                self.qrCodeReaderNav.dismiss(animated: false)
+                self.dismissQRReader()
                 self.createAccountFromQRCode()
                 self.createAccountFromQRCode()
             }
             }
         )
         )
@@ -176,15 +165,13 @@ extension WelcomeViewController: QrCodeReaderDelegate {
             title: String.localized("cancel"),
             title: String.localized("cancel"),
             style: .cancel,
             style: .cancel,
             handler: { [unowned self] _ in
             handler: { [unowned self] _ in
-                self.qrCodeReaderNav.dismiss(animated: true) {
-                    self.scannedQrCode = nil
-                }
+                self.dismissQRReader()
             }
             }
         )
         )
 
 
         alert.addAction(okAction)
         alert.addAction(okAction)
         alert.addAction(qrCancelAction)
         alert.addAction(qrCancelAction)
-        qrCodeReaderNav.present(alert, animated: true)
+        qrCodeReaderNav?.present(alert, animated: true)
     }
     }
 
 
     private func qrErrorAlert() {
     private func qrErrorAlert() {
@@ -194,11 +181,19 @@ extension WelcomeViewController: QrCodeReaderDelegate {
             title: String.localized("ok"),
             title: String.localized("ok"),
             style: .default,
             style: .default,
             handler: { [unowned self] _ in
             handler: { [unowned self] _ in
-                self.qrCordeReader.startSession()
+                self.qrCodeReader?.startSession()
             }
             }
         )
         )
         alert.addAction(okAction)
         alert.addAction(okAction)
-        qrCodeReaderNav.present(alert, animated: true, completion: nil)
+        qrCodeReaderNav?.present(alert, animated: true, completion: nil)
+    }
+
+    private func dismissQRReader() {
+        self.qrCodeReaderNav?.dismiss(animated: false) {
+            self.qrCodeReaderNav = nil
+            self.qrCodeReader = nil
+            self.scannedQrCode = nil
+        }
     }
     }
 }
 }
 
 

+ 13 - 8
deltachat-ios/Coordinator/AppCoordinator.swift

@@ -26,12 +26,6 @@ class AppCoordinator: NSObject, Coordinator {
         return tabBarController
         return tabBarController
     }()
     }()
 
 
-    private lazy var welcomeController: WelcomeViewController = {
-        let welcomeController = WelcomeViewController(dcContext: dcContext)
-        welcomeController.coordinator = self
-        return welcomeController
-    }()
-
     private lazy var loginController: UIViewController = {
     private lazy var loginController: UIViewController = {
         let accountSetupController = AccountSetupController(dcContext: dcContext, editView: false)
         let accountSetupController = AccountSetupController(dcContext: dcContext, editView: false)
         let nav = UINavigationController(rootViewController: accountSetupController)
         let nav = UINavigationController(rootViewController: accountSetupController)
@@ -83,6 +77,8 @@ class AppCoordinator: NSObject, Coordinator {
         return nav
         return nav
     }()
     }()
 
 
+
+    private var welcomeController: WelcomeViewController?
     private var profileInfoNavigationController: UINavigationController?
     private var profileInfoNavigationController: UINavigationController?
 
 
     init(window: UIWindow, dcContext: DcContext) {
     init(window: UIWindow, dcContext: DcContext) {
@@ -145,15 +141,24 @@ class AppCoordinator: NSObject, Coordinator {
         // but even when this changes in ios, we need the reset as we allow account-deletion also in-app.
         // but even when this changes in ios, we need the reset as we allow account-deletion also in-app.
         UIApplication.shared.applicationIconBadgeNumber = 0
         UIApplication.shared.applicationIconBadgeNumber = 0
 
 
-        window.rootViewController = welcomeController
+        let wc = makeWelcomeController()
+        self.welcomeController = wc
+        window.rootViewController = wc
         window.makeKeyAndVisible()
         window.makeKeyAndVisible()
     }
     }
 
 
     func presentTabBarController() {
     func presentTabBarController() {
         window.rootViewController = tabBarController
         window.rootViewController = tabBarController
+        welcomeController = nil
         window.makeKeyAndVisible()
         window.makeKeyAndVisible()
         showTab(index: chatsTab)
         showTab(index: chatsTab)
     }
     }
+
+    private func makeWelcomeController() -> WelcomeViewController {
+        let welcomeController = WelcomeViewController(dcContext: dcContext)
+        welcomeController.coordinator = self
+        return welcomeController
+    }
 }
 }
 
 
 // MARK: - WelcomeCoordinator
 // MARK: - WelcomeCoordinator
@@ -170,7 +175,7 @@ extension AppCoordinator: WelcomeCoordinator {
             loginController.coordinator?.onLoginSuccess = handleLoginSuccess
             loginController.coordinator?.onLoginSuccess = handleLoginSuccess
         }
         }
         loginController.modalPresentationStyle = .fullScreen
         loginController.modalPresentationStyle = .fullScreen
-        welcomeController.present(loginController, animated: true, completion: nil)
+        welcomeController?.present(loginController, animated: true, completion: nil)
     }
     }
 
 
     func handleLoginSuccess() {
     func handleLoginSuccess() {

+ 20 - 13
deltachat-ios/Handler/ProgressAlertHandler.swift

@@ -2,34 +2,46 @@ import UIKit
 import DcCore
 import DcCore
 
 
 protocol ProgressAlertHandler: UIViewController {
 protocol ProgressAlertHandler: UIViewController {
-    var progressAlert: UIAlertController { get }
-    var configureProgressObserver: Any? { get set }
-    func showProgressAlert(title: String)
+    var progressAlert: UIAlertController? { get set }   // needs to be implemented as weak
+    var configureProgressObserver: Any? { get set } // set to nil in viewDidDisappear
+    func showProgressAlert(title: String, dcContext: DcContext)
     func updateProgressAlertValue(value: Int?)
     func updateProgressAlertValue(value: Int?)
     func updateProgressAlert(error: String?)
     func updateProgressAlert(error: String?)
     func updateProgressAlertSuccess(completion: VoidFunction?)
     func updateProgressAlertSuccess(completion: VoidFunction?)
     func addProgressAlertListener(onSuccess: @escaping VoidFunction)
     func addProgressAlertListener(onSuccess: @escaping VoidFunction)
-    func progressAlertWillDismiss()
 }
 }
 
 
 extension ProgressAlertHandler {
 extension ProgressAlertHandler {
 
 
-    func showProgressAlert(title: String) {
+    func showProgressAlert(title: String, dcContext: DcContext) {
+        self.progressAlert = makeProgressAlert(dcContext: dcContext)
+        guard let progressAlert = progressAlert else { return }
         progressAlert.actions[0].isEnabled = true
         progressAlert.actions[0].isEnabled = true
         progressAlert.title = title
         progressAlert.title = title
         progressAlert.message = String.localized("one_moment")
         progressAlert.message = String.localized("one_moment")
         present(progressAlert, animated: true, completion: nil)
         present(progressAlert, animated: true, completion: nil)
     }
     }
 
 
+    private func makeProgressAlert(dcContext: DcContext) -> UIAlertController {
+        let alert = UIAlertController(title: "", message: "", preferredStyle: .alert)
+        alert.addAction(UIAlertAction(
+            title: String.localized("cancel"),
+            style: .cancel,
+            handler: { _ in
+                dcContext.stopOngoingProcess()
+        }))
+        return alert
+    }
+
     func updateProgressAlertValue(value: Int?) {
     func updateProgressAlertValue(value: Int?) {
         if let value = value {
         if let value = value {
-            progressAlert.message = String.localized("one_moment") + " " + String(value/10) + "%"
+            progressAlert?.message = String.localized("one_moment") + " " + String(value/10) + "%"
         }
         }
     }
     }
 
 
     func updateProgressAlert(error message: String?) {
     func updateProgressAlert(error message: String?) {
         DispatchQueue.main.async(execute: {
         DispatchQueue.main.async(execute: {
-            self.progressAlert.dismiss(animated: false)
+            self.progressAlert?.dismiss(animated: false)
             let errorAlert = UIAlertController(title: String.localized("error"), message: message, preferredStyle: .alert)
             let errorAlert = UIAlertController(title: String.localized("error"), message: message, preferredStyle: .alert)
             errorAlert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
             errorAlert.addAction(UIAlertAction(title: String.localized("ok"), style: .default, handler: nil))
             self.present(errorAlert, animated: true, completion: nil)
             self.present(errorAlert, animated: true, completion: nil)
@@ -38,10 +50,9 @@ extension ProgressAlertHandler {
 
 
     func updateProgressAlertSuccess(completion onComplete: VoidFunction?) {
     func updateProgressAlertSuccess(completion onComplete: VoidFunction?) {
         updateProgressAlertValue(value: 1000)
         updateProgressAlertValue(value: 1000)
-        progressAlertWillDismiss()
         // delay so the user has time to read the success message
         // delay so the user has time to read the success message
         DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
         DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
-            self.progressAlert.dismiss(animated: true) {
+            self.progressAlert?.dismiss(animated: true) {
                 onComplete?()
                 onComplete?()
             }
             }
         })
         })
@@ -65,9 +76,5 @@ extension ProgressAlertHandler {
             }
             }
         }
         }
     }
     }
-
-    func progressAlertWillDismiss() {
-        // can be overwritten if needed
-    }
 }
 }