Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error: Assigning non-escaping parameter 'publicationQuery' to an @escaping closure

I have a view controller like this:

class PublicationListViewController: UIViewController {
    var publicationQuery: (() -> [Publication])!

    func initWith(title: String, publicationQuery: () -> [Publication]) {
        self.title = title
        self.publicationQuery = publicationQuery
    }
}

Why am I getting a "Assigning non-escaping parameter 'publicationQuery' to an @escaping closure" error?

like image 424
Melodius Avatar asked Feb 28 '18 16:02

Melodius


1 Answers

Escaping Closures

Because by storing the publicationQuery into a property you are allowing it to "escape" from the initializer (it lives even after the initiliazer finished its execution, thus is a potential cause of retain cycle). To be able to do that you have to explicitly mark it as escaping using @escaping annotation:

class PublicationListViewController: UIViewController {
    var publicationQuery: (() -> [String])!

    // notice that now publicationQuery uses @escaping annotation
    func initWith(title: String, publicationQuery: @escaping () -> [String]) {
        self.title = title
        self.publicationQuery = publicationQuery
    }
}

Read more about escaping in Escaping Closures section of the Closures documentation.

Preventing Retain Cycle

When using escaping closures, you have to be careful not to create a retain cycle. Easiest way is to use the capture list when creating escaping closure, and in that capture list you explicitly capture self as a weak reference:

// use [weak self] capture list to make sure that you don't create another strong reference to self
pubController.initWith(title: "Title") { [weak self] () -> [String] in
    // use guard to safely unwrap the self
    guard let `self` = self else { return }

    // here self will be non-optional value that you can directly use
}
like image 100
Milan Nosáľ Avatar answered Oct 13 '22 00:10

Milan Nosáľ