     }
 
     deinit {
-        if containerView != nil {
-            containerView.superview?.removeObserver(self, forKeyPath: TorchContentOffsetKey)
-            containerView.superview?.removeObserver(self, forKeyPath: TorchContentSizetKey)
-        }
+        observingContentSizeToken?.invalidate()
+        observingContentOffsetToken?.invalidate()
     }
 
     func stopObserving() {
-        scrollView.removeObserver(self, forKeyPath: TorchContentOffsetKey)
-        if !isPullingDown {
-            scrollView.removeObserver(self, forKeyPath: TorchContentSizetKey)
-        }
+        observingContentSizeToken?.invalidate()
+        observingContentOffsetToken?.invalidate()
     }
 
     func startObserving() {

            fatalError("Refreher can only be used in UIScrollView and it's subclasses.")
        }

        scrollView.addObserver(self, forKeyPath: TorchContentOffsetKey, options: .new, context: &TorchContentOffsetKVOContext)
        originalContentOffsetY = scrollView.contentOffset.y

        if !isPullingDown {
            scrollView.addObserver(self, forKeyPath: TorchContentSizetKey, options: .new, context: &TorchContentSizeKVOContext)
        }
    }

    open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {

        if context == &TorchContentOffsetKVOContext {
            observingContentOffsetChanges()
        } else if context == &TorchContentSizeKVOContext {
            observingContentSizeChanges()
        }
    }



import UIKit

open class PullObserver: NSObject {
    let option: PullOption
    weak var refreshView: RefreshView!
