Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to abort a map function on a Swift collection?

We have a case where we're being handed an object of type Array<Any> which we need to convert to an Array<Codable>. If any of the items in the original array don't adhere to Codable, then we want the entire thing to abort and return nil.

Or current approach is to manually loop over everything, testing along the way, like so...

func makeCodable(sourceArray:Array<Any>) -> Array<Codable>?{

    var codableArray = Array<Codable>()

    for item in sourceArray{

        guard let codableItem = item as? Codable else {
            return nil
        }

        codableArray.append(codableItem)
    }

    return codableArray
}

However, I'm wondering if there's an easier way to do this with the map command, but it would require it to short-circuit if any of the elements can't be mapped. That's what I'm not sure or not is possible.

For instance, this pseudo-code...

func makeCodable(sourceArray:Array<Any>) -> Array<Codable>?{

    return sourceArray.map({ $0 as? Codable});
}

Is this possible, or is our original way the correct/only way?

like image 863
Mark A. Donohoe Avatar asked Sep 18 '25 05:09

Mark A. Donohoe


1 Answers

Here's one solution using map and throws.

func makeCodable(sourceArray: [Any]) -> [Codable]? {
    enum CodableError: Error {
        case notCodable
    }

    let res: [Codable]? = try? sourceArray.map {
        guard let codable = $0 as? Codable else {
            throw CodableError.notCodable
        }

        return codable
    }

    return res
}

let res = makeCodable2(sourceArray: [5, 6.5, "Hi", UIView()])
print(res) // nil

Here's a variation that makes makeCodable throw and return a non-optional array:

enum CodableError: Error {
    case notCodable
}

func makeCodable(sourceArray: [Any]) throws -> [Codable] {
    let res: [Codable] = try sourceArray.map {
        guard let cod = $0 as? Codable else {
            throw CodableError.notCodable
        }

        return cod
    }

    return res
}

do {
    let res = try makeCodable(sourceArray: [5, 6.5, "Hi"])
    print(res) // prints array
    let bad = try makeCodable(sourceArray: [5, 6.5, "Hi", UIView()])
    print(bad)
} catch {
    print(error) // goes here on 2nd call
}
like image 94
rmaddy Avatar answered Sep 19 '25 20:09

rmaddy