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?
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With