Swift check if value is of type array (of any type)
Got it working like this, although it's not as beautiful as I would've hoped:
protocol ArrayType {}
extension Array : ArrayType {}
let intArray : Any = [1, 2, 3]
let stringArray : Any = ["hi", "hello", "world"]
intArray is ArrayType // true
stringArray is ArrayType // true
EDIT: I think I misunderstood your question before, now I got it though:
let intArray = [1, 2, 3]
let anyArray = intArray.map{ $0 as Any }
This is the only way to my knowledge.
Swift - Check if a value belongs is in an array
First of all, array
s define with [Type]
like [User]
Second of all init
method calls as with (Arguments)
like User(name: ,age:)
And last but not least, don't forget the ',' between elements of the array.
So
struct User: Identifiable {
var id = UUID()
var name: String
var age: String
}
var array: [User] = [
User(name: "AZE", age: "10"),
User(name: "QSD", age: "37")
]
So now you can check your element inside with contains
like
array.contains(where: { user in user.name == "AZE" }) // returns `true` if it is
Tips
Try name array
s not array. Use plural names instead like users
To returtning the found one:
users.first(where: { user in user.name == "AZE" })
To summarizing it
users.first { $0.name == "AZE" }
How to check generic class type is array?
As commentator @Holex says, you can use Any
. Combine it with Mirror
and you could, for example, do something like this:
func isItACollection(_ any: Any) -> [String : Any.Type]? {
let m = Mirror(reflecting: any)
switch m.displayStyle {
case .some(.collection):
print("Collection, \(m.children.count) elements \(m.subjectType)")
var types: [String: Any.Type] = [:]
for (_, t) in m.children {
types["\(type(of: t))"] = type(of: t)
}
return types
default: // Others are .Struct, .Class, .Enum
print("Not a collection")
return nil
}
}
func test(_ a: Any) -> String {
switch isItACollection(a) {
case .some(let X):
return "The argument is an array of \(X)"
default:
return "The argument is not an array"
}
}
test([1, 2, 3]) // The argument is an array of ["Int": Swift.Int]
test([1, 2, "3"]) // The argument is an array of ["Int": Swift.Int, "String": Swift.String]
test(["1", "2", "3"]) // The argument is an array of ["String": Swift.String]
test(Set<String>()) // The argument is not an array
test([1: 2, 3: 4]) // The argument is not an array
test((1, 2, 3)) // The argument is not an array
test(3) // The argument is not an array
test("3") // The argument is not an array
test(NSObject()) // The argument is not an array
test(NSArray(array:[1, 2, 3])) // The argument is an array of ["_SwiftTypePreservingNSNumber": _SwiftTypePreservingNSNumber]
How to check that object of type `Any` is an array of concrete class implementing some protocol
I found a workaround to solve this problem:
func classTypeFrom(_ className: String) -> AnyClass!{
if let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String {
let classStringName = "_TtC\(appName.characters.count)\(appName)\(className.characters.count)\(className)"
return NSClassFromString(classStringName)
}
return nil;
}
func update(object: Any){
if let array = object as? [Initiatable]{
let arrayTypeName = "\(type(of: ar))"
let objectTypeName = arrayTypeName.substringFrom(index: 6, length: arrayTypeName.characters.count - 7)
if let arrayType = classTypeFrom(objectTypeName) as? Initiatable.Type{
process(array: array, type: arrayType)
}
}
}
func process(array: [Initiatable], type: Initiatable.Type){
var ar = array
let newObj = type.init()
ar.append(newObj)
}
Checking if an object is a given type in Swift
If you want to check against a specific type you can do the following:
if let stringArray = obj as? [String] {
// obj is a string array. Do something with stringArray
}
else {
// obj is not a string array
}
You can use "as!" and that will throw a runtime error if obj
is not of type [String]
let stringArray = obj as! [String]
You can also check one element at a time:
let items : [Any] = ["Hello", "World"]
for obj in items {
if let str = obj as? String {
// obj is a String. Do something with str
}
else {
// obj is not a String
}
}
Array of objects that have specific type
You can use the short and simple is
attribute.
which in your case will be:
switch objects[indexPath.row] {
case is DogDetailModel:
return DogTableCell
case is CatDetailModel:
return CatTableCell
default:
return AnimalTableCell
}
Checking if a metatype is an Array with an Element type of kind MyProtocol
The problem is that while instances of [MyDto]
can be freely converted to [MappableProtocol]
and [Any]
, these are really just magical conversions that the compiler does behind the scenes (see this Q&A for more information).
The same conversions don't exist for metatype values, which is why Swift says that a [MyDto].Type
is not a [MappableProtocol].Type
nor a [Any].Type
– they are unrelated metatype types.
Likely the simplest solution in your case would just be to forget working with metatypes, and instead just declare different overloads of test(a:)
to handle different ResponseType
types.
// 'default' overload of test(a:)
func test<T : ResponseProtocol>(a: T) -> String {
return "notFound"
}
func test<T : ResponseProtocol>(a: T) -> String where T.ResponseType == String {
return "String"
}
func test<T : ResponseProtocol>(a: T) -> String where T.ResponseType : MappableProtocol {
return "MappableProtocol"
}
func test<T : ResponseProtocol>(a: T) -> String where T.ResponseType == [MyDto] {
return "Array<MDto>"
}
// overload of test(a:) that accepts a type that conforms to ResponseProtocol, where the
// ResponseType is an Array with arbitrary Element type.
func test<T : ResponseProtocol, ResponseTypeElement : MappableProtocol>(a: T) -> String
where T.ResponseType == [ResponseTypeElement]
{
return "Array<MappableProtocol>"
}
print(test(a: A1())) // String
print(test(a: A2())) // MappableProtocol
print(test(a: A3())) // Array<MyDto>
// A MappableProtocol with a ResponseType that conforms to MappableProtocol,
// but isn't MyDto.
class Foo : MappableProtocol { required init(map: String) { } }
class A4 : ResponseProtocol { typealias ResponseType = [Foo] }
print(test(a: A4())) // Array<MappableProtocol>
(I removed your API
class just to simplify things)
The compiler will simply resolve which overload to call at compile time, rather than having the runtime jump through lots of type-casting hoops.
If you insist on working with metatype values, one possible solution is to define a dummy protocol for Array
to conform to (see for example this similar Q&A), which we can then cast the metatype values to. We can then declare an elementType
static requirement in order to extract the Array
's Element.self
metatype value, which we can then inspect the type of in order to determine what the array is convertible to.
For example, if we define and conform Array
to _ArrayProtocol
:
protocol _ArrayProtocol {
static var elementType: Any.Type { get }
}
extension Array : _ArrayProtocol {
static var elementType: Any.Type {
return Element.self
}
}
We can now use test(a:)
like so:
func test<T : ResponseProtocol>(a: T) -> String {
if T.ResponseType.self is String.Type {
return "String"
}
if T.ResponseType.self is MappableProtocol.Type {
return "MappableProtocol"
}
// attempt to cast the T.ResponseType.self metatype value to the existential metatype
// type _ArrayProtocol.Type (i.e a type that conforms to _ArrayProtocol),
// in this case, that's only ever Array.
if let responseType = T.ResponseType.self as? _ArrayProtocol.Type {
// switch on the element type, attempting to cast to different metatype types.
switch responseType.elementType {
case is MyDto.Type:
return "Array<MyDto>"
case is MappableProtocol.Type:
return "Array<MappableProtocol>"
default:
return "Array<Any>"
}
}
return "notFound"
}
print(test(a: A1())) // String
print(test(a: A2())) // MappableProtocol
print(test(a: A3())) // Array<MyDto>
print(test(a: A4())) // Array<MappableProtocol>
Related Topics
"Ambiguous Use of 'Children'" When Trying to Use Nstreecontroller.Arrangedobjects in Swift 3.0
Codable Decode Property with Multiple Object Types Based on Another Value
Disable Email Detection in Swiftui's Text
Could Not Cast Value of Type Uiview to [Customview] Using Xib
How to Make a Function with a Loop Asynchronous in Swift
Contextual Member Has No Associated Value in Swift 3
Need Clarification for Swift Type Properties
Implementing a 'Report' Feature for Inappropriate Content Swift Firebase
Expanding Uitextview Inside a Stack View with Scrolling Enabled
Binary Operator '==' Cannot Be Applied to Operands of Type 'Uilabel' and 'String'
Simple Swift Class Does Not Compile
How to Integrate Mapbox Sdk with Swiftui
Cannot Stop Background Music from Within Game Scenes, Swift 3/Spritekit
Change Mkmarkerannotationview Size
When Two Optionals Are Assigned to an If Let Statement, Which One Gets Unwrapped? Swift Language
With Data (Not Nsdata), in Fact How Actually Do You Make a Utf8 Version of a Jpeg