1

I hope this doesn't sound dumb but I'm trying to put:

let lowercasedQuery = query.lowercased()
            
             let usersNew = users.filter({ $0.fullname.lowercased().contains(lowercasedQuery) || $0.username.contains(lowercasedQuery) })

into the DispatchQueue function but obviously, since they are constants declared in the function, the function is out of scope for the return line.

func filteredUsers(_ query: String) -> [User] {
        
        
        let delay = 3.3
    
        DispatchQueue.main.asyncAfter(deadline: .now() + delay)
        {
            
        }
            
            let lowercasedQuery = query.lowercased()
            
             let usersNew = users.filter({ $0.fullname.lowercased().contains(lowercasedQuery) || $0.username.contains(lowercasedQuery) })
        
        return usersNew
    }

Does anyone know how to solve this?

Thanks!

  • 1
    You cannot return a value from a function that does something `async`! Please read http://www.programmingios.net/what-asynchronous-means/ and the two articles that follow it. – matt Apr 30 '21 at 23:49
  • What is the purpose of `asyncAfter`? It looks like an attempt to work around an asynchronous network request. If yes, don't do that, it's horrible practice, and it causes exactly the behavior you try to avoid. – vadian May 01 '21 at 15:44

1 Answers1

2

You need a closure... more info here. Instead of return, call the completion handler closure.

func filteredUsers(_ query: String, completion: @escaping (([User]) -> Void)) {
    let delay = 3.3
    
    DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
        let lowercasedQuery = query.lowercased()
        let usersNew = self.users.filter({ $0.fullname.lowercased().contains(lowercasedQuery) || $0.username.contains(lowercasedQuery) })
        completion(usersNew)
    }
}

Usage:

viewModel.filteredUsers(searchText) { users in
    print(users) /// get your users here!
}

If you are trying to return users inside another function, it won't work. You also need to a add a closure to that function:

                                   /// another closure here
func mainFunction(_ query: String, completion: @escaping (([User]) -> Void)) {
    viewModel.filteredUsers(query) { users in
        completion(users) /// equivalent to `return users`
    }
}

mainFunction("searchText") { users in
    print(users) /// get your users here!
}

/// NOT `let users = mainFunction("searchText")`
aheze
  • 24,434
  • 8
  • 68
  • 125
  • Thanks for the quick reply! I call the function in a different view using: return viewModel.filteredUsers(searchText) But i now get an error, do you know how to solve this? – TheLegend27 Apr 30 '21 at 23:50
  • @TheLegend27 you wouldn't be able to use `return` there either. See my edit – aheze May 01 '21 at 00:32
  • thanks for the help, I get this error when trying to add it "Cannot convert return expression of type '()' to return type '[User]'". I'm calling it inside this "var users: [User] {}" as the return was in here before. Sorry for making this confusing. – TheLegend27 May 01 '21 at 14:19
  • @TheLegend27 Did you do `return viewModel.filteredUsers(searchText)` again? Completion handlers are asynchronous (they are delayed), so you can't use `return` anywhere. I'll add an example in my answer. But you should really check out the [article](http://www.programmingios.net/what-asynchronous-means/) @matt sent. – aheze May 01 '21 at 15:29