swiftswift3variadicperfect

Swift 3: Method expecting variadic String parameter can only receive single String argument


I'm calling a method expecting a String... variadic parameter, but the only thing it allows receiving from the enclosing function is a plain String.

My method looks like this:

public func deleteKeys(keysReceived:String..., completionHandler:@escaping () -> Void)
{
        RedisClient.getClient(withIdentifier: RedisClientIdentifier()) {
            c in
            do {
                let client = try c()
                client.delete(keys: keysReceived){}
                completionHandler()
            }
//...
            }
    }

The compile error is

Cannot convert value of type '[String]' to expected argument type 'String'

This method (client.delete()) is from a Redis API for Perfect-Swift so I cannot change the signature, but I can change the enclosing function (deleteKeys). I also cannot call the function directly because it is within a callback closure

Any suggestions on how I can pass a received variadic parameter to an enclosed variadic function? I can break the array down to Single strings and delete individually but that doesn't seem very efficient


Solution

  • A variadic parameter means it is a type followed by three dots, such as String... They are used to pass in a variable amount of values of the same type. You can't pass a method's variadic parameter to another method. Inside the method it becomes an Array which can't be passed as a variadic without lots of trickery that you really don't want to bother with in this instance.

    However, we can see from the source:

    public extension RedisClient {
        /// Get the key value.
        func delete(keys: String..., callback: @escaping redisResponseCallback) {
            self.sendCommand(name: "DEL \(keys.joined(separator: " "))", callback: callback)
        }
    }
    

    That all they are doing is joining up the Array with a space as a separator. So you can add this to your own code at a top level:

    public extension RedisClient {
        /// Get the key value.
        func delete(keys: [String], callback: @escaping redisResponseCallback) {
            self.delete(keys: keys.joined(separator: " "), callback: callback)
        }
    }
    

    Then you can call it with:

    client.delete(keys: keysReceived){}
    

    Note that this only works in this particular case because, internally, the original method converts the strings in:

    delete(keys: "one", "two", "three"){}
    

    to:

    ["one", "two", "three"]
    

    then to:

    "one two three"
    

    I'm doing this manually and passing it the last string like:

    delete(keys: "one two three"){}
    

    which becomes:

    ["one two three"]
    

    and then is joined to:

    "one two three"
    

    So the final result is the same when it calls self.sendCommand.

    This will most likely not work with other variadic methods since it relies on the method using the joined method internally.