1

I'm using the Google Drive REST API in a Swift 3 app. Queries are executed using the executeQuery method of GTLRDriveService. This method takes a completion block of type GTLRServiceCompletionHandler?, which in turn is declared as

public typealias GTLRServiceCompletionHandler = (GTLRServiceTicket, Any?, Error?) -> Swift.Void

Because of this declaration, the second parameter must be downcast to the appropriate type inside the block. For instance:

let createPermissionQuery = GTLRDriveQuery_PermissionsCreate.query(
    withObject: permission, fileId: toShare.id)

...

driveService.executeQuery(createPermissionQuery) { (ticket, result, error) in
    if (error == nil) {
        // need to downcast result to GTLRDrive_Permission
        let permission = result as! GTLRDrive_Permission
        ...
    }
}

The second parameter is always of a specific type that is completely determined by the particular query passed to executeQuery. For instance, if one passes an instance of GTLRDriveQuery_PermissionsCreate, then the second parameter (if the query succeeds) will always be of type GTLRDrive_Permission. However, if I try to declare result to be of any type other than Any?, the code won't compile.

In Objective C, the completion block can be specified with a type that's specific to the query. For instance (adapted from here):

GTLRDriveQuery_PermissionsCreate *createPermissionQuery =
    [GTLRDriveQuery_PermissionsCreate queryWithObject:permission
                                               fileId:fileId];
...

[driveService executeQuery:createPermissionQuery
         completionHandler:^((GTLRServiceTicket *ticket,
                              GTLRDrive_Permission *permission,
                              NSError *error) {
    if (error == nil) {
        // work directly with permission
        ...
    }
}];

Is there any way to avoid this downcast? (I'm asking out of ignorance; I'm somewhat of a newbie to Swift.) If I was writing my own library, I'd design the method signatures differently, but this is Google's library and am kind of stuck with what they supply. Perhaps some sort of extension or layer on top of Google's code?

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • 2
    not an answer, but if the library is getting in the way, it's probably worth considering calling the http REST API directly and parsing the resulting JSON. My experience of the Google libraries to date (I confess, I haven't tried Swift) is that they don't help much with the hard stuff (e.g. throttling, retries, pagination, resumable uploads), so you'll need to code for that yourself anyway. – pinoyyid Mar 24 '17 at 23:17

1 Answers1

0

You might be able to specify an extension that wraps the Google execute method, takes a generic and casts to your generic type in the block. This would basically just be a pretty abstraction of what you're doing already, but for all types your extension would be designed to cover.

Joseph Quigley
  • 346
  • 1
  • 12