Andrei Herford
Andrei Herford

Reputation: 18729

Swift closure defindet as class property cannot access other class properies

When directly assigning / implementing a Swift closure it is no problem to access class properties. But when I try to define the closure as class propertie as well, access to other class properties is not possible. Why is this?


Here is an example:

While the closure directly assigned to editorVC.completionBlock can access the class property tableView without any problem, the same code within leads to an error when the closure is defined as class property editorCompletionBlock:

class MyViewController: UIViewController {
    @IBOutlet var tableView: UITableView!

    func showEditor(withData: String) {
        let editorVC = EditorViewController()

        // Directly assign closure - Works without any problem
        editorVC.completionBlock = { (result) in
            self.tableView.reloadData()
            doSomething(withResult: result)
            // ...
        }
        present(editorVC, animated: true, completion: nil)
    }

    // Define closure as class property ==> Error
    let editorCompletionBlock: EditorCompletionBlock = { (resut) in
        // ERROR: Value of type '(MyViewController) -> () -> MyViewController' has no member 'tableView'
        self.tableView.reloadData()
        doSomething(withResult: result)
        // ...
    }
}


typealias EditorCompletionBlock = (String) -> Void

class EditorViewController: UIViewController {
    var completionBlock: EditorCompletionBlock?

    func closeEditor(withResult result: String) {
        completionBlock?(result)
    }
}

Upvotes: 0

Views: 220

Answers (2)

Sanad Barjawi
Sanad Barjawi

Reputation: 578

Solution 1:

place your editorCompletionBlock in viewDidLoad(:_) and it should work like charm:

    class MyViewController: UIViewController {

        @IBOutlet var tableView: UITableView!
    
        func showEditor(withData: String) {
            let editorVC = EditorViewController()
    
            editorVC.completionBlock = { (result) in
                self.tableView.reloadData()
            }
            present(editorVC, animated: true, completion: nil)
        }

        override func viewDidLoad() {
            super.viewDidLoad()
            let editorCompletionBlock: EditorCompletionBlock = { (resut) in
                self.tableView.reloadData() ///should work :)
            }
        }
        
    }
    
    
    typealias EditorCompletionBlock = (String) -> Void
    
    class EditorViewController: UIViewController {
        var completionBlock: EditorCompletionBlock?
    
        func closeEditor(withResult result: String) {
            completionBlock?(result)
        }
    }

Solution 2: Or you can just declare your closure as lazy:

lazy var editorCompletionBlock: EditorCompletionBlock = { (result) 
      in
    self.tableView.reloadData()
    doSomething(withResult: result)
}

Upvotes: 1

PGDev
PGDev

Reputation: 24341

Reason:

You can't access self until the initialization process of a type is completed.

In your code, editorCompletionBlock is a stored property and you're trying to access self.tableView inside it. This is the reason it is giving compile time error.

Solution:

Instead, make editorCompletionBlock as a lazy property to get that working.

lazy var editorCompletionBlock: EditorCompletionBlock = { (result) in
    self.tableView.reloadData()
    doSomething(withResult: result)
}

Upvotes: 3

Related Questions