Memory management @转义completionHandler-内存管理如何为它们工作?

Memory management @转义completionHandler-内存管理如何为它们工作?,memory-management,swift3,singleton,completionhandler,Memory Management,Swift3,Singleton,Completionhandler,在我的应用程序2中,控制器使用相同的数据来显示,并且从每个控制器类进行服务器调用以从服务器获取数据 若用户来回导航,则在第一个请求完成之前,会发出另一个请求,要求两个获取相同的数据 我想通过只使用一个服务器调用来优化这一点,并防止在进行另一个服务器调用时再次调用 为了做到这一点,我使用了一个singleton类,它负责获取数据并防止来自服务器的两个同时请求相同的数据 若控制器的视图将消失收到呼叫,我不想在从服务器收到数据后通知该控制器。就像我们在视图中删除观察者将消失一样,在视图中添加观察者将出

在我的应用程序2中,控制器使用相同的数据来显示,并且从每个控制器类进行服务器调用以从服务器获取数据

若用户来回导航,则在第一个请求完成之前,会发出另一个请求,要求两个获取相同的数据

我想通过只使用一个服务器调用来优化这一点,并防止在进行另一个服务器调用时再次调用

为了做到这一点,我使用了一个singleton类,它负责获取数据并防止来自服务器的两个同时请求相同的数据

若控制器的
视图将消失
收到呼叫,我不想在从服务器收到数据后通知该控制器。就像我们在
视图中删除观察者将消失
一样,在视图中添加观察者将出现

class ViewController: UIViewController {
    override func viewWillAppear(_ animated: Bool) {
        print("ViewController 1 Function")

        DataSource.sharedInstance.fetchData { (name, error) in
            print("ViewController 1 Handler")
        }
    }
}
以下是我的密码-

final class SingletonDataManager { 
        typealias MYCompletionHandler = (_ persons:[Person]?, _ error: NSError?) -> Void

        // MARK: Shared Instance
        static let sharedInstance = SingletonDataManager()

        // MARK: Concurrent queue f

        fileprivate let concurrentQ = DispatchQueue(label: "com.test.concurrentQueue",
                                                                      qos: .userInitiated,
                                                                      attributes: .concurrent)

        fileprivate var _handler: MYCompletionHandler?
        fileprivate var handler: MYCompletionHandler? {
            get {
                return concurrentQ.sync {
                    return _handler
                }
            }

            set {
                concurrentQ.async(flags: .barrier){ [weak self] in
                    self?._handler = newValue
                }
            }
        }

        fileprivate var result:(persons: [Person]?, error: NSError?) {
            didSet {
                if let hndlr = handler {
                    hndlr(result.persons, result.error)
                    self.isInProgress = false
                }
            }
        }

        fileprivate var _isInProgress = false
        fileprivate var isInProgress: Bool {
            get {
                return concurrentQ.sync {
                    return _isInProgress
                }
            }

            set {
                concurrentQ.async(flags: .barrier){ [weak self] in
                    self?._isInProgress = newValue
                }
            }
        }


        // MARK:- init()
        private init() {

        }

        deinit {
            print(" destroyed")
        }


        internal func getData(_ onCompletion: @escaping MYCompletionHandler) {

            if self.isInProgress == true { 
                self.handler = onCompletion
            } else {
                       NetworkManager.sharedInstance().fetchDataFromServer({ [weak self] (data, error) in 
                        DispatchQueue.main.async {
                            self?.result = (data, error)
                        }
                    })
                }
            } 
    }

    }
和控制器类1-ViewControllerA

class ViewControllerA {

func getPersons() {
SingletonDataManager.sharedInstance.getData(onCompletion: { [weak self] (persons, error) in

})

override func viewWillAppear(_ animated: Bool) {
   getPersons()
}
}
控制器类2-ViewControllerB

class ViewControllerB {

func getPersons() {
SingletonDataManager.sharedInstance.getData(onCompletion: { [weak self] (persons, error) in

})

override func viewWillAppear(_ animated: Bool) {
   getPersons()
}
}
用户可以在ViewControllerA和ViewControllerB之间导航。 这里有两个案例- 在控制器ViewControllerA发起的网络请求完成之前,用户可以从ViewControllerA导航到ViewControllerB。 或在请求完成后移动

我想通过阻止多个服务器请求来解决案例1。 为了实现这一点,我在singleton类中使用了一个bool变量
isInProgress
并设置其值线程安全方式

我还有一个变量
**handler**
,它保存了需要调用的最新完成处理程序。这也是线程安全的

一切正常,但我想确保未调用的completionhandler不会占用额外内存

当我将新的完成处理程序分配给**
handler
变量时,它们会被释放吗?**还是会持续消耗内存

这是解决这个问题的正确方法吗

或者我应该在这里使用NSNotification。 最好的方法是什么

我想释放结果数组占用的内存,以防内存不足警告。如何在ARC中处理此问题

希望我现在能正确地解释我的问题。 我已经问了很多次这个问题,但由于对问题的解释不好,所以没有得到很好的回答。 请让我知道,如果需要更多的澄清

谢谢。

我终于明白了

  • @即使在类去初始化之后,转义闭包也会得到调用,但如果您使用弱self正确管理内存,它不会得到nil实例变量

  • 如果我们根本不调用@escaping闭包,它就不会占用任何内存

  • 示例代码

    final class DataSource {
    
        typealias RequestCompleted = (_ data:String?, _ error: NSError?) -> Void
    
        // MARK: Shared Instance
        static let sharedInstance = DataSource()
    
        // MARK: Concurrent queue for thread-safe array
    
        fileprivate let concurrentQ = DispatchQueue(label: "com.test.concurrentQueue",
                                                    qos: .userInitiated,
                                                    attributes: .concurrent)
    
        // MARK:- Local Variable
        fileprivate var _dataHandler: RequestCompleted?
        fileprivate var dataHandler: RequestCompleted? {
            get {
                return concurrentQ.sync {
                    return _dataHandler
                }
            }
    
            set {
                concurrentQ.async(flags: .barrier){ [weak self] in
                    self?._dataHandler = newValue
                }
            }
        }
    
        fileprivate var result:(data: String?, error: NSError?) {
            didSet {
                if let handlr = dataHandler {
                    handlr(result.data, result.error)
                    self.isRequestInProgress = false
                }
            }
        }
    
        fileprivate var _isRequestInProgress = false
        fileprivate var isRequestInProgress: Bool {
            get {
                return concurrentQ.sync {
                    return _isRequestInProgress
                }
            }
    
            set {
                concurrentQ.async(flags: .barrier){ [weak self] in
                    self?._isRequestInProgress = newValue
                }
            }
        }
    
    
        // MARK:- Private init()
        private init() {
    
        }
    
        deinit {
            print("Deinitialized")
        }
    
    
        internal func fetchData(_ onCompletion: @escaping RequestCompleted) {
            self.dataHandler = onCompletion
            if self.isRequestInProgress == true { print("TTT: In Progress")
                return
            } else {
    
                self.isRequestInProgress = true
    
                DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(20)) {
                    // Code
                     self.result = ("Done", nil)
                }
            }
        }
    }
    
    视图控制器

    class ViewController: UIViewController {
        override func viewWillAppear(_ animated: Bool) {
            print("ViewController 1 Function")
    
            DataSource.sharedInstance.fetchData { (name, error) in
                print("ViewController 1 Handler")
            }
        }
    }
    
    视图控制器2

    class ViewController2: UIViewController {
        var str = "Test"
        var arr = [1, 2, 3]
    
        override func viewWillAppear(_ animated: Bool) {
            print("ViewController 2 Function")
    
            DataSource.sharedInstance.fetchData { [weak self] (name, error) in
                print("ViewController 2 Handler")
                print("CCCC\(self?.arr ?? [0])")
                print("SSSS\(self?.str ?? "Happy")")
            }
        }
    
        deinit {
            print("VC2.. deinit")
        }
    }
    
    视图控制器3

    class ViewController3: UIViewController {
        override func viewWillAppear(_ animated: Bool) {
            print("ViewController 3 Function")
    
            DataSource.sharedInstance.fetchData { (name, error) in
                print("ViewController 3 Handler")
            }
        }
    
        deinit {
            print("VC3.. deinit")
        }
    
    }
    
    和内存不足警告-

    从斯威夫特开始

    集合类型和元组是值类型

    在内存不足警告的情况下,我将删除person对象或将tuple设置为nil。它不会影响控制器视图上的数据