You can simply conditionally cast [T?]
to [T]
, this succeeds exactly if the array contains no nil elements:
let x: [Int?] = [1, 2, 3, 4]
print(x as? [Int]) // Optional([1, 2, 3, 4])
let y: [Int?] = [1, 2, nil, 3, 4]
print(y as? [Int]) // nil
As an extension method of Array
that would be
extension Array {
func someFunction<T>() -> [T]? where Element == Optional<T> {
return self as? [T]
}
}
Previous, more complicated solutions:
You can use compactMap()
to get the non-nil elements, and then check if that is the same number as the original number of elements:
extension Array {
func someFunction<T>() -> [T]? where Element == Optional<T> {
let nonNils = compactMap { $0 }
return nonNils.count == count ? nonNils : nil
}
}
(The approach from Swift: Extension on [<SomeType<T>?] to produce [<T>?] possible? is used here to define an extension method for arrays of optional elements.)
Examples:
let x: [Int?] = [1, 2, 3, 4]
print(x.someFunction()) // Optional([1, 2, 3, 4])
let y = [1, 2, nil, 3, 4]
print(y.someFunction()) // nil
An alternative, just for fun: If you define an “unwrap or throw” method for optionals
extension Optional {
struct FoundNilError : Error { }
func unwrapOrThrow() throws -> Wrapped {
switch self {
case .some(let wrapped) : return wrapped
case .none: throw FoundNilError()
}
}
}
then you can use that with map
and the “optional try”:
extension Array {
func someFunction<T>() -> [T]? where Element == Optional<T> {
try? map { try $0.unwrapOrThrow() }
}
}
As soon as a nil element is found, map
throws an error, and try?
returns nil
.