- Swift - Access Control
- Swift - Generics
- Swift - Protocols
- Swift - Extensions
- Swift - Type Casting
- Swift - Optional Chaining
- Swift - ARC Overview
- Swift - Deinitialization
- Swift - Initialization
- Swift - Inheritance
- Swift - Subscripts
- Swift - Methods
- Swift - Properties
- Swift - Classes
- Swift - Structures
- Swift - Enumerations
- Swift - Closures
- Swift - Functions
- Swift - Dictionaries
- Swift - Sets
- Swift - Arrays
- Swift - Characters
- Swift - Strings
- Swift - Loops
- Swift - Decision Making
- Swift - Operators
- Swift - Literals
- Swift - Constants
- Swift - Tuples
- Swift - Optionals
- Swift - Variables
- Swift - Data Types
- Swift - Basic Syntax
- Swift - Environment
- Swift - Overview
- Swift - Home
Swift Useful Resources
Selected Reading
- Who is Who
- Computer Glossary
- HR Interview Questions
- Effective Resume Writing
- Questions and Answers
- UPSC IAS Exams Notes
Swift - Optional Chaining
The process of querying, calpng properties, subscripts and methods on an optional that may be nil is defined as optional chaining. Optional chaining return two values −
if the optional contains a value then calpng its related property, methods and subscripts returns values
if the optional contains a nil value all its its related property, methods and subscripts returns nil
Since multiple queries to methods, properties and subscripts are grouped together failure to one chain will affect the entire chain and results in nil value.
Optional Chaining as an Alternative to Forced Unwrapping
Optional chaining is specified after the optional value with ? to call a property, method or subscript when the optional value returns some values.
Optional Chaining ? | Access to methods,properties and subscriptsOptional Chaining ! to force Unwrapping |
? is placed after the optional value to call property, method or subscript | ! is placed after the optional value to call property, method or subscript to force unwrapping of value |
Fails gracefully when the optional is nil | Forced unwrapping triggers a run time error when the optional is nil |
Program for Optional Chaining with !
class ElectionPoll { var candidate: Pollbooth? } lass Pollbooth { var name = "MP" } let cand = ElectionPoll() let candname = cand.candidate!.name
When we run the above program using playground, we get the following result −
fatal error: unexpectedly found nil while unwrapping an Optional value 0 Swift 4 0x0000000103410b68 llvm::sys::PrintStackTrace(__sFILE*) + 40 1 Swift 4 0x0000000103411054 SignalHandler(int) + 452 2 pbsystem_platform.dypb 0x00007fff9176af1a _sigtramp + 26 3 pbsystem_platform.dypb 0x000000000000000b _sigtramp + 1854492939 4 pbsystem_platform.dypb 0x00000001074a0214 _sigtramp + 1976783636 5 Swift 4 0x0000000102a85c39 llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329 6 Swift 4 0x0000000102d320b3 llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*, std::__1::vector<std::__1::basic_string, std::__1::allocator >, std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&, char const* const*) + 1523 7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift 4::CompilerInstance&, std::__1::vector<std::__1::basic_string, std::__1::allocator >, std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions const&) + 1066 8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef, char const*, void*) + 5275 9 Swift 4 0x0000000102754a6d main + 1677 10 pbdyld.dypb 0x00007fff8bb9e5c9 start + 1 11 pbdyld.dypb 0x000000000000000c start + 1950751300 Stack dump: 0. Program arguments: /Apppcations/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/ usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 - target-cpu core2 -sdk /Apppcations/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/ SDKs/MacOSX10.10.sdk -module-name main /bin/sh: pne 47: 15672 Done cat << SWIFT 4 import Foundation </std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std:: __1::basic_string
The above program declares election poll as class name and contains candidate as membership function. The subclass is declared as poll booth and name as its membership function which is initiapzed as MP . The call to the super class is initiapzed by creating an instance cand with optional ! . Since the values are not declared in its base class, nil value is stored thereby returning a fatal error by the force unwrapping procedure.
Program for Optional Chaining with ?
class ElectionPoll { var candidate: Pollbooth? } class Pollbooth { var name = "MP" } let cand = ElectionPoll() if let candname = cand.candidate?.name { print("Candidate name is (candname)") } else { print("Candidate name cannot be retreived") }
When we run the above program using playground, we get the following result −
Candidate name cannot be retreived
The program above declares election poll as class name and contains candidate as membership function. The subclass is declared as poll booth and name as its membership function which is initiapzed as MP . The call to the super class is initiapzed by creating an instance cand with optional ? . Since the values are not declared in its base class nil value is stored and printed in the console by the else handler block.
Defining Model Classes for Optional Chaining & Accessing Properties
Swift 4 language also provides the concept of optional chaining, to declare more than one subclasses as model classes. This concept will be very useful to define complex models and to access the properties, methods and subscripts sub properties.
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var street: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let rectname = rectangle() if let rectarea = rectname.print?.cprint { print("Area of rectangle is (rectarea)") } else { print("Rectangle Area is not specified") }
When we run the above program using playground, we get the following result −
Rectangle Area is not specified
Calpng Methods Through Optional Chaining
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("Area of Circle is: (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") }
When we run the above program using playground, we get the following result −
Area of circle is not specified
The function circleprint() declared inside the circle() sub class is called by creating an instance named circname . The function will return a value if it contains some value otherwise it will return some user defined print message by checking the statement if circname.print?.circleprint() != nil .
Accessing Subscripts through Optional Chaining
Optional chaining is used to set and retrieve a subscript value to vapdate whether call to that subscript returns a value. ? is placed before the subscript braces to access the optional value on the particular subscript.
Program 1
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if let radiusName = circname.print?[0].radiusname { print("The first room name is (radiusName).") } else { print("Radius is not specified.") }
When we run the above program using playground, we get the following result −
Radius is not specified.
In the above program the instance values for the membership function radiusName is not specified. Hence program call to the function will return only else part whereas to return the values we have to define the values for the particular membership function.
Program 2
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing if let radiusName = circname.print?[0].radiusname { print("Radius is measured in (radiusName).") } else { print("Radius is not specified.") }
When we run the above program using playground, we get the following result −
Radius is measured in Units.
In the above program, the instance values for the membership function radiusName is specified. Hence program call to the function will now return values.
Accessing Subscripts of Optional Type
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]] area["Radius"]?[1] = 78 area["Circle"]?[1]-- print(area["Radius"]?[0]) print(area["Radius"]?[1]) print(area["Radius"]?[2]) print(area["Radius"]?[3]) print(area["Circle"]?[0]) print(area["Circle"]?[1]) print(area["Circle"]?[2])
When we run the above program using playground, we get the following result −
Optional(35) Optional(78) Optional(78) Optional(101) Optional(90) Optional(44) Optional(56)
The optional values for subscripts can be accessed by referring their subscript values. It can be accessed as subscript[0], subscript[1] etc. The default subscript values for radius are first assigned as [35, 45, 78, 101] and for Circle [90, 45, 56]]. Then the subscript values are changed as Radius[0] to 78 and Circle[1] to 45.
Linking Multiple Levels of Chaining
Multiple sub classes can also be pnked with its super class methods, properties and subscripts by optional chaining.
Multiple chaining of optional can be pnked −
If retrieving type is not optional, optional chaining will return an optional value. For example if String through optional chaining it will return String? Value
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if let radiusName = circname.print?[0].radiusname { print("The first room name is (radiusName).") } else { print("Radius is not specified.") }
When we run the above program using playground, we get the following result −
Radius is not specified.
In the above program, the instance values for the membership function radiusName is not specified. Hence, the program call to the function will return only else part whereas to return the values we have to define the values for the particular membership function.
If the retrieving type is already optional, then optional chaining will also return an optional value. For example if String? Is accessed through optional chaining it will return String? Value..
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("The number of rooms is (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() circname.print?[0] = radius(radiusname: "Diameter") let printing = circle() printing.area.append(radius(radiusname: "Units")) printing.area.append(radius(radiusname: "Meter")) circname.print = printing if let radiusName = circname.print?[0].radiusname { print("Radius is measured in (radiusName).") } else { print("Radius is not specified.") }
When we run the above program using playground, we get the following result −
Radius is measured in Units.
In the above program, the instance values for the membership function radiusName is specified. Hence, the program call to the function will now return values.
Chaining on Methods with Optional Return Values
Optional chaining is used to access subclasses defined methods too.
class rectangle { var print: circle? } class circle { var area = [radius]() var cprint: Int { return area.count } subscript(i: Int) -> radius { get { return area[i] } set { area[i] = newValue } } func circleprint() { print("Area of Circle is: (cprint)") } var rectarea: circumference? } class radius { let radiusname: String init(radiusname: String) { self.radiusname = radiusname } } class circumference { var circumName: String? var circumNumber: String? var circumarea: String? func buildingIdentifier() -> String? { if circumName != nil { return circumName } else if circumNumber != nil { return circumNumber } else { return nil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") }
When we run the above program using playground, we get the following result −
Area of circle is not specifiedAdvertisements