What is the type of a Swift Type? - swift

I want to pass an array of types to a function - but I'm not sure what is the type of a Swift Type.
Let's say I have two classes:
MyClass and AnotherClass.
I want an array like this [MyClass, AnotherClass].
What will be the type of the array?

It would be of AnyClass type which is base for all object types.
func checkClassTypes(types: [AnyClass]) {
types.forEach { type in
// Your custom classes don't necessarily have to subclass from NSObject.
print(type is NSObject.Type)
}
}
checkClassTypes([MyClass.self, AnotherClass.self])

If you need to contain only class types, AnyClass will works:
class MyClass {
//...
}
class AnotherClass {
//...
}
let classTypes: [AnyClass] = [MyClass.self, AnotherClass.self]
If you want to include some value types, you may need to use Any or Any.Type:
let types: [Any] = [Int.self, String.self, MyClass.self, AnotherClass.self]
let anyTypes: [Any.Type] = [Int.self, String.self, MyClass.self, AnotherClass.self]
But all three types, AnyClass, Any or Any.Type, are hard to use. You will soon find it is very hard just to instantiate a class in the array.

I'm not sure I understand your question about Swift Types correctly, but Swift doesn't specify a Type as being a certain kind of variable. Swift defines that variables in code can have a certain type, which can be a float, a string, integer, etc. When it is said that Swift is type safe and infers a type, this means that Swift requires you to be clear on the type of values that you store in your variables (type safety) and that Swift will try to infer what type a variable is when you specify a value (type inference).
The type of your variable can also be more complex, like an enum, a struct or a class. Swift even sees an array or other collections as types. In this sense a Type could be defined as a piece of memory in which a constant or a variable (or a collection of these) is stored. A type can be different things. The great thing about having a Type as a constant/variable in which I store information, is that I can now defer the type of a variable until runtime, rather than that I have to specify it in my code. Or I can specify a structure of a generic type and later I can define different kinds of variables with the same structure, but of different types. Please, read for a more detailed understanding of dealing with types the Swift programming language from Apple. It is free and can be downloaded in the iBooks Store.
Now coming back to your second question of an array of [MyClass, AnotherClass] is kind of like deferring the types of your array until later. You can initially define your array as an array of AnyObjects or more swift-like AnyClass, like
myArray = [AnyClass]()
Later you can put different types of variables/objects in that array, like a Double, a String, or an object with a specific class.
You should be careful about building such an array, however. This array is not type safe and you haven't specified the type of object at a certain index. To prevent xcode having trouble with your code and your program from crashing, you should always type cast the individual objects in your array. For instance like
if let myObject = myArray[2] as? myClass { do something }
If you don't typecast your array both xcode and your program will do weird things.
I hope this answered your question.
Kind regards,
MacUserT

I'm guessing that you really want to create an array of instances of the two classes rather than an array of the class definitions. If so, you will be creating an array of Any or AnyObject, not AnyClass.
class MyClass {
}
class OtherClass {
}
let m = MyClass()
let o = OtherClass()
let array1 = [m, o] as [Any]
// or
let array2 = [m, o] as [AnyObject]

Related

What exactly is a metatype in Swift?

I am very confused around the concept of "metatype" in the Swift language.
Suppose I have:
class SomeClass {
class func callClassMethod() {
print("I'm a class method. I belong to my type.")
}
func callInstanceMethod() {
print("I'm an instance method. I belong to my type instance.")
}
}
According to the definition:
A metatype type refers to the type of any type, including class types,
structure types, enumeration types, and protocol types.
SomeClass is already a type called SomeClass, then what exactly is the type of SomeClass?
I can create a SomeClass.Type variable:
let var1 : SomeClass.Type = SomeClass.self
var1.doIt();//"I'm a class method. I belong to my type."
but I can also call the static/class function this way:
SomeClass.doIt();//"I'm a class method. I belong to my type."
Are they the same?
They are the same because the compiler guarantees that class names are unique (Swift is name spaced by module), so there is only one thing that is of SomeClass.Type and that is the class SomeClass. The meta type is often useful when you just want to pass the type of something to a function but you don't want to pass an instance. Codable does this for instance:
let decoded = try decoder.decode(SomeType.self, from: data)
If you could not pass the meta type here then the compiler could still infer the return type based on an annotation on the left, but it would be less readable:
let decoded: Sometype = try decoder.decode(data)
Some libraries do use the type inference style instead, although the Apple preference seems to be to use the meta type as its clearer what the right side of the assignment is on its own, without relying on type inference from the left side of the assignment.

Get Type from Metatype

I'm struggling to understand the different between Types and Metatypes in swift 4. In particular I am looking to create an array something like this:
class A { ... }
class B {
func doStuff() {
let otherType = A.self
let itemArr : [otherType] = // Objects of type A
}
}
This throws a compile time error of Use of undeclared type 'otherType' which I think is occurring because otherType is actually A.Type. I think this may have something to do with Generics, but the catch is the type might not be known at compile time...
Is there a solution to this problem?
Swift is powerful because you can pass types as parameters and create variable of types. This is attractive, but yet, there is better solution for your issue.
Define protocol CustomArrayPopulatable {} And add this to all subclasses/classes that could be added to the array. E.G. A1: CustomArrayPopulatable ; A2: CusstomArrayPopulatable.
With generic types, you could achieve great abstraction. However, have in mind, if you need to cast to specific subtype later on, you would need to cast it yourself such as: if type as? A1 {...}, so use generics carefully and think before you start, do you really need them.

swift use of AnyClass object with as?

I would like to do this:
let myClass: AnyClass = functionReturningClass() // ex. String.self
if let myObject = functionReturningObject() as? myClass { ...
The as? myClass doesn't compile ('myClass is not a type'). What can I do?
Unfortunately this is not possible--as must know the type it is casting to at compile-time. You cannot provide a variable type to as. If you must cast, then you are limited to features like generics and overloading that work at compile-time.
Think about it--what methods should the compiler allow you to call on the resulting myObject? It's impossible to say without knowing the runtime value of myClass. It makes good sense, therefore, that this doesn't work.
You can still return subclasses from functionReturningObject(). You can still cast them to different types. You just can't decide what type to cast them to dynamically at runtime.

The difference between an any type and a generic type in swift

What is the difference between an any type and generic type in swift?
Any Type Example:
let swiftInt: Int = 1
let swiftString: String = "miao"
var array: [Any] = []
array.append(swiftInt)
array.append(swiftString)
Generic Type Example:
func duplicate<T>(item: T, numberOfTimes n: Int) -> [T] {
var buffer : [T] = []
for _ in 0 ..< n {
buffer.append(item)
}
return buffer
}
Is this a matter of preference because both appear to solve the same problem by being able to substitute the desired type.
I'm not going to explain generics in details and i'll just point out the essential differences.
In the first example, you'll be able to append any type in that array, without being able to restrict beforehand your array to a specific type and to leverage compile time checks to guarantee that the array will not contain extraneous types. Not much to see in that example.
The second example contains instead a generic function that provides all of the above functionalities, consistency checks on the content of the array will come for free and if you want you'll also be able to specify additional characteristics of that generic type T, like requesting that it implements a specific protocol (e.g. limit duplicate() to object that implement Comparable or Equatable).
But that is just a simple example of a generic function, you can also have parametrized classes (what you'll use the most) and there are a lot of additional functionalities.
Never use Any as a poor-man generics, real generics are way more flexible, add useful checks and make more explicit your intentions, with minimal additional effort required to implement them.
Any means "I don't want any type checking and I won't be able to call type-specific methods without casting"
For example, try to call:
var array: [Any] = [1, 2]
var sum = array[0] + array[1] // you cannot do this! you have to cast to Int first
A generic type is a placeholder for a type. When used, a concrete type is used instead of it (e.g. an Int or a String).
In short, never use Any. There are very very few specific situations when Any is what you want to use.

Store type in variable to use like a type later

I'm trying to store a type in a variable so that I can use it like a 1st class type later on.
class SomeModel {}
let someType = SomeModel.self
let array = Array<someType>()
In this case sure I could have done Array<SomeModel>() instead but I want to generalize it and let subclasses provide the value of someType.
However I get errors like someType isn't a type or use of undeclared type 'someType' on the last line.
If you need to store several type values in array, this works pretty well:
let array: [Any.Type] = [String.self, Int.self]
func someFunc<T>(model: T) -> Array<T> {
let array = Array<T>()
return array
}
let someType = SomeModel.self
let array = someFunc(someType())
Looks like this does what I want. The only drawback is that I have to create an instance of the desired type to pass. In this case its minimal overhead, but it just seems like a waste.
Another thing with using generics like this is it appears that the generic's possible types are computed at compile time, so at run time model.dynamicType doesn't necessarily match T. In most cases it will, but if you are doing any reflection driven stuff make sure to really check your use case well.
These days, this can be more easily and adaptably achieved by using .Type on a class or protocol. Note that only functions available to that root class or protocol will be accessible however, so you should ensure that a required initialiser of some kind is defined. For example:
protocol MyClass {
init(someValue: Int)
}
class MyWrapper {
let myClassType: MyClass.Type
init(classType: MyClass.Type) {
self.myClassType = classType
}
func new(with value: Int) -> MyClassType {
return MyClassType.init(someValue: value)
}
}
You can now initialise this rather silly factory class with a specific class implementing the MyClass protocol and when you call the new() function with an integer value it will generate a new instance of that class and return it.