0

Between these 2 codes

( returns -> Void)

static func dropboxWorkoutList ( userCompletionHandler: @escaping ([String]) -> Void) {
  let client  = DropboxClientsManager.authorizedClient
  var files: [String] = []

  _ = client?.files.listFolder(path: "/workouts")
    .response { response, error in
      if let result = response {
        for entry in result.entries {
          if let file = entry as? Files.FileMetadata {
            let ext = (file.name as NSString).pathExtension
          
            switch ext {
            case "txt", "mrc", "zwo":
              //  print("filename:\(file.name) ext:\(ext) path:\(file.pathLower)")
              files.append(file.pathLower!)
            
            default:
              continue
            }
          }
        }
        files = files.sorted(by: { $0 < $1 } )
        // print("Contents of Workout Folder:\(files)")
      userCompletionHandler(files)
    } else if let error = error {
      print(error)
    }
  }
}

calling it

dropboxFunc.dropboxWorkoutList() { (value) in
  print("value:\(value)")
  print("value[0] : \(value[0])")
  print("value.count : \(value.count)")
}

results in:

value:["/1-01.txt", "/1-17.txt"]
value[0] : /1-01.txt
value.count : 5

however when changing it

  • from Return -> Void
  • to Return -> Any

trying to execute the below will have swift telling me:

"Missing return in a closure expected to return 'Any'"

dropboxFunc.dropboxWorkoutList() { (value) in
  print("value:\(value)")
  print("value[0] : \(value[0])")
  print("value.count : \(value.count)")
}

I can only allowed to execute 1 print statement. Just want to understand the difference.

Note: Asked this Return list of files from function call

and was given this as possible answer How I can return value from async block in swift

Rob
  • 415,655
  • 72
  • 787
  • 1,044
app4g
  • 670
  • 4
  • 24
  • You need to do `return value`, or value or "whatever" be `Any`. It's just that's since you can have implicit `return`, when you write one line it tries to convert it into an implicit return. More on implicit return https://github.com/apple/swift-evolution/blob/master/proposals/0255-omit-return.md Now question is: Do you really want to return `Any`? Which value do you want to return, will you use it really? Or is it just a test? – Larme Mar 09 '21 at 15:51
  • @Larme I was following the SO https://stackoverflow.com/questions/52287840/how-i-can-return-value-from-async-block-in-swift which has both of these as the solution. – app4g Mar 09 '21 at 16:00
  • @Rob I actually want to use the return values from dropboxWorkoutList to populate a tableview which I've not coded yet – app4g Mar 09 '21 at 16:01
  • @Rob It seems indeed what's logical, but doesn't seem to match the real use (if you see the initial question from `static func dropboxWorkoutList() -> [String]`). User wants to manage correclty async calls, and you can't return directly, you need to have a closure and understand how async works. In it, once you get the list, refresh the UI. – Larme Mar 09 '21 at 17:15
  • you really need to properly learn how to work with closures / async calls. You are stumbling upon simple things that any tutorial can answer – timbre timbre Mar 09 '21 at 17:23
  • http://www.programmingios.net/what-asynchronous-means/ – matt Mar 09 '21 at 17:24

1 Answers1

1

Specifying a closure of ([String]) -> Any means that the closure is going to return something, and it is of type Any. But in your examples, (a) your closures are not returning anything at all; and (b) the dropboxWorkoutList does not appear to need/use an object returned by the closure supplied by the caller, anyway. This is a “completion handler closure” pattern, and completion handler closures almost always have a Void return type.

I actually want to use the return values from dropboxWorkoutList to populate a tableview which I've not coded yet

OK, then I think you may be conflating the closure parameter (what dropboxWorkoutList will be supplying back to the caller) and the closure’s return value (the far less common scenario, where the caller needs to supply dropboxWorkoutList some value based upon the closure’s parameter). In this case, you want the former (the closure parameter), not the latter (the closure’s return value).

You likely do not want to change the closure to be ([String]) -> Any, at all, but rather leave it as ([String]) -> Void. The caller should just take the parameter of the closure and use that. For example:

dropboxFunc.dropboxWorkoutList { values in
    self.strings = values        // update whatever model object your table view data source is using
    self.tableview.reloadData()  // and tell the table view to reload the data
}

In short, your question here (and in that other post) was, effectively, “how do I return a value using a closure?”, to which the answer is that you should not think of it as “returning” a value. Rather, in asynchronous routines with completion handler closures, results are supplied as parameter(s) to the closure. Essentially, dropboxWorkoutList is calling a function (in this case, a closure) to say “hey, here is your data”. It is providing data to that closure, not returning data from that closure.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Yes. This is exactly what I am going for. Getting the returned values from the async which is then to be passed to the tableview as a datasource. Your explanation also helped to differentiate between the question asked which was ```Any``` vs ```Void``` – app4g Mar 10 '21 at 06:23