Oleg Gordiichuk
Oleg Gordiichuk

Reputation: 15512

Is it an optimal way in Swift for the function to return more than 2 types?

I need to have function that should return secure random String or Data with future possible extension with other types.

I start looking for the suggestions and find out that this could be done via Enums and Tuples.

I decide to proceed with Enums.

My implementation:

enum SecureRandomInput {
    case forString
    case forData
}


enum SecureRandomOutput {
    case forString(String)
    case forData(Data)

    static func generate(with type: SecureRandomInput, bytesCount: Int) -> SecureRandomOutput {
        var randomBytes = [UInt8](repeating: 0, count: bytesCount)
        let _ = SecRandomCopyBytes(kSecRandomDefault, bytesCount, &randomBytes)
        switch type {
        case .forString:
            return SecureRandomOutput.forString(randomBytes.map({ String(format: "%02hhx", $0) }).joined(separator: ""))
        case .forData:
            return SecureRandomOutput.forData(Data(bytes: randomBytes, count: bytesCount))
        }
    }
}

So questions are:

1) Usage of the Enums in particular situation is more flexible than Tuples?

2) Do you have any suggestions about that part of code? (What could be done better)

3) Are any other ways how we could achieve required behavior in Swift 4? (without Enums and Tuples)

Upvotes: 1

Views: 89

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 52043

Another way to go is with closures and generics

func generate<T>(bytesCount: Int, convert: ([UInt8]) ->T ) -> T {
    var randomBytes = [UInt8](repeating: 0, count: bytesCount)
    let _ = SecRandomCopyBytes(kSecRandomDefault, bytesCount, &randomBytes)
    return convert(randomBytes)
}

let x = generate(bytesCount: 7) {
    return Data(bytes: $0, count: $0.count)
}

let y = generate(bytesCount: 7) { bytes in
    return bytes.map({ String.init(format: "%02hhx", $0) }).joined(separator: "")
}

Upvotes: 1

pacification
pacification

Reputation: 6018

  1. I agree with you, that enum is more clear way to separate different behavior instead of creating massive tuple.

  2. Code is pretty standard.

  3. IMO, this situation also can be handled by regular class or struct if there are any kind of large amount of shared data for both results (init/generate some things, like SecRandomCopyBytes(kSecRandomDefault, bytesCount, &randomBytes) or so). For now it's good, but in future it can be one option to refactoring the code.

Upvotes: 1

Related Questions