In this blog we will be exploring the topics Initializers in swift, Interoperability between swift and Objective C, inout and mutating keywords in swift
Initializers in Swift
Initialization is process of setting up new instance for a particular type. Any setup that need to be done before the first uses of the object can be done here. The special function, which facilitates this process, is init. A default initializer is provided and thus it is not mandatory to implement an initializer
Please note the class and struct in the code below is an example where the default initializer is used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/* Class declaration start */ class SomeArbitraryPoint{ var xArbitrary:Int = 0; var yArbitrary:Int = 0; func getAnAribitararyPoint(var aPoint:SomeArbitraryPoint) -> SomeArbitraryPoint { aPoint.xArbitrary = 3 return aPoint } } /* Class declaration end */ var aPoint = SomeArbitraryPoint() /* Struct declaration start */ struct SomeArbitraryPoint{ var xArbitrary:Int = 0; var yArbitrary:Int = 0; func getAnAribitararyPoint(var aPoint:SomeArbitraryPoint) -> SomeArbitraryPoint { aPoint.xArbitrary = 3 return aPoint } } /* Struct declaration start */ var aPoint = SomeArbitraryPoint() |
Initializer can have parameters and you should have guessed by now what Failable Initializers represent. A Failable Initializers cane be compared to an optional initializer.
The following code is an example class that implement initializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class SomeIntegerValueWrapper{ var value:Int? //simple initializer init(){ value = 10; } // initializer with parameter init(value:Int){ self.value = value } // failable with parameter init?(valueString:String){ //the intializer used by itself is a failable. The obvious reason being the fact that a string with "ABC" will fail to be converted to an int value self.value = Int(valueString) if(self.value == nil){ // retrun nil implies the initialization failed return nil; } } } |
In the above example the failable initializer returns a nil if the initialization process fails.
Designated and Convenience Initializer
The designated initializers are the main initializers for a particular type. A Convenience Initializer on the other hand is an initializer that which uses a designated initializer within itself to initialize the type
All the initializer implemented in the above class SomeIntegerValueWrapper are an example of a designated initializer.
The following code we have re-written the same class with convenience initializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class SomeIntegerValueWrapper{ var value:Int? // convenience initializer convenience init(){ self.init(value: 10) } // initializer with parameter init(value:Int){ self.value = value } } |
“required” keyword with initializer
By using the required keyword with an initializer for a particular type (lets say class SomeClass), we are telling the compiler that it is a mandate to implement this initializer while sub classing the type (i.e. SomeClass)
If an initializer is marked with required keyword then while sub classing
It is mandate that the initializer marked with required keyword is implemented.
Required modifier should be present with implementation of required initializer in subclass as well
The sample code below depicts required initializer implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class SomeClass{ required init(){ //write the implementation for SomeClass } } class SomeSubClass:SomeClass{ required init(){ //write the implementation for SomeSubClass } } |
Interoperability with Objective C
Interoperability need to be considered with two perspective. Lets discuss each of these.
- Using Objective C implementation within Swift
- Using Swift implementation within Objective C
The former works well and in almost all the cases the developer will be able to use Objective C with Swift without any hurdle. However the latter 100% inter operability is not possible. Let look into the aspects that one should be aware of so that interoperability in each of the above can be achieved.
- Objective C implementation within Swift
It is the bridging header where you have to import the objective C header file that you need to expose to the swift. While you create or add an Objective C file to a swift iOS project, Xcode suggest to create a bridging header with name “<replace project name>-Bridging-Header.h” . The bridging header can be specified in the build setting tab of the iOS Project as well(i.e. a developer can manually create a bridging header and specify the same in the Swift Compiler – Code Generation section of build settings tab). You can also import the Objective C framework in the same manner by specifying it in the bridging header and thus the framework can be made available to be used in the swift class.
- Using Swift implementation within Objective C
In this case the build tool creates the header file for us, which need to be imported in the Objective C files to expose the swift class to Objective C. Name of the header can be found at the Swift Compiler – Code Generation section of build settings tab for the property Objective-C Generated Interface Header Name. You will notice that the Objective C bridging header is required for our project to compile even if we are not trying to expose any Objective C to swift . For using the swift class we will import the Objective-C Generated Interface Header Name to our Objective C file and use the @class directive for forward declaration of the class.
- inout , mutating keywords in swift
These keywords are those that need to be explained with value types in swift. Sounds confusing, not to worry, let me re-iterate the fact that you all might have observed with introduction of swift language. Apple is more focused and promoting the usage of value types and minimize usage of reference types.
As said most of the data type introduce with swift are value type . If the inout keyword is used with a function signature then it is the reference of the variable that which is passed to the function and any modification made to the variable inside the function affect the original variable as well on contrary to the actual value type behavior. The example code will show the above-mentioned case, which uses the inout keyword and that which does not use inout keyword.
Using inout keyword can be compared to pass by reference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
var someValue:Int = 10; func findSquare(inout value:Int){ value = value * value } findSquare(&someValue); print(someValue) // 100 will be printed to console Without the inout keyword the function can be compared to pass by value someValue = 10; func findSquare(var value:Int){ value = value * value } findSquare(someValue); print(someValue) // 10 will be printed to console |
Struct are designed keeping immutability in mind. However in all the situation this wont work and in such case explicitly mention/ marking a method mutating makes the method capable to mutate the value/members of struct instance.
The following show how mutating modifier can be used along with structs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
struct SampleStruct { var someValue:Int // mutating modifier in a mandate here or else compile time error will be throw mutating func changeSomeValue(value:Int){ someValue = value } // mutating modifier can be used to change the actual struct object instance mutating func resetSelf(){ self = SampleStruct(someValue: 10) } func printValue(){ print(someValue) } } |
As said in the comment if you want to change the value it is a mandate that mutating keyword is used and the compiler enforces the same. On additional note you might have noticed what the resetSelf function in the above example does. This function utilizes the capability of mutating keyword to change the struct instance itself.
Hope you have enjoyed reading. Watch this space The Swifty Way ! – Exploring Beyond
Leave a Reply