Let’s get more know about Swift Generic Class

Danny Santoso
5 min readDec 27, 2022
Photo by Maxwell Nelson on Unsplash

In the Swift programming language, a generic class is a class that can work with different types in a type-safe manner. A generic class has one or more type parameters, which are placeholders for the specific types that the class will work with.

To create a generic class in Swift, basically, you can use angle brackets (<>) after the class name to specify the type parameters. For example, you could create a generic class called “MyClass” with a single type parameter called “T” like this:

class MyClass<T> {
// Class Implementation goes here
}

In this example, “MyClass” is a generic class with a type parameter called “T”. This type parameter can be used within the class implementation to declare properties and methods that are related to the type “T”.

For example, you could use the type parameter to declare a property of type “T” like this:

class MyClass<T> {
var someProperty: T

init(property: T) {
self.someProperty = property
}
}

In this example, the “someProperty” property of “MyClass” is declared to have the same type as the “T” type parameter. This means that if “MyClass” is instantiated with a specific type for “T”, the “someProperty” property will have that same type.

For example, if you instantiate “MyClass” with the type “String” for “T”, the “someProperty” property will be of type “String”:

let myClass = MyClass<String>("Hello")
print(type(of: myClass.someProperty))
// output will be : "String"

In this way, you can use the type parameter of a generic class to specify the type of properties and methods within the class, and the type of those properties and methods will be determined by the type that is used when the class is instantiated.

Constraint

a generic class can have one or more type parameters, and each type parameter can have one or more type constraints. A type constraint specifies the requirements that the type parameter must satisfy in order to be used with the class.

To add a type constraint to a type parameter in a generic class, you use a colon (:) after the type parameter name, followed by one or more protocol or class names that the type parameter must conform to or inherit from. For example, you could create a generic class called “MyClass” with a type parameter called “T” that has a type constraint specifying that “T” must be a subclass of “NSManagedObject” like this:

class MyClass<T: NSManagedObject> {
// Class Implementation goes here
}

In this example, the “MyClass” class has a type parameter called “T” that has a type constraint specifying that “T” must be a subclass of “NSManagedObject”. This means that when “MyClass” is instantiated with a specific type for “T”, that type must be a subclass of “NSManagedObject” in order to be used with the class.

For example, if you want to use “MyClass” with the type “MyManagedObject”, which is a subclass of “NSManagedObject”, you would instantiate “MyClass” like this:

let myClass = MyClass<MyManagedObject>()

Where Clause

there is another approach for us to specify the requirements of the type parameter, that is using the Where clause.

the constraint of the parameter can be used in the `where` clause. the “where” keyword is used in generic class and function declarations to specify constraints on the type parameters. A type constraint specifies the requirements that the type parameter must satisfy in order to be used with the class or function.

To add a type constraint to a type parameter in a generic class or function, you use the “where” keyword after the list of type parameters, followed by a condition that must be satisfied by the type parameter. For example, you could create a generic class called “MyClass” with a type parameter called “T” that has a type constraint specifying that “T” must be a subclass of “NSManagedObject” like this:

Class MyClass<T> where T:NSManagedObject {
// Class implementation goes here
}

In this example, the “MyClass” class has a type parameter called “T” that has a type constraint specifying that “T” must be a subclass of “NSManagedObject”. This means that when “MyClass” is instantiated with a specific type for “T”, that type must be a subclass of “NSManagedObject” in order to be used with the class.

For example, if you want to use “MyClass” with the type “MyManagedObject”, which is a subclass of “NSManagedObject”, you would instantiate “MyClass” the same as the previous example, which is like this:

let myClass = MyClass<MyManagedObject>()

the two ways of declaring a generic class with a type constraint are equivalent and will have the same effect.

In the first example, you use a colon (:) after the type parameter name to specify the type constraint, In this example, the “MyClass” class has a type parameter called “T” that has a type constraint specifying that “T” must be a subclass of “NSManagedObject”. This means that when “MyClass” is instantiated with a specific type for “T”, that type must be a subclass of “NSManagedObject” in order to be used with the class.

In the second example, you use the “where” keyword after the list of type parameters to specify the type constraint, This example is identical to the first example, except that the type constraint is specified using the “where” keyword instead of using a colon (:) after the type parameter name.

Generic Class with 2 Parameter

If you want to have multiple type parameters in a generic class and each type parameter has a different type constraint, you can specify the constraints using the “where” keyword after the list of type parameters.

For example, you could create a generic class called “MyClass” with two type parameters called “T” and “U”, where “T” must be a subclass of “NSManagedObject” and “U” must conform to the “Equatable” protocol, like this:

Class MyClass<T, U> where T: NSManagedObject, U: Equatable {
// Class implementation goes here
}

In this example, the “MyClass” class has two type parameters called “T” and “U”. The “T” type parameter has a type constraint specifying that it must be a subclass of “NSManagedObject”, and the “U” type parameter has a type constraint specifying that it must conform to the “Equatable” protocol. This means that when “MyClass” is instantiated with specific types for “T” and “U”, those types must satisfy the constraints in order to be used with the class.

Generic Class and Generic Function

Basically, you also can use generic in a function, that is used to write a function that is flexible and reusable, without the need to specify the type of data it will be working with until you use it in your code.

To define a generic function in Swift, you use the same <T> syntax as for a generic class. For example:

func reverse<T>(array: [T]) -> [T] {
// function implementation goes here
}

You can use generic classes and functions to make your code more flexible and reusable, and to avoid having to write multiple versions of the same code for different data types.

Sum up

generics are a way to write code that can work with any type, rather than being specific to a single type. This allows you to write flexible and reusable code that can be used in a variety of contexts, without the need to specify the exact type of data it will be working with until you use it in your code. You can use generics in both classes and functions in Swift.

Reference

--

--

Danny Santoso

not a wizard, nor a sage. only an apprentice who keeps intensifying his intelligence to form great magic.