Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何使用dispatchQueues创建引用循环?_Swift_Memory Management_Memory Leaks_Closures_Grand Central Dispatch - Fatal编程技术网

Swift 如何使用dispatchQueues创建引用循环?

Swift 如何使用dispatchQueues创建引用循环?,swift,memory-management,memory-leaks,closures,grand-central-dispatch,Swift,Memory Management,Memory Leaks,Closures,Grand Central Dispatch,我觉得我总是误解,当引用循环被创建时。在我过去认为几乎任何地方都有一个块,编译器强迫你写.self之前,这是我正在创建一个引用循环的标志,我需要在中使用[weak self] 但以下设置不会创建参考循环 import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution class UsingQueue { var property : Int = 5 var

我觉得我总是误解,当引用循环被创建时。在我过去认为几乎任何地方都有一个块,编译器强迫你写
.self
之前,这是我正在创建一个引用循环的标志,我需要在
中使用
[weak self]

但以下设置不会创建参考循环

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution


class UsingQueue {
    var property : Int  = 5
    var queue : DispatchQueue? = DispatchQueue(label: "myQueue")

    func enqueue3() {
        print("enqueued")
        queue?.asyncAfter(deadline: .now() + 3) {
            print(self.property)
        }
    }

    deinit {
        print("UsingQueue deinited")
    }
}

var u : UsingQueue? = UsingQueue()
u?.enqueue3()
u = nil
块仅保留
self
3秒钟。然后释放它。如果我使用
async
而不是
asyncAfter
,那么它几乎是即时的

据我所知,这里的设置是:

self ---> queue
self <--- block
在闭包示例中,设置更像:

self ----> block
self <--- block
通过下面的代码,我能够在Xcode的内存图中创建一个泄漏ie,我看到的是一个循环,而不是一条直线。我得到了紫色的指示器。我认为这种设置非常类似于存储的闭包如何产生泄漏。这与您的两个示例不同,在这两个示例中,执行从未完成。在本例中,执行已完成,但由于引用,它仍保留在内存中

我认为参考是这样的:

┌─────────┐─────────────self.item──────────────▶┌────────┐
│   self  │                                     │workItem│
└─────────┘◀︎────item = DispatchWorkItem {...}───└────────┘
你说:

据我所知,这里的设置是:

self ---> queue
self <--- block
即使我启动上述计时器的视图控制器被解除,GCD仍会继续启动此计时器,
Ticker
不会被释放。如“调试内存图”功能所示,在
startTicker
例程中创建的块保持对
Ticker
对象的持久强引用:

如果我在该块中使用
[weak self]
作为调度队列上调度的计时器的事件处理程序,显然可以解决这个问题

其他场景包括缓慢(或不确定长度)调度的任务,您希望
取消它(例如,在
deinit
):

尽管如此,在绝大多数GCD用例中,
[弱自我]
的选择并不是一个强引用周期,而仅仅是我们是否介意在任务完成之前对
自我
的强引用是否持续

  • 如果我们只是想在任务完成时更新UI,那么如果视图控制器被取消,就没有必要让视图控制器及其视图在层次结构中等待一些UI更新

  • 如果我们需要在任务完成时更新数据存储,那么如果我们想确保更新发生,我们肯定不想使用
    [weak self]

  • 通常,分派的任务并不重要,因此不必担心
    self
    的寿命。例如,当请求完成时,您可能会有一个
    URLSession
    完成处理程序dispatch UI update返回到主队列。当然,理论上我们希望
    [弱自我]
    (因为没有理由保留已被取消的视图控制器的视图层次结构),但这又给我们的代码增加了噪音,通常没有什么实质好处



不相关,但操场是测试记忆行为的可怕场所,因为它们有自己的特质。在实际的应用程序中这样做要好得多。另外,在实际的应用程序中,您还可以使用“调试内存图”功能查看实际的强引用。请参阅。

DispatchQueue
专门设计为不会导致保留循环。它包含一个控制行为的
autoreleaseFrequency
属性。这很有趣。你能再补充一点细节吗?但是,在
中使用
[weak self]来调度队列的目的是什么?只是为了控制流量吗?我做了一个小的编辑来详细说明我的意思,看一下。捕获
self
毫无意义。我知道它不会捕获
self
,但如果是,那么哪行源代码可以捕获
self
?(我只是不能处理所有这些,所以我想缩小我应该处理的部分)我还将队列更改为:
var queue:DispatchQueue?=DispatchQueue(标签:“mine”,qos:。后台,属性:。并发,自动释放频率:。从不,目标:nil)
但它仍然被释放。
从不
是否意味着它不会自动释放任何内容?
自动释放频率
与强引用周期问题无关。这就是在调度任务中创建的对象的自动释放池被耗尽的时间。读完这篇文章后,我感觉到队列的GCD就像计时器的runloop。那很有趣,非常感谢!我从未使用过
DispatchSource
&
DispatchWorkItem
,但您的示例足以理解。因此,虽然
DispatchSource
DispatchWorkItem
都强烈引用了
self
self
(与我的闭包示例不同)没有指向
DispatchSource
DispatchWorkItem
的指针。这仅仅是一个任务并没有完成的问题,你们可以取消它或者引用它。使用闭包,即使执行了块。它不会释放,因为它仍然关闭
self
。PS我不知道如何阅读“调试内存图”,我必须研究它。它是分析强引用、识别周期等的伟大工具。请参阅WWDC 2016视频。我创建了一个新问题作为后续问题。你能看一下吗?
class C{var item:DispatchWorkItem!var name:String=“蜂蜜”func assignItem(){item=DispatchWorkItem{//Oops!print(self.name)}}}func execute(){DispatchQueue.main.asyncAfter(截止日期:.now()+1,execute:item)}deinit{print(“deinit hit!”)}
通过以下代码,我能够在Xcode的
┌─────────┐─────────────self.item──────────────▶┌────────┐
│   self  │                                     │workItem│
└─────────┘◀︎────item = DispatchWorkItem {...}───└────────┘
self ---> queue
self <--- block
class Ticker {
    private var timer: DispatchSourceTimer?

    func startTicker() {    
        let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".ticker")
        timer = DispatchSource.makeTimerSource(queue: queue)
        timer!.schedule(deadline: .now(), repeating: 1)
        timer!.setEventHandler {                         // whoops; missing `[weak self]`
            self.tick()
        }
        timer!.resume()
    }

    func tick() { ... }
}
class Calculator {
    private var item: DispatchWorkItem!

    deinit {
        item?.cancel()
        item = nil
    }

    func startCalculation() {
        let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".calcs")
        item = DispatchWorkItem {                         // whoops; missing `[weak self]`
            while true {
                if self.item?.isCancelled ?? true { break }
                self.calculateNextDataPoint()
            }
            self.item = nil
        }
        queue.async(execute: item)
    }

    func calculateNextDataPoint() {
        // some intense calculation here
    }
}