Jelajahi Sumber

Merge pull request #1138 from deltachat/fix-chatlist-anr

fix chatlist anr
bjoern 4 tahun lalu
induk
melakukan
7db20d5e65

+ 3 - 0
DcCore/DcCore/DC/Wrapper.swift

@@ -92,8 +92,11 @@ public class DcContext {
     }
 
     public func getChatlist(flags: Int32, queryString: String?, queryId: Int) -> DcChatlist {
+        let start = CFAbsoluteTimeGetCurrent()
         let chatlistPointer = dc_get_chatlist(contextPointer, flags, queryString, UInt32(queryId))
         let chatlist = DcChatlist(chatListPointer: chatlistPointer)
+        let diff = CFAbsoluteTimeGetCurrent() - start
+        logger?.info("⏰ getChatlist: \(diff) s")
         return chatlist
     }
 

+ 10 - 16
DcShare/Controller/ChatListController.swift

@@ -11,8 +11,6 @@ class ChatListController: UITableViewController {
     let viewModel: ChatListViewModel
     let contactCellReuseIdentifier = "contactCellReuseIdentifier"
     weak var chatListDelegate: ChatListDelegate?
-    var keyboardAppearedObserver: Any?
-    var keyboardDisappearedObserver: Any?
 
     /// MARK - search
 
@@ -53,14 +51,14 @@ class ChatListController: UITableViewController {
     override func viewDidAppear(_ animated: Bool) {
         navigationItem.hidesSearchBarWhenScrolling = true
         let nc = NotificationCenter.default
-        keyboardAppearedObserver = nc.addObserver(self,
-                                                  selector: #selector(keyboardWillShow(_:)),
-                                                  name: UIResponder.keyboardWillShowNotification,
-                                                  object: nil)
-        keyboardDisappearedObserver = nc.addObserver(self,
-                                                     selector: #selector(keyboardWillHide(_:)),
-                                                     name: UIResponder.keyboardWillHideNotification,
-                                                     object: nil)
+        nc.addObserver(self,
+                       selector: #selector(keyboardWillShow(_:)),
+                       name: UIResponder.keyboardWillShowNotification,
+                       object: nil)
+        nc.addObserver(self,
+                       selector: #selector(keyboardWillHide(_:)),
+                       name: UIResponder.keyboardWillHideNotification,
+                       object: nil)
     }
 
     override func viewDidLoad() {
@@ -71,12 +69,8 @@ class ChatListController: UITableViewController {
     }
 
     override func viewDidDisappear(_ animated: Bool) {
-        if let keyboardAppearedObserver = keyboardAppearedObserver {
-            NotificationCenter.default.removeObserver(keyboardAppearedObserver)
-        }
-        if let keyboardDisappearedObserver = keyboardDisappearedObserver {
-            NotificationCenter.default.removeObserver(keyboardDisappearedObserver)
-        }
+        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
     }
 
     @objc func keyboardWillShow(_ notification: Notification) {

+ 13 - 19
deltachat-ios/Chat/ChatViewController.swift

@@ -14,9 +14,9 @@ class ChatViewController: UITableViewController {
     let chatId: Int
     var messageIds: [Int] = []
 
-    var msgChangedObserver: Any?
-    var incomingMsgObserver: Any?
-    var ephemeralTimerModifiedObserver: Any?
+    var msgChangedObserver: NSObjectProtocol?
+    var incomingMsgObserver: NSObjectProtocol?
+    var ephemeralTimerModifiedObserver: NSObjectProtocol?
     // isDismissing indicates whether the ViewController is/was about to dismissed.
     // The VC can be dismissed by pressing back '<' or by a swipe-to-dismiss gesture.
     // The latter is cancelable and leads to viewWillAppear is called in case the gesture is cancelled
@@ -24,8 +24,6 @@ class ChatViewController: UITableViewController {
     var isDismissing = false
     var isInitial = true
     var ignoreInputBarChange = false
-    var foregroundObserver: Any?
-    var backgroundObserver: Any?
 
     lazy var isGroupChat: Bool = {
         return dcContext.getChat(chatId: chatId).isGroup
@@ -408,15 +406,15 @@ class ChatViewController: UITableViewController {
             self.updateTitle(chat: self.dcContext.getChat(chatId: self.chatId))
         }
 
-        foregroundObserver = nc.addObserver(self,
-                                            selector: #selector(applicationDidBecomeActive(_:)),
-                                            name: UIApplication.didBecomeActiveNotification,
-                                            object: nil)
+        nc.addObserver(self,
+                       selector: #selector(applicationDidBecomeActive(_:)),
+                       name: UIApplication.didBecomeActiveNotification,
+                       object: nil)
 
-        backgroundObserver = nc.addObserver(self,
-                                            selector: #selector(applicationWillResignActive(_:)),
-                                            name: UIApplication.willResignActiveNotification,
-                                            object: nil)
+        nc.addObserver(self,
+                       selector: #selector(applicationWillResignActive(_:)),
+                       name: UIApplication.willResignActiveNotification,
+                       object: nil)
 
         // things that do not affect the chatview
         // and are delayed after the view is displayed
@@ -453,12 +451,8 @@ class ChatViewController: UITableViewController {
         if let ephemeralTimerModifiedObserver = self.ephemeralTimerModifiedObserver {
             nc.removeObserver(ephemeralTimerModifiedObserver)
         }
-        if let foregroundObserver = self.foregroundObserver {
-            nc.removeObserver(foregroundObserver)
-        }
-        if let backgroundObserver = self.backgroundObserver {
-            nc.removeObserver(backgroundObserver)
-        }
+        nc.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
+        nc.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil)
         audioController.stopAnyOngoingPlaying()
 
     }

+ 3 - 3
deltachat-ios/Controller/AccountSetupController.swift

@@ -5,12 +5,12 @@ import DcCore
 class AccountSetupController: UITableViewController, ProgressAlertHandler {
     private let dcContext: DcContext
     private var skipOauth = false
-    private var backupProgressObserver: Any?
-    var progressObserver: Any?
+    private var backupProgressObserver: NSObjectProtocol?
+    var progressObserver: NSObjectProtocol?
     var onProgressSuccess: VoidFunction? // not needed here
     var onLoginSuccess: (() -> Void)?
 
-    private var oauth2Observer: Any?
+    private var oauth2Observer: NSObjectProtocol?
 
     private let tagEmailCell = 0
     private let tagPasswordCell = 1

+ 17 - 20
deltachat-ios/Controller/ChatListController.swift

@@ -9,12 +9,9 @@ class ChatListController: UITableViewController {
     private let deadDropCellReuseIdentifier = "deaddrop_cell"
     private let contactCellReuseIdentifier = "contact_cell"
 
-    private var msgChangedObserver: Any?
-    private var msgsNoticedObserver: Any?
-    private var incomingMsgObserver: Any?
-    private var viewChatObserver: Any?
-    private var foregroundObserver: Any?
-    private var backgroundObserver: Any?
+    private var msgChangedObserver: NSObjectProtocol?
+    private var msgsNoticedObserver: NSObjectProtocol?
+    private var incomingMsgObserver: NSObjectProtocol?
 
     private weak var timer: Timer?
 
@@ -127,14 +124,16 @@ class ChatListController: UITableViewController {
             queue: nil) { [weak self] _ in
                 self?.viewModel.refreshData()
         }
-        foregroundObserver = nc.addObserver(self,
-                                            selector: #selector(applicationDidBecomeActive(_:)),
-                                            name: UIApplication.didBecomeActiveNotification,
-                                            object: nil)
-        backgroundObserver = nc.addObserver(self,
-                                            selector: #selector(applicationWillResignActive(_:)),
-                                            name: UIApplication.willResignActiveNotification,
-                                            object: nil)
+        nc.addObserver(
+            self,
+            selector: #selector(applicationDidBecomeActive(_:)),
+            name: UIApplication.didBecomeActiveNotification,
+            object: nil)
+        nc.addObserver(
+            self,
+            selector: #selector(applicationWillResignActive(_:)),
+            name: UIApplication.willResignActiveNotification,
+            object: nil)
     }
 
     override func viewDidDisappear(_ animated: Bool) {
@@ -142,6 +141,7 @@ class ChatListController: UITableViewController {
         stopTimer()
 
         let nc = NotificationCenter.default
+        // remove observers with a block
         if let msgChangedObserver = self.msgChangedObserver {
             nc.removeObserver(msgChangedObserver)
         }
@@ -151,12 +151,9 @@ class ChatListController: UITableViewController {
         if let msgsNoticedObserver = self.msgsNoticedObserver {
             nc.removeObserver(msgsNoticedObserver)
         }
-        if let foregroundObserver = self.foregroundObserver {
-            nc.removeObserver(foregroundObserver)
-        }
-        if let backgroundObserver = self.backgroundObserver {
-            nc.removeObserver(backgroundObserver)
-        }
+        // remove non-block observers
+        NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
+        NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification, object: nil)
     }
     
     // MARK: - setup

+ 1 - 1
deltachat-ios/Controller/QrPageController.swift

@@ -4,7 +4,7 @@ import DcCore
 class QrPageController: UIPageViewController, ProgressAlertHandler {
     private let dcContext: DcContext
     weak var progressAlert: UIAlertController?
-    var progressObserver: Any?
+    var progressObserver: NSObjectProtocol?
     var qrCodeReaderController: QrCodeReaderController?
 
     private var selectedIndex: Int = 0

+ 1 - 1
deltachat-ios/Controller/SettingsController.swift

@@ -32,7 +32,7 @@ internal final class SettingsViewController: UITableViewController, ProgressAler
 
     let documentInteractionController = UIDocumentInteractionController()
     weak var progressAlert: UIAlertController?
-    var progressObserver: Any?
+    var progressObserver: NSObjectProtocol?
 
     // MARK: - cells
 

+ 1 - 1
deltachat-ios/Controller/WelcomeViewController.swift

@@ -3,7 +3,7 @@ import DcCore
 
 class WelcomeViewController: UIViewController, ProgressAlertHandler {
     private let dcContext: DcContext
-    var progressObserver: Any?
+    var progressObserver: NSObjectProtocol?
     var onProgressSuccess: VoidFunction?
 
     private lazy var scrollView: UIScrollView = {

+ 1 - 1
deltachat-ios/Handler/ProgressAlertHandler.swift

@@ -3,7 +3,7 @@ import DcCore
 
 protocol ProgressAlertHandler: UIViewController {
     var progressAlert: UIAlertController? { get set }   // needs to be implemented as weak
-    var progressObserver: Any? { get set } // set to nil in viewDidDisappear
+    var progressObserver: NSObjectProtocol? { get set } // set to nil in viewDidDisappear
     func showProgressAlert(title: String, dcContext: DcContext)
     func updateProgressAlertValue(value: Int?)
     func updateProgressAlert(error: String?)

+ 2 - 2
deltachat-ios/Helper/NotificationManager.swift

@@ -5,8 +5,8 @@ import UIKit
 
 public class NotificationManager {
     
-    var incomingMsgObserver: Any?
-    var msgsNoticedObserver: Any?
+    var incomingMsgObserver: NSObjectProtocol?
+    var msgsNoticedObserver: NSObjectProtocol?
 
     init() {
         initIncomingMsgsObserver()

+ 12 - 0
docs/uiview-layout.md

@@ -140,6 +140,18 @@ a tricky part (see eg. [3]) seems to be to hold the correct type of rerences to
 tl;dr: post from main thread and also add/remove observers from main thread.
 on receiving, assume, things will block.
 
+## notification system: adding and removing observers
+
+- for the `addObserver()` variant returning an object
+  (overview at https://developer.apple.com/documentation/foundation/notificationcenter )
+  always save the object as `NSObjectProtocol` not as `Any?` -
+  otherwise you risk to mix addObserver() functions as also
+  the non-return variant can be saved as `Any?`
+  (Swift allows saving "no return type" as `Any?`)
+
+- call `removeObserver(self)` only in deinit,
+  otherwise use `removeObserver(self, name, obj)` or `removeObserver(obj)`
+
 
 ## some sources