0

I have the following code below:

var rootTasks: [Task]?

func loadRootTasks() {
    rootTasks == nil ? rootTasks = [Task]() : rootTasks?.removeAll() // removeAll() works here
    TasksManager.loadTasks(parentTaskIDString: "0", tasks: &rootTasks!)
}

static func loadTasks(parentTaskIDString: String, tasks: inout [Task]) {

    let urlString = Config.httpsProtocol + "://" + Config.server + Config.portString + "/" + TasksManager.getTasksEndpoint + "/" + parentTaskIDString
    let url = URL(string: urlString)
    var urlRequest = URLRequest(url: url!)
    urlRequest.setValue(AccountsManager.sharedInstance.securityAccessToken, forHTTPHeaderField: "Authorization")

    let defaultSession = URLSession(configuration: .default)
    let getTasksTask = defaultSession.dataTask(with: urlRequest, completionHandler: { (data, response, error) in

        guard (response as? HTTPURLResponse)?.statusCode == 200 else {
            print("GetTasks response status code != 200")
            return
        }

        guard error == nil else {
            print("GetTasks error")
            return
        }

        guard let jsonData = data else {
            print("GetTasks did not receive JSON data")
            return
        }

        do {
            // PROBLEM is here:
            // compiler flags "Escaping closures can only capture inout parameters explicitly by value"
            tasks.removeAll() // removeAll() does not work here
            // same error here
            tasks = try JSONDecoder().decode([Task].self, from: jsonData)
            NotificationCenter.default.post(name: .rootTasksRefreshed, object: nil, userInfo: nil)
        }
        catch {
            print("GetTasks JSON parsing exception")
        }
    })

    getTasksTask.resume()
}

The problem is in the line "// PROBLEM ...". The compiler flags the "Escaping closures can only capture inout parameters explicitly by value" error.

The function "loadTasks" is a static method, which is called by "loadRootTasks". It needs to pass a "tasks" array which is a member variable, and needs to be modified from within the static method after the asynchronous method dataTask() runs.

How do I resolve the problems to be able to "tasks.removeAll()", etc?

I have read other posts, but there are not for Swift 4.2. I need help specifically for Swift 4.2. Thanks!

0

1 Answer 1

1

You cannot manipulate an inout parameter in asynchronous code.

In this case, though, there's no need to do so. Don't pass rootTasks to your loadTasks method at all. First, make your loadTasks method an instance method instead of a static method. Now your loadTasks method can see rootTasks, directly. So it can just change it, directly!

So, at that point, there's no need to say

        tasks.removeAll() // removeAll() does not work here

Just say

        self.rootTasks.removeAll()

And so on.

(However, your asynchronous code should probably take care to touch self.rootTasks only on the main thread.)

If you don't want to do that — that is, if you insist on leaving loadTasks as a static method — then you will have to do this in a normal way: loadTasks must take a completion handler which it will then call, as a way of passing the array back to the original caller asynchronously.

Sign up to request clarification or add additional context in comments.

2 Comments

I cannot make loadTasks to become an instance method, because for any tasks which are non-root tasks they will be held in a dictionary map with the parent task as key (I've not yet programmed this). So, I'll try to completion handler approach. Any tips here on the coding will be appreciated. Thanks!
"You cannot manipulate an inout parameter in asynchronous code." > That makes sense! Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.