Adding methods with extensions

Sometimes, we would like to add methods to an existing class. We already know how to do this; we just need to go to its Swift source file and add a new method within the class body. However, sometimes, we cannot access the source code for the class, or it isn't convenient to make changes to it. A typical example of this situation is a class, struct, or any other type that is part of the standard language elements. For example, we might want to add a method that we can call in any Int value to initialize either a 2D or 3D point with all its elements set to the Int value.

The following lines declare a simple Point2D class that represents a mutable 2D point with the x and y elements. The class conforms to the CustomStringConvertible protocol; therefore, it declares a description computed property that returns a string representation for the 2D point. The code file for the sample is included in the swift_3_oop_chapter_08_01 folder.

    open class Point2D: CustomStringConvertible { 
      open var x: Int 
      open var y: Int 
 
      open var valuesAsDescription: String { 
        return "x: (x), y: (y)" 
      } 
 
      open var description: String { 
        get { 
          return "((valuesAsDescription))" 
        } 
      } 
 
      init(x: Int, y: Int) { 
        self.x = x 
        self.y = y 
      } 
    }

The Point2D class declares two stored properties: x and y. The valueAsDescription computed property returns a string with the values for x and y without parentheses. The description computed property encloses the value returned by valueAsDescription in parentheses.

The following lines declare a Point3D class that inherits from the previously created Point2D class and adds a z element to the inherited x and y elements. The code file for the sample is included in the swift_3_oop_chapter_08_01 folder.

    open class Point3D: Point2D { 
      open var z: Int 
 
      open override var valuesAsDescription: String { 
        return "(super.valuesAsDescription), z:(z)" 
      } 
 
      init(x: Int, y: Int, z: Int) { 
        self.z = z 
        super.init(x: x, y: y) 
      } 
    }

The Point3D class declares the z stored property and overrides the valueAsDescription computed property to concatenate the value of the z stored property to the string value of this property in the superclass. This way, the description computed property declared in the Point2D superclass will generate the values for x, y, and z enclosed within parentheses. Now that we have a Point2D class and a Point3D class, we want to extend the Int type to provide methods that generate instances of these classes with all their elements initialized with the Int value. Specifically, we want to be able to write the following line to generate a Point2D instance with the x and y values initialized to 3:

    var point2D1 = 3.toPoint2D() 

In addition, we want to be able to write the following line to generate a Point3D instance with the x, y, and z values initialized to 5:

    var point3D1 = 5.toPoint3D() 

The following lines use the extension keyword to add two methods to the Int standard type: toPoint2D and toPoint3D. The code file for the sample is included in the swift_3_oop_chapter_08_01 folder.

    public extension Int { 
      public func toPoint2D() -> Point2D { 
        return Point2D(x: self, y: self) 
      } 
 
      public func toPoint3D() -> Point3D { 
        return Point3D(x: self, y: self, z: self) 
      } 
    }

The toPoint2D method returns a new instance of Point2D with the x and y arguments of the initializer set to self. In this case, self represents the actual value for Int. The toPoint3D method returns a new instance of Point3D with the x, y, and z arguments of the initializer set to self.

The following lines use the previously added methods to create instances of both Point2D and Point3D. The code file for the sample is included in the swift_3_oop_chapter_08_01 folder.

    print(3.toPoint2D()) 
    print(5.toPoint2D()) 
    print(3.toPoint3D()) 
    print(5.toPoint3D()) 

The following lines show the output generated by the preceding code:

(x: 3, y: 3)
(x: 5, y: 5)
(x: 3, y: 3, z:3)
(x: 5, y: 5, z:5)

The following screenshot shows the results of executing the previous lines in the Playground:

Adding methods with extensions

Tip

If you have some experience with Objective-C, you will notice that extensions in Swift are very similar to categories in Objective-C. However, one of the main differences is that extensions in Swift do not have names.

Now, let's imagine that both the Point2D and Point3D classes are included in an external framework or library and that we aren't able to access the source code. Our code needs to convert instances of Point3D to a (Int, Int, Int) tuple. It is a nice feature to generate a tuple with named elements. Given that we cannot access the source code, we can use the extension keyword to add a toTuple method to the Point3D class. This way, we can easily convert a Point3D instance to a tuple. The following lines do the job. The code file for the sample is included in the swift_3_oop_chapter_08_02 folder.

    public extension Point3D { 
      public func toTuple() -> (x: Int, y: Int, z: Int) { 
        return (x: x, y: y, z: z) 
      } 
    } 

The following lines create an instance of the Point3D class and then call the recently added toTuple method to generate a tuple composed of three Int values: (Int, Int, Int). Then, the code prints the string representation of the generated tuple. The next line uses a let statement to retrieve the three elements from the tuple generated by another call to the toTuple method. Then, the code prints the values for the three retrieved elements. The last two lines use the element names (x, y, and z) and numbers (0, 1, and 2) to access the generated tuple values. The code file for the sample is included in the swift_3_oop_chapter_08_02 folder.

    var point3D1 = Point3D(x: 10, y: 20, z: 15) 
    var point3D1Tuple = point3D1.toTuple() 
    print(point3D1Tuple) 
    let (point3D1x, point3D1y, point3D1z) = point3D1.toTuple() 
    print(point3D1x, point3D1y, point3D1z) 
    print(point3D1Tuple.x, point3D1Tuple.y, point3D1Tuple.z) 
    print(point3D1Tuple.0, point3D1Tuple.1, point3D1Tuple.2)

The following lines show the output generated by the preceding code.

(10, 20, 15)
10 20 15
10 20 15
10 20 15

The following screenshot shows the result of executing the previous lines in the Playground:

Adding methods with extensions

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.158.137