ARC Overview
In order to monitor and handle the memory usage of your app, Swift utilizes Automatic Reference Counting (ARC). As a programmer, you are not required to think about memory management as it is being taken care of by ARC. If such instances are no longer required, ARC automatically releases the memory used by class instances.
In a few instances, however, ARC needs further data on the connections between components of your code to handle your memory.
ARC allocates a piece of memory for storing data every time you generate a fresh class instance . This memory contains data on the type of class and any stored characteristics connected with that instance.
ARC assures an additional property of class instances which no longer take up memory space when they are not required, and hence the space can be utilized for some other purposes.
However, In case if ARC deallocates an instance that was already being used, the instance's properties would no longer be accessed. Infact , if the user attempted to achieve the above kind of instance, the app would most probably crash.
ARC monitors the number of properties , constants and variables presently referred to each class instance , to ensure that instances do not vanish as required. As long as at least one active reference exists still, ARC will not deallocate an instance.To enable this, property, constant or variable refers strongly to instance where the user assigns a class instance to a property, constant or variable. The reference is called a "strong" reference . It is being referred as strong here since the instance does not allow it to be distributed for as long as it remains a same i:s“Strong reference”.
Example
class Person { let name: String init(name: String) { self.name = name print("\(name) is being initialized") } deinit { print("\(name) is being deinitialized") } } ARC Strong Reference Cycles Class Instances class studmarks { let name:String var stud: student? init (name:String){ print("Initializing: \(name)") self.name = name } deinit { print("Deallocating: \(self.name)") } } class student { let name:String var strname: studmarks? init (name:String){ print("Initializing: \(name)") self.name = name } deinit { print("Deallocating: \(self.name)") } } var shiba: studmarks? var mari: student? shiba = studmarks(name:"Hello") mari = student(name:"ARC") shiba!.stud = anushka mari!.strname = Swati
ARC Weak and Unowned References
These references are used to allow an individual instance in a reference process to refer to other instances. Instead of taking great care of the strong reference cycle, the instance may refer to every single instance. If the user understands that a certain instance can return nil, we can point out that the weak reference is used. If something is returned instead of nil, then declare it with an unknown reference.
Weak Reference
classmodule{ let name:String init(name:String){self.name = name } varsub: submodule? deinit {print("\(name) Is The Main Module")} } class submodule { let number:Int init(number:Int){self.number = number } weak var topic:module? deinit {print("Sub Module with its topic number is \(number)")} } var toc:module? var list: submodule? toc =module(name:"ARC") list = submodule(number:4) toc!.sub= list list!.topic = toc toc =nil list =nil
The output of the above program would be
ARC Is The Main Module Sub Module with its topic number is 4
Unowned References
class student { let name: String var section: marks? init(name: String) { self.name = name } deinit { print("\(name)") } } class marks { let marks: Int unowned let stname: student init(marks: Int, stname: student) { self.marks = marks self.stname = stname } deinit { print("Marks Obtained by the student is \(marks)") } } var module: student? module = student(name: "ARC") module!.section = marks(marks: 98, stname: module!) module = nil
The output of the above program would be
ARC Marks Obtained by the student is 98
Strong Reference Cycles for Closures
When we actually assign a closure statement to the class instance property and to the body of the closure to capture a particular instance ,there is a scope that the strong reference cycle can occur. Strong reference to the closure in particular is well addressed and defined as by 'self.someProperty' or 'self.someMethod()'. Strong reference cycles are in turn used as reference types for the closures.
The strong reference cycle can happen if a closure for the class instance property and the body of the closure is assigned in order to capture a specific instance. self.someProperty' or' self.someMethod()' is the strong reference to closure. As reference types for closures, strong reference cycles are used.
class HTMLElement{ let samplename:String let text:String? lazy var asHTML:()->String={ if let text = self.text { return "<\(self.samplename)>\(text)</\(self.samplename)>" } else { return "<\(self.samplename) />" } } init(samplename:String, text:String?= nil){ self.samplename = samplename self.text = text } deinit { print("\(samplename) is being deinitialized") } } var paragraph:HTMLElement?=HTMLElement(samplename:"p", text:"Welcome to Closure SRC") print(paragraph!.asHTML()) The output for the above program would be <p>Welcome to Closure SRC</p>
Optional Chaining
Optional chaining is an operation on an optional that could presently be nil for querying and calling properties, methods, and subscriptions. If the options include the value, the property, methods, or subscript call is successful, if the optional is nil, then nil returns the property, method or subscript call. Many queries can be linked together, and if any link is nil, the whole chain will fail gracefully.
Optional Chaining as an Alternative to Forced Unwrapping
If you want to call a property, method or subscript on optional value if you have an optional non-nil, you indicate optional chaining by putting the question mark(?). This is very comparable to a mark(!) after an optional value to force its value to be unwrapped. The major distinction is that if the optional is nil, optional chaining fails, whereas forced unwrapping causes a runtime error when the optional is nil.
Program for optional chaining by (!)
classLoksabhaPoll{ var candidate:Constituency? //Optional } lass Constituency{ var name ="Hajipur" } let cand =LoksabhaPoll () let candname = cand.candidate!.name //forced unwrapping The output for the above program would be as follows 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 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26 3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939 4 libsystem_platform.dylib 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 libdyld.dylib 0x00007fff8bb9e5c9 start + 1 11 libdyld.dylib 0x000000000000000c start + 1950751300 Stack dump:
0.Program arguments:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/ usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 - target-cpu core2 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/ SDKs/MacOSX10.10.sdk -module-name main /bin/sh: line 47: 15672 Done cat <<'SWIFT 4' import Foundation </std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std:: __1::basic_string
Since the values are not stated in their base class, the value ' NIL' is saved and the force unwrapping operation returns a fatal error.
Program for optional chaining by (?) classLoksabhaPoll{ var candidate:Constituency? //Optional } lass Constituency{ var name ="Hajipur" } let cand =LoksabhaPoll() if let candname = cand.candidate?.name { print("Candidate name is \(candname)") } else { print("Candidate name cannot be retrieved") } The output for the above program would be Candidate name cannot be retrieved Defining Model Classes for Optional Chaining & Accessing Properties
Swift also offers the optional chaining idea in the form of declaring more than one subclass as a model class. This idea is very helpful for defining and accessing complicated models and sub-properties of properties, methods, and subscriptions.
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") } The output for the above program would be Rectangle Area is not specified
Calling Methods Through Optional Chaining
class rectangle { varprint: 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 } elseif circumNumber != nil { return circumNumber } else { returnnil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") } .
In the circle () subclass, the function circleprint() is called when an instance 'circname' is created. If the function includes some value, the value is given back, it checks the value by checking 'circname.print?.circleprint() != nil’ to return some specified print message in case of nil.
Accessing Subscripts through Optional Chaining
To set and retrieve a subscript value we can leverage optional chaining for ensuring whether a call to that subscript returns a value or not.The optional value of a specific subscript can be accessed by putting before’?’ the subscript braces.
Example 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.") } The output of the above program would be
Radius is not specified.
In the example above the membership function, 'radiusName' instance values are not specified.
Example 2
In the below example membership function instance values are specified.
class rectangle { varprint: 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 } elseif circumNumber != nil { return circumNumber } else { returnnil } } } 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 iflet radiusName = circname.print?[0].radiusname { print("Radius is measured in \(radiusName).") } else { print("Radius is not specified.") }
Accessing Subscripts of Optional Type
class rectangle { varprint: 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 } elseif circumNumber != nil { return circumNumber } else { returnnil } } } 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]) The output for the above program would be Optional(35) Optional(78) Optional(78) Optional(101) Optional(90) Optional(44) Optional(56)
Linking Multiple Levels of Chaining
The optional chaining also facilitates multiple subclasses linking with its superclass properties, methods, and subscripts.
class rectangle { varprint: 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 } elseif circumNumber != nil { return circumNumber } else { returnnil } } } let circname = rectangle() iflet radiusName = circname.print?[0].radiusname { print("The first room name is \(radiusName).") } else { print("Radius is not specified.") }
The instance values for the' radiusName' member function are not specified in the above program.It will return only else part of function, while returning values we need to define values for membership function. If the value we are trying to retrieve is optional, then optional chaining will also retrieve the optional value.
class rectangle { varprint: 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 } elseif circumNumber != nil { return circumNumber } else { returnnil } } } 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 iflet radiusName = circname.print?[0].radiusname { print("Radius is measured in \(radiusName).") } else { print("Radius is not specified.") }
When we run the above program the output would be
Radius is measured in Units.
Chaining on Methods with Optional Return Values
The subclasses methods can be also accessed by optional chaining.
class rectangle { varprint: 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 } elseif circumNumber != nil { return circumNumber } else { returnnil } } } let circname = rectangle() if circname.print?.circleprint() != nil { print("Area of circle is specified)") } else { print("Area of circle is not specified") }
Type Casting
Typecasting is a way of examining the type of instance or treating it as a superclass or subclass different from that of another one in its class hierarchy. The casting of type in Swift is carried out with operators ”is” and “as”. Both operators provide an easy and expressive way of checking a value type or casting a value to a different type.
Defining a Class Hierarchy
Typecasting is used to check the type of instance to see if it belongs to a specific type of class. It also examines the class hierarchy and its subclasses in order to check and cast these instances in the same hierarchy.
classSubjects { var physics: String init(physics: String) { self.physics = physics } } classChemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } classMaths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)")
The output for the above program would be
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz
Type Checking
The' is' operator will perform the type check. The' Is' type checks if the instance is a subclass-type instance and returns true if it belongs to this instance, otherwise it returns false.
class Subjects { var physics: String init(physics: String) { self.physics = physics } } classChemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } classMaths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in sa { if item isChemistry { ++chemCount } elseif item isMaths { ++mathsCount } } print("Subjects in chemistry contains \(chemCount) topics and maths contains \(mathsCount) topics")
The output for the above program would be
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Subjects in chemistry contains 2 topics and maths contains 3 topics
Downcasting
Two operators (as? and as!) can be used to downcast the subclass type.In case the nil value gets returned the ‘as? , the operator returns an optional value. It is used to monitor downcast success. The as! Operator is used for forced unwrapping in the context of optional chaining when downcasting returns nil value. It is used in case of downcast failure to trigger runtime errors
classSubjects { var physics: String init(physics: String) { self.physics = physics } } classChemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } classMaths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in sa { ifletprint = item as? Chemistry { print("Chemistry topics are: '\(print.physics)', \(print.equations)") } elseiflet example = item as? Maths { print("Maths topics are: '\(example.physics)', \(example.formulae)") } }
The above program output would be
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Chemistry topics are: 'solid physics', Hertz Maths topics are: 'Fluid Dynamics', Giga Hertz Chemistry topics are: 'Thermo physics', Decibels Maths topics are: 'Astro Physics', MegaHertz Maths topics are: 'Differential Equations', Cosine Series
Typecasting: Any and Any Object
The keyword 'Any' is used to represent an instance which belongs to any type including function types. For representing an instance of any type including function we use ‘Any’ keyword.
classSubjects { var physics: String init(physics: String) { self.physics = physics } } classChemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } classMaths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in sa { ifletprint = item as? Chemistry { print("Chemistry topics are: '\(print.physics)', \(print.equations)") } elseiflet example = item as? Maths { print("Maths topics are: '\(example.physics)', \(example.formulae)") } } var exampleany = [Any]() exampleany.append(12) exampleany.append(3.14159) exampleany.append("Example for Any") exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz")) forprintin exampleany { switchprint { caselet someInt asInt: print("Integer value is \(someInt)") caselet someDouble asDoublewhere someDouble > 0: print("Pi value is \(someDouble)") caselet someString asString: print("\(someString)") caselet phy asChemistry: print("Topics '\(phy.physics)', \(phy.equations)") default: print("None") } }
The output for the above program would be the following:
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Chemistry topics are: 'solid physics', Hertz Maths topics are: 'Fluid Dynamics', Giga Hertz Chemistry topics are: 'Thermo physics', Decibels Maths topics are: 'Astro Physics', MegaHertz Maths topics are: 'Differential Equations', Cosine Series Integer value is 12 Pi value is 3.14159 Example for Any Topics 'solid physics', Hertz
AnyObject
The ‘AnyObject’ keyword is used for representing an instance of any class type.
classSubjects { var physics: String init(physics: String) { self.physics = physics } } classChemistry: Subjects { var equations: String init(physics: String, equations: String) { self.equations = equations super.init(physics: physics) } } classMaths: Subjects { var formulae: String init(physics: String, formulae: String) { self.formulae = formulae super.init(physics: physics) } } let saprint: [AnyObject] = [Chemistry(physics: "solid physics", equations: "Hertz"), Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"), Chemistry(physics: "Thermo physics", equations: "Decibels"), Maths(physics: "Astro Physics", formulae: "MegaHertz"), Maths(physics: "Differential Equations", formulae: "Cosine Series")] let samplechem = Chemistry(physics: "solid physics", equations: "Hertz") print("Instance physics is: \(samplechem.physics)") print("Instance equation is: \(samplechem.equations)") let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz") print("Instance physics is: \(samplemaths.physics)") print("Instance formulae is: \(samplemaths.formulae)") var chemCount = 0 var mathsCount = 0 for item in saprint { ifletprint = item as? Chemistry { print("Chemistry topics are: '\(print.physics)', \(print.equations)") } elseiflet example = item as? Maths { print("Maths topics are: '\(example.physics)', \(example.formulae)") } } var exampleany = [Any]() exampleany.append(12) exampleany.append(3.14159) exampleany.append("Example for Any") exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz")) forprintin exampleany { switchprint { caselet someInt asInt: print("Integer value is \(someInt)") caselet someDouble asDoublewhere someDouble > 0: print("Pi value is \(someDouble)") caselet someString asString: print("\(someString)") caselet phy asChemistry: print("Topics '\(phy.physics)', \(phy.equations)") default: print("None") } }
The output for the above program would be
Instance physics is: solid physics Instance equation is: Hertz Instance physics is: Fluid Dynamics Instance formulae is: Giga Hertz Chemistry topics are: 'solid physics', Hertz Maths topics are: 'Fluid Dynamics', Giga Hertz Chemistry topics are: 'Thermo physics', Decibels Maths topics are: 'Astro Physics', MegaHertz Maths topics are: 'Differential Equations', Cosine Series Integer value is 12 Pi value is 3.14159 Example for Any Topics 'solid physics', Hertz
Extensions
Extensions in a layman’s language add to a class, structure, enumeration or type of protocol new functionality. This even includes the feasibility to extend types for which the original source code is not even available (called retroactive modeling). Extensions in Swift are exactly the same as categories in Objective-C.Swift extension within the functionalities :
Syntax
extension SomeType { // new functionality can be added here }
Existing type can also be added as a protocol standard with extensions and its syntax is similar to the classes or structures.
extension SomeType: SomeProtocol, AnotherProtocol { // protocol requirements is described here }
Computed Properties
With the help of extensions computed ‘instance’ and type properties can be extended.
extension Int { varadd: Int {returnself + 100 } varsub: Int { returnself - 10 } var mul: Int { returnself * 10 } var div: Int { returnself / 5 } } let addition = 3.add print("Addition is \(addition)") let subtraction = 120.sub print("Subtraction is \(subtraction)") let multiplication = 39.mul print("Multiplication is \(multiplication)") let division = 55.div print("Division is \(division)") let mix = 30.add + 34.sub print("Mixed Type is \(mix)")
The above program output would be
Addition is 103 Subtraction is 110 Multiplication is 390 Division is 11 Mixed Type is 154
Initializers
Swift offers the flexibility of adding new initializers by extensions to an existing type. The user can add his own custom types to extend the defined types and also allow further initialization options. Only init() is supported by extensions. The deinit() are not supported by extensions.
struct sum { var num1 = 100, num2 = 200 } struct diff { var no1 = 200, no2 = 100 } struct mult { var a = sum() var b = diff() } let calc = mult() print ("Inside mult block \(calc.a.num1, calc.a.num2)") print("Inside mult block \(calc.b.no1, calc.b.no2)") let memcalc = mult(a: sum(num1: 300, num2: 500),b: diff(no1: 300, no2: 100)) print("Inside mult block \(memcalc.a.num1, memcalc.a.num2)") print("Inside mult block \(memcalc.b.no1, memcalc.b.no2)") extension mult { init(x: sum, y: diff) { let X = x.num1 + x.num2 let Y = y.no1 + y.no2 } } let a = sum(num1: 100, num2: 200) print("Inside Sum Block:\( a.num1, a.num2)") let b = diff(no1: 200, no2: 100) print("Inside Diff Block: \(b.no1, b.no2)") The output for the above program would be Inside mult block (100, 200) Inside mult block (200, 100) Inside mult block (300, 500) Inside mult block (300, 100) Inside Sum Block:(100, 200) Inside Diff Block: (200, 100)
Methods
The extensions also help subclasses to add new instance methods and type methods.
extension Int { func topics(summation: () -> ()) { for _ in0..<self { summation() } } } 4.topics(summation: { print("Inside Extensions Block") }) 3.topics(summation: { print("Inside Type Casting Block") })
The output for the above program would be
Inside Extensions Block Inside Extensions Block Inside Extensions Block Inside Extensions Block Inside Type Casting Block Inside Type Casting Block Inside Type Casting Block
Mutating Instance Methods
When declared as extensions, instance methods can also be mutated.
Structures and enumeration methods that modify themselves or their properties must identify the instance method as mutating, as do methods from the original implementation.
extension Double { mutating func square() { let pi = 3.1415 self = pi * self * self } } varTrial1 = 3.3 Trial1.square() print("Area of circle is: \(Trial1)") varTrial2 = 5.8 Trial2.square() print("Area of circle is: \(Trial2)") varTrial3 = 120.3 Trial3.square() print("Area of circle is: \(Trial3)")
Subscript & Nested type
extension Int { subscript(var multtable: Int) -> Int { var no1 = 1 while multtable > 0 { no1 *= 10 --multtable } return (self / no1) % 10 } } print(12[0]) print(7869[1]) print(786543[2])
The extensions can help in extending nested types for class,structure and enumeration instance.
extension Int { enum calc { caseadd casesub case mult case div case anything } varprint: calc { switchself { case0: return .add case1: return .sub case2: return .mult case3: return .div default: return .anything } } } func result(numb: [Int]) { for i in numb { switch i.print { case .add: print(" 10 ") case .sub: print(" 20 ") case .mult: print(" 30 ") case .div: print(" 40 ") default: print(" 50 ") } } } result(numb: [0, 1, 2, 3, 4, 7])
Protocols
A protocol defines the actual blueprint of any methods, its properties along with other requirements which are perfectly suitable for a specific task or feature. Any class enumeration or structure can then take the protocol to ensure its actual execution. Any type of protocol complying with the requirements is said to comply with that protocol.You can extend the protocol to implement some of these needs and can also implement additional functionality which conforms the types that can be used. Along with that it can even specify requirements that conform types that are a must for implementation.
Syntax protocol SomeProtocol { // protocol definition }
Protocols are declared after names of class, structure or type of enumeration. It is also feasible to declare single and multiple protocols. When defining various protocols, they must be split up by commas.
structSomeStructure: Protocol1, Protocol2 { // structure definition }
If a protocol for superclass has to be defined, the name of the protocol should follow the name of Super Class with commas.
class SomeClass: SomeSuperclass, Protocol1, Protocol2 { // class definition }
Property and Method Requirements
A protocol is used to indicate a property of instance or instance of specific class type. It simply specifies the property of the type or instance alone, instead of whether it has been stored or computed property. It is also used to indicate if the property is 'gettable' or 'settable'.
‘var' keyword declares property requirements as property variables. After their type declaration,{ get set} is used for declaring gettable and settable properties. Gettable is specified after a type declaration by{ get} property.
protocol classa { var marks: Int { getset } var result: Bool { get } func attendance() -> String func markssecured() -> String } protocol classb: classa { var present: Bool { getset } var subject: String { getset } var stname: String { getset } } class classc: classb { var marks = 96 let result = true var present = false var subject = "Swift Protocols" var stname = "Protocols" func attendance() -> String { return"The \(stname) has secured 99% attendance" } func markssecured() -> String { return"\(stname) has scored \(marks)" } } let studdet = classc() studdet.stname = "Swift" studdet.marks = 98 studdet.markssecured() print(studdet.marks) print(studdet.result) print(studdet.present) print(studdet.subject) print(studdet.stname)
The output for the above program would be
98 true false Swift Protocols Swift
Mutating Method Requirements
protocol daysofaweek { mutating func print() } enum days: daysofaweek { case sun, mon, tue, wed, thurs, fri, sat mutating func print() { switchself { case sun: self = sun print("Sunday") case mon: self = mon print("Monday") case tue: self = tue print("Tuesday") case wed: self = wed print("Wednesday") case mon: self = thurs print("Thursday") case tue: self = fri print("Friday") case sat: self = sat print("Saturday") default: print("NO Such Day") } } } var res = days.wed res.print()
Initializer Requirements
Swift allows users to initialize protocols that conform like normal initializers to type compliance.
Syntax
protocol SomeProtocol { init(someParameter: Int) } Example protocol tcpprotocol { init(aprot: Int) }
Class Implementations of Protocol Initializer Requirements
To initialize a protocol,designated or convenience initializer allows the user to conform its standard by reserved ‘required’ keyword.
lass SomeClass: SomeProtocol { required init(someParameter: Int) { // initializer implementation statements } } protocol tcpprotocol { init(aprot: Int) } class tcpClass: tcpprotocol { required init(aprot: Int) { } }
Conformity to the Protocol is guaranteed on all subclasses with a "required" modifier for explicit or inherited execution.When a subclass overrides its superclass initialization requirement, the' override' keyword is used.
protocol tcpprotocol { init(no1: Int) } class mainClass { var no1: Int// local storage init(no1: Int) { self.no1 = no1 // initialization } } class subClass: mainClass, tcpprotocol { var no2: Int init(no1: Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method required override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1: 20) letprint = subClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
Protocols as Types
Protocols are used as types of functions , classes, methods, etc, instead of applying functionality in a protocol.
There are numerous ways in which protocols can be applicable :
protocol Generator { typealias members func next() -> members? } var items = [10,20,30].generate() whilelet x = items.next() { print(x) } for lists in map([1,2,3], {i in i*5}) { print(lists) } print([100,200,300]) print(map([1,2,3], {i in i*10}))
The output for the above program would be
10 20 30 5 10 15 [100, 200, 300] [10, 20, 30]
Adding Protocol Conformance with an Extension
By using extensions, the existing type can be embraced and complied with by a fresh protocol. The existing type can be supplemented by extensions with new properties, methods, and subscripts.
protocol AgeClasificationProtocol { var age: Int { get } func agetype() -> String } classPerson { let firstname: String let lastname: String var age: Int init(firstname: String, lastname: String) { self.firstname = firstname self.lastname = lastname self.age = 10 } } extension Person : AgeClasificationProtocol { func fullname() -> String { var c: String c = firstname + " " + lastname return c } func agetype() -> String { switch age { case0...2: return"Baby" case2...12: return"Child" case13...19: return"Teenager" caselet x where x > 65: return"Elderly" default: return"Normal" } } }
Protocol Inheritance
Swift permits protocols to inherit properties that have been defined. It's comparable to class inheritance , but with several inheritance protocols separated by commas being listed.
protocol classa { var no1:Int{getset} func calc(sum:Int) } protocol result { func print(target: classa) } class student2: result { func print(target: classa){ target.calc(sum:1) } } class classb: result { func print(target: classa){ target.calc(sum:5) } } class student: classa { var no1:Int=10 func calc(sum:Int){ no1 -= sum print("Student attempted \(sum) times to pass") if no1 <=0{ print("Student is absent for exam") } } } classPlayer{ var stmark: result! init(stmark: result){ self.stmark = stmark } func print(target: classa){ stmark.print(target: target) } } var marks =Player(stmark: student2()) var marksec = student() marks.print(target: marksec) marks.print(target: marksec) marks.print(target: marksec) marks.stmark = classb() marks.print(target: marksec) marks.print(target: marksec) marks.print(target: marksec)
The above program output would be
Student attempted 1 times to pass Student attempted 1 times to pass Student attempted 1 times to pass Student attempted 5 times to pass Student attempted 5 times to pass Student is absent for exam Student attempted 5 times to pass Student is absent for exam
Class Only Protocols
When protocols and class protocols are described, the user needs to add class first followed by the inheritance list of protocols.
rotocol tcpprotocol { init(no1: Int) } class mainClass { var no1: Int// local storage init(no1: Int) { self.no1 = no1 // initialization } } class subClass: mainClass, tcpprotocol { var no2: Int init(no1: Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method required override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1: 20) letprint = subClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
Protocol composition
The protocol composition can help multiple protocols to be called at once.
Syntax
protocol<SomeProtocol, AnotherProtocol> Example protocol stname { var name:String{get} } protocol stage { var age:Int{get} } structPerson: stname, stage { var name:String var age:Int } func print(celebrator: stname & stage){ print("\(celebrator.name) is \(celebrator.age) years old") } let studname =Person(name:"Priya", age:21) print(studname) let stud =Person(name:"Rehan", age:29) print(stud) let student =Person(name:"Roshan", age:19) print(student)
Checking for Protocol Conformance
You can use the operators "is" and "as" defined in the type casting to verify protocol compliance and cast them into a particular protocol. The checking and casting on a protocol is identical to checking and casting to a type.
importFoundation
@objc protocol rectangle { var area: Double { get } } @objcclassCircle: rectangle { let pi = 3.1415927 var radius: Double var area: Double { return pi * radius * radius } init(radius: Double) { self.radius = radius } } @objcclass result: rectangle { var area: Double init(area: Double) { self.area = area } } class sides { var rectsides: Int init(rectsides: Int) { self.rectsides = rectsides } } let objects: [AnyObject] = [Circle(radius: 2.0),result(area:198),sides(rectsides: 4)] forobjectin objects { iflet objectWithArea = objectas? rectangle { print("Area is \(objectWithArea.area)") } else { print("Rectangle area is not defined") } }
The output for the above program would be
Area is 12.5663708 Area is 198.0 Rectangle area is not defined
Generic
Generic code allows you to write flexible, reusable functions and type, depending on criteria that you define, that can work with any type. You can write code which prevents duplication and clearly, abstractly expresses its purpose.
Generics are one of Swift's strongest characteristics and many Swift standard libraries are made from generic code. Swift's Array and Dictionary are generic collections, for instance. You can generate an array containing Int or an array containing String values or a set for any other type in Swift. Likewise, you can generate a dictionary to store any given type of values and there are no restrictions on what type.
func exchange(a: inout Int, b: inout Int) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("Before Swapping values are: \(numb1) and \(numb2)") exchange(a: &numb1, b: &numb2) print("After Swapping values are: \(numb1) and \(numb2)")
The output for the above program would be
Before Swapping values are: 100 and 200 After Swapping values are: 200 and 100 Generic Functions: Type Parameters Generic functions can be used to access any data type like 'Int' or 'String'. func exchange<T>(a: inout T, b: inout T) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("Before Swapping Int values are: \(numb1) and \(numb2)") exchange(a: &numb1, b: &numb2) print("After Swapping Int values are: \(numb1) and \(numb2)") var str1 = "Generics" var str2 = "Functions" print("Before Swapping String values are: \(str1) and \(str2)") exchange(a: &str1, b: &str2) print("After Swapping String values are: \(str1) and \(str2)")
The output for the above program would be
Before Swapping Int values are: 100 and 200 After Swapping Int values are: 200 and 100 Before Swapping String values are: Generics and Functions After Swapping String values are: Functions and Generics
The exchange() function is used to exchange values outlined above, and < T > is used as a parameter sort. The exchange() function is called first to return the value of' Int' and then the second call to the exchange() function gives the value of' String.' Inside the angle brackets, separated by commas, several parameter types can be included.
The user-specified parameters of the type are named to understand what type of parameter it holds. As a generic parameter type name, Swift offers < T>. However, parameters such as Arrays and Dictionaries can be used to define that they are of the' Dictionary' type.
struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push(item: "Swift ") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items) let deletetos = tos.pop()
The output for the above program would be
[Swift ] [Swift , Generics] [Swift , Generics, Type Parameters] [Swift , Generics, Type Parameters, Naming Type Parameters]
Extending a Generic Type
Extending the stack property to know the top of the item is included with 'extension' keyword.
struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push(item: "Swift ") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items) extension TOS { var first: T? { return items.isEmpty ? nil : items[items.count - 1] } } iflet first = tos.first { print("The top item on the stack is \(first).") }
The output for the above program would be
["Swift "] ["Swift ", "Generics"] ["Swift ", "Generics", "Type Parameters"] ["Swift ", "Generics", "Type Parameters", "Naming Type Parameters"] The top item on the stack is Naming Type Parameters.
Type Constraints
Specifically,' type constraints’' may allow the specified type parameter to be inherited from a certain class, or the protocol conformity standard to be ensured.
func exchange<T>(a: inout T, b: inout T) { let temp = a a = b b = temp } var numb1 = 100 var numb2 = 200 print("Before Swapping Int values are: \(numb1) and \(numb2)") exchange(a: &numb1, b: &numb2) print("After Swapping Int values are: \(numb1) and \(numb2)") var str1 = "Generics" var str2 = "Functions" print("Before Swapping String values are: \(str1) and \(str2)") exchange(a: &str1, b: &str2) print("After Swapping String values are: \(str1) and \(str2)")
The output for the above program would be
Before Swapping Int values are: 100 and 200 After Swapping Int values are: 200 and 100 Before Swapping String values are: Generics and Functions After Swapping String values are: Functions and Generics
Associated Types
In the protocol definition, Swift allows associated types to be declared by the' associatedtype' keyword.
protocol Container { associatedtype ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } struct TOS<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item: item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } var tos = TOS<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items)
The output for the above program would be
Access Control:
Access control limits access by other source files and modules to parts of your code from the code. This feature assists the user to hide the implementation details of the user code, and to specify a particular interface through which that code can be accessed and easily used by the end users.
In addition to offering different levels of control of access, Swift reduces the requirement for explicit levels of access control by providing standard access levels for typical scenarios.
Module and abstraction are done through access control to restrict access to code blocks. According to their properties, methods, initializers and subscriptions, access to classes, structures and enumerations can be achieved through access control procedures.
Access control is applicable to properties, types and functions can be referred to as 'entities'. Constants, variables and functions are restricted in a protocol and allowed access as global or local by way of access control.
Modules and source files are the basis of the Access Control Model.
The module is described as a single distribution unit of code and can be exported using an 'import' keyword.
A single source file with multiple types and features in a module is defined as the source file.
Three different types of access provided by Swift language are:
Public, Internal and Private
Syntax:
public class SomePublicClass {} internal class SomeInternalClass {} private class SomePrivateClass {} public var somePublicVariable = 0 internal let someInternalConstant = 0 private func somePrivateFunction() {}
Access control for function types:
Some functions may even have their arguments being declared within the function without any return values. Such programs declare a and b as arguments to the sum() function. Within the function itself the values for the arguments a and b are fed by invoking the function call sum() and its values are automatically printed; thereby completely eliminating the return values. Inorder to make the function's return type as private, the end user declares the function’s overall access level with a private modifier.
Live demo for the same would be:
private func sum(a: Int, b: Int) { let a = a + b let b = a - b print(a, b) } sum(a: 20, b: 10) sum(a: 40, b: 10) sum(a: 24, b: 6)
The output achieved in this case is
30 20 50 40 30 24
Access Control for Enumeration Types:
Live Demo publicenumStudent { caseName(String) caseMark(Int,Int,Int) } var studDetails = Student.Name("Swift 4") var studMarks = Student.Mark(98,97,95) switch studMarks { case .Name(let studName): print("Student name is: \(studName).") case .Mark(letMark1, letMark2, letMark3): print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).") }
While running this program with the playground we achieve the following output:
Student Marks are: 98,97,95
For individual cases of an enumeration, the listing in Swift 4 automatically receives the same level of access.
Consider accessing the name and trademarks of students in three subjects, for example. Enumerated names are declared as students and members of the enum class are names of a data type string, mark 2, and mark3 of an Integer data type.
They have entered either the name of the student or the marks. Now, if that case block is carried out, the switch case will print out the name of the student. If both conditions fail, the default block will be executed.
Access control of Subclasses:
Swift 4 enables the user to subclass any class accessible in the existing access framework.
A subclass cannot be greater than its superclass access level. A public subclass of an internal superclass is limited for the user.
publicclass cricket { internal func printIt() { print("Welcome to Swift 4 Super Class") } } internalclass tennis: cricket { overrideinternal func printIt() { print("Welcome to Swift 4 Sub Class") } } let cricinstance = cricket() cricinstance.printIt() let tennisinstance = tennis() tennisinstance.printIt()
On running the above program with the playground, the following output can be achieved:
Welcome to Swift Super Class Welcome to Swift Sub Class
Access Control for Constants, variables, properties, and subscripts:
Swift 4 is not defined as the public constant, variable, or characteristic other than the type. A public property with a personal form is not valid to be documented. More so, a subscript cannot be more public in comparison to its index or return type.
If a constant, variable, property or subscript uses a private form, it must also be labeled privately as a constant, variable, property or subscription
private var privateInstance = SomePrivateClass()
Getters and Setters:
The same access levels are automatically received by getters and setters of constant, variable, properties and subscript to which they actually belong to.
class Samplepgm { var counter: Int = 0{ willSet(newTotal) { print("Total Counter is: \(newTotal)") } didSet { if counter > oldValue { print("Newly Added Counter \(counter - oldValue)") } } } } letNewCounter = Samplepgm() NewCounter.counter = 100 NewCounter.counter = 800
The output of the above program is shown below:
Total Counter is: 100 Newly Added Counter 100 Total Counter is: 800 Newly Added Counter 700
Access Control for Initializers and Default Initializers:
Custom initializers can actually be assigned the access less than or equal to the initialized type.The required initializer must have the same amount of access as its class. The types of parameters of an initializer cannot be more private than the access level of the initializer itself.
For declaration of each and every subclass of the initialize,the 'required' keyword needs to be pre-defined prior the init() function.
class classA { required init() { let a = 10 print(a) } } class classB: classA { required init() { let b = 30 print(b) } } let res = classA() letprint = classB()
Following outputs are obtained by running the above program:
10 30 10
A default initializer has the same level of access as its initialised type, unless that type is publicly defined.If initializing by default is public, it is internally considered. If the user needs to have a public type initialized in another module with a no-argument initializer, it provides exclusively a public no-argument initializer as part of the type's definition.
Access control for Protocols:
The same levels of access to each other must be stated when defining a new protocol to inherit functions from the existing prototype.The Swift 4 access control will not enable users inherent in an 'internal' protocol to define a 'public' protocol.
public protocol tcpprotocol { init(no1: Int) } publicclass mainClass { var no1: Int// local storage init(no1: Int) { self.no1 = no1 // initialization } } class subClass: mainClass, tcpprotocol { var no2: Int init(no1: Int, no2 : Int) { self.no2 = no2 super.init(no1:no1) } // Requires only one parameter for convenient method required override convenience init(no1: Int) { self.init(no1:no1, no2:0) } } let res = mainClass(no1:20) let print = subClass(no1:30, no2:50) print("res is: \(res.no1)") print("res is: \(print.no1)") print("res is: \(print.no2)")
While running the program, the following output is being achieved:
res is: 20 res is: 30 res is: 50
Access Control for Extensions:
Swift 4 does not entertain the end users to facilitate an explicit access level modifier for an extension when the user uses that particular extension to add protocol conformance. The default access level in case of every single protocol requirement actually does the implementation within the extension and is provided with its very own protocol access level.
Access Level for Generics:
In case of Generics users are allowed to specify minimum access levels to access the type constraints along with its type parameters.
public struct TOS<T> { var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } } var tos = TOS<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Type Parameters") print(tos.items) tos.push(item: "Naming Type Parameters") print(tos.items) let deletetos = tos.pop()
The following results are obtained when the program is being run:
[Swift 4] [Swift 4, Generics] [Swift 4, Generics, Type Parameters] [Swift 4, Generics, Type Parameters, Naming Type Parameters]
Access Control for Type Aliases:
The user can readily define type aliases to treat the unique access control types, whereas the same or different access levels can be easily identified by the user. In scenarios wherein the type alias is 'private' its associated members can be declared as 'private, internal of public type', and in the situations wherein the type alias is public the members cannot be an alias as an 'internal' or 'private' name.
Any type aliases defined are regarded as distinct types for the exclusive purposes of access control. A type alias can even have an access level less than or equal to the access level of the type its aliases have in original. For example, a private type alias can actually alias a private, internal, or public type in contrary to which a public type alias cannot alias an internal or private type.
public protocol Container { associatedtype ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } } structStack<T>: Container { // original Stack<T> implementation var items = [T]() mutating func push(item: T) { items.append(item) } mutating func pop() -> T { return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { self.push(item: item) } var count: Int { return items.count } subscript(i: Int) -> T { return items[i] } } func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, anotherContainer: C2) -> Bool { // check that both containers contain the same number of items if someContainer.count != anotherContainer.count { returnfalse } // check each pair of items to see if they are equivalent for i in0..<someContainer.count { if someContainer[i] != anotherContainer[i] { returnfalse } } // all items match, so return true returntrue } var tos = Stack<String>() tos.push(item: "Swift 4") print(tos.items) tos.push(item: "Generics") print(tos.items) tos.push(item: "Where Clause") print(tos.items) var eos = ["Swift 4", "Generics", "Where Clause"] print(eos)
The following output is being achieved while the above program is being run:
[Swift 4] [Swift 4, Generics] [Swift 4, Generics, Where Clause] [Swift 4, Generics, Where Clause]
Swift Encoding and Decoding:
Swift 4 introduces the new Codable protocol, which allows you to serialize and remove customized data types without any special code – and without worrying about losing your value types.
struct Language: Codable { var name: String var version: Int } let swift = Language(name: "Swift", version: 4) let java = Language(name: "java", version: 8) let R = Language(name: "R", version: 3 let encoder =JSONEncoder() iflet encoded =try? encoder.encode(java){ //Perform some operations on this value. } let decoder =JSONDecoder() iflet decoded =try? decoder.decode(Language.self,from: encoded){ //Perform some operations on this value. }
Summary:
This module covered all other details related to ARC ,optional chaining ,type casting ,extensions ,protocols and generics. We have also got fair understanding of access control with help of this module.
I am interested in the learning of swift and coding
Is this included in csm training and certification or sold separately?
I am interested in advanced level training of SWIFT and coding.
C# is an object-oriented programming developed by Microsoft that uses ...
Leave a Reply
Your email address will not be published. Required fields are marked *