3

I use an viewController which inherit BaseViewController. The function "monitorNetworkStatus()" is invoked in BaseViewController's method "viewDidLoad".

private func monitorNetworkStatus() {
        ReachabilityManager.shared.startMonitoring { [weak self] (status, presentingVC) in

            print(self?.description)

        }
    }
ReachabilityManager is a singleton。The startMonitoring function like this
    func startMonitoring(reachabilityStatus: @escaping (_ status: AFNetworkReachabilityStatus, _ presentingVC: UIViewController?) -> Void) {

        AFNetworkReachabilityManager.shared().setReachabilityStatusChange { [weak self] (status) in
            if status != self?.networkStatus {
                // Only notify when status toggling between reachable and not reachable
                if (self?.networkStatus == .notReachable &&
                    (status == .reachableViaWiFi || status == .reachableViaWWAN)) ||
                    status == .notReachable {
                    reachabilityStatus(status, self?.getPresentingViewController())
                }

                self?.networkStatus = status
            }
        }

        AFNetworkReachabilityManager.shared().startMonitoring()
When net status changes it will print nil occasionally.
gui
  • 31
  • 2

1 Answers1

3

The startMonitoring method takes in a closure which holds a weak reference to your view controller's instance. This closure lets ReachabilityManager's singleton instance know what needs to happen whenever network status changes.

Passing a weak reference to this closure ensures that the memory occupied by your view controller instance can be freed when it is no longer being used, thus preventing a potential memory leak.

At times, your view controller will get garbage collected when it is dismissed (or no longer being used elsewhere), but the singleton instance of ReachabilityManager (which outlives your view controller) will still call the closure that was passed to the startMonitoring method earlier. Since your view controller has been garbage collected, self will be nil in this case and you will see nil being printed occasionally.

Were the closure holding a strong reference to your view controller, you would probably be facing memory leaks, since your view controller will not get garbage collected when dismissed.

  • The view controller doesn't dismiss and get garbage collected. I stay in this viewController. – gui Jan 10 '19 at 03:26
  • Maybe you are presenting another view controller, which inherits from `BaseViewController`, and then returning to your current view controller after dismissing it. In this case, the other view controller would replace the closure and `ReachabilityManager` will notify this other view controller instead of the desired view controller. Try moving the call to `monitorNetworkStatus()` to `viewDidAppear` instead of `viewDidLoad` of the `BaseViewController` – Mayank K Rastogi Jan 10 '19 at 03:37
  • If other controller is created I wouldn't print nil. – gui Jan 10 '19 at 04:55
  • 1
    Put a breakpoint in `ReachabilityManager.startMonitoring`. It is likely called more than once. Also add a method `deinit` on every object that calls `startMonitoring` and place a breakpoint there. You'll see something like what Mayank is saying, where `deinit` is called and then a network change occurs before another call to `startMonitoring` is made. Without your full program, it's hard to know exactly how this happens, but it is very certain that it is happening. – Rob Napier Jan 14 '19 at 02:10
  • @RobNapier Thanks a lot, I have found the problem. The singleton's method "startMonitoring" is only invoked once. – gui Jan 14 '19 at 02:53