Properties In Swift

Stored Properties

Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance.
In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure.

struct Size {
 var width: Int 
 let height: Int 
}
var size1 = Size(width: 10, height: 35)
size1.width = 6

In the example above, height is initialized when the new size is created. This is a constant property, and it cannot be changed once initialized.
When creating an instance of a structure, if you assign an instance of a structure to a constant, the instance‘s properties cannot be modified, even if they were declared as variable properties.

Lazy Stored Properties

A lazy stored property’s initial value is not calculated until the first time it is used.

class DataManager {
 lazy var importer = DataImporter()
 var data = [String]()
}

Lazy properties are useful when a property’s initial value is dependent on outside factors, the values of which are not known until after an instance‘s initialization is complete; or when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed.
You must always declare a lazy property as a variable, using the var keyword, because its initial value might not be retrieved until after the completion of instance initialization. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

Computed Properties

Rather than storing a value, a computed property provides a getter and, optionally, a setter, which indirectly retrieve and set other properties and values, respectively.

struct Point {
 var x = 0.0, y = 0.0
}
struct Shape {
 var origin = Point() 
 var center: Point {
  get {
   return Point(x: origin.x/2 , y: origin.y/2)
  }
  set(newCenter) {
   origin.x = newCenter.x/2
   origin.y = newCenter.y/2
  }
 }
}

The Shape structure defines a custom getter and setter for a computed variable called center. The center property is then accessed through dot syntax, which causes the getter for center to be called to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new point that represents the center of the shape.

If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used.
Below is an alternative version of the Rect structure, which takes advantage of this shorthand notation:

struct Point {
 var x = 0.0, y = 0.0
}
struct Shape {
 var origin = Point() 
 var center: Point {
  get {
   return Point(x: origin.x/2, y: origin.y/2)
  }
  set {
   origin.x = newValue.x/2
   origin.y = newValue.y/2
  }
 }
}

A computed property with a getter but no setter is known as a read-only computed property. It always returns a value, and can be accessed through dot syntax. However, that value cannot be altered.

Property Observers

Property observers detect and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value.
Property observers can be added to any defined stored properties, with the exception of lazy stored properties.
You have the option of defining either or both of the following observers of a property:
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.

The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking.

class StepCounter {
 var totalSteps: Int = 0 {
  willSet(newSteps) {
   print("About to set totalSteps to \(newSteps)")
  }
  didSet {
   if totalSteps > oldValue  {
   print("Added \(totalSteps - oldValue) steps")
   }
  }
 }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 50
// About to set totalSteps to 50
// Added 50 steps
stepCounter.totalSteps = 150
// About to set totalSteps to 150
// Added 100 steps
stepCounter.totalSteps = 420
// About to set totalSteps to 420
// Added 270 steps

The StepCounter class declares a totalSteps property of type Int, with willSet and didSet observers.
The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value.
The willSet observer uses a custom parameter name of newSteps for the upcoming new value.

The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. The didSet observer does not provide a custom parameter name for the old value; the default name of oldValue is used, instead.
Similarly, newValue could be used for the willSet observer, if no parameter name was defined.
If you assign a value to a property within its own didSet observer, the new assigned value will replace the one that was just set.

Type Properties

Type properties are useful when defining values that are universal to all instances of a particular type, such as a constant property used in all instances, or a variable property that stores a global value to all instances of that type. Stored type properties can be variables or constants. You define type properties with the static keyword:

class SomeClass {
 static var storedProp = "Some value."
 static var computedProp: Int {
   return 42
 }
}

Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type:

print(SomeClass.storedProp) 

Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time.

Advertisements
Properties In Swift

Some Additional Functionalities Of Swift – Part 3

Classes vs. Structures

Structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks.
As a general guideline, consider creating a structure instead of a class when one or more of these conditions apply:

1. The structure’s primary purpose is to encapsulate a few relatively simple data values.
2. It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
3. Any properties stored by the structure are themselves value types, which you would also expect to be copied, as opposed to being referenced.
4. It is not necessary for the structure to inherit properties or behavior from another existing type.

For example, the size of a geometric shape would be a good choice for a structure, with the structure perhaps encapsulating a width property and a height property, both of type Double.

In all other cases, define a class. You will find that most custom data constructs should be defined as classes rather than as structures.
Swift’s String, Array, and Dictionary types are implemented as structures.

Modifying Value Types

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.
The mutating keyword is added to the method‘s definition so it can modify its properties.

struct Point {
 var x = 0.0, y = 0.0
 mutating func moveByX(dX: Double, dY: Double) {
   x += dX
   y += dY
 }
}

You cannot call a mutating method on a constant of structure type, because its properties cannot be changed.
Mutating methods can assign an entirely new instance to the implicit self property.

Type Methods

Instance methods are called on an instance of a particular type. A type method is called on the type itself, and is indicated by writing the keyword static before the method‘s func keyword:

class SomeClass {
 static func someTypeMethod() {
 // type method implementation goes here
 }
}
SomeClass.someTypeMethod()

As with instance methods, type methods are called with dot syntax. However, type methods are called on the type, not on an instance of that type.
Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type.

Subscripts

Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence. Subscripts enable you to query instances of a type by writing one or more values in square brackets after the instance name.

Subscript definitions are written using the subscript keyword, and specify one or more input parameters and a return type, in the same way asinstance methods.
Here’s an example of a read-only subscript implementation, which defines a TimesTable structure to represent an n-times-table of integers:

struct TimesTable {
let multiplier: Int
 subscript(index: Int) -> Int {
   return multiplier * index
 }
}
let threeTimesTable = TimesTable(multiplier: 3)
print(threeTimesTable[5])
// prints "15"

Multiple subscripts can be defined for a single type. The appropriate subscript overload to use is selected according to the type of index value you pass to the subscript. Subscripts are not limited to a single dimension, and can be defined using multiple input parameters that best suit your custom type’s needs.

A Matrix is a good example how a subscript is used.
The following example defines a Matrix structure, which represents a two-dimensional matrix of Double values. The subscript takes two integer parameters:
struct Matrix {
 let rows: Int, columns: Int
 var grid: [Double]
 init(rows: Int, columns: Int) {
   self.rows = rows
   self.columns = columns
   grid = Array(count: rows * columns, repeatedValue: 0.0)
 }
 subscript(row: Int, column: Int) -> Double {
   get {
    return grid[(row * columns) + column]
   }
   set {
    grid[(row * columns) + column] = newValue
   }
 }
}

Matrix provides an initializer that takes two parameters called rows and columns to create an array large enough to store values of type Double. Each position in the matrix is given an initial value of 0.0.
Initialization is described in detail in the coming lessons.
You can construct a new Matrix instance by passing an appropriate row and column count to its initializer:

var matrix = Matrix(rows: 2, columns: 2)

This results in the following grid:


Values in the matrix can be set by passing comma-separated row and column values into the subscript.:
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2


This results in the following:

Overriding

You can prevent a method, property, or subscript override by marking it as final (such as final var, final func, final class func, and final subscript).
You can mark an entire class as final by placing the final modifier before the class keyword in its class definition (final class).

Initializers

In the case of structure types that have no defined custom initializers, Swift automatically provides a memberwise initializer, even if the structure types have stored properties that do not have default values.
The Size structure automatically receives an init(width:height:) memberwise initializer, which you can use to initialize a new Size instance:

struct Size {
   var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)

Class InitializationAll stored properties of a class – including any properties inherited from its superclassmust be assigned an initial value during initialization. In other words, assign a default value or create an initializer for the properties of the class.
The structure from the above example would have the following form as a class with an initializer:

class Size {
   var width:Double, height:Double
   init(w:Double, h:Double) {
     width = w
     height = h
   }
}
let twoByTwo = Size(w: 2.0, h: 2.0)

Required Initializers

Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer:

class SomeClass {
 required init() {
 // initializer implementation goes here
 }
}

You must also insert the required modifier before every subclass implementation of a required initializer. This indicates that the initializer requirement applies to further subclasses along the chain. Do not write the override modifier when overriding a required designated initializer:

class SomeSubclass: SomeClass {
 required init() {
 // subclass implementation goes here
 }
}

It’s not necessary to provide an explicit implementation of a required initializer if you can satisfy the requirement with an inherited initializer.

Deinitialization

A deinitializer is called immediately before a class instance is deallocated, and is useful when you work with your own resources.
For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.
Class definitions can have at most one deinitializer per class.
Rather than providing you with the ability to call a deinitializer, Swift automatically calls it, just prior to instance deallocation. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even in cases in which subclasses do not provide their own deinitializers.

The deinit keyword is used to write a deinitializer, which is similar to writing an initializer using the init keyword. The deinitializer does not take any parameters and is written with no parentheses:

deinit {
 // perform the deinitialization
}

Deinitializers are only available on class types.

Some Additional Functionalities Of Swift – Part 3

Closures in Swift

Closures

A Closure is a self-contained block of functionality that can be passed around and used in your code.

Global and nested functions are actually special kinds of closures.

Nested functions offer a convenient way to name and define self-contained blocks of code within a larger function.
However, it is sometimes useful to have the option of writing shorter versions of function-like constructs that do not require full declarations and names. This is particularly true when working with functions that take other functions as one or more of their arguments.

Closure expressions present a way to write inline closures using brief, focused syntax. Closure expressions offer a number of syntax optimizations for use in writing closures in a shortened form, without losing clarity or intent.

Closure expression syntax takes the following general form:

{ (parameters) -> return type in
 statements
}

Closure expression syntax can use constant parameters, variable parameters, and inout parameters, but default values cannot be used. Variadic parameters can be used if you name them and make sure that it’s placed last in the parameter list.

The Sort Function

To understand how Closures are used, let’s take a look at a function called sort, which is available in Swift’s standard library. The sort function orders an array of values of a known type.

The sort method takes two arguments:
– An array of values of a known type.
– A closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the sorting is complete.

The example below shows the sorting of an array of String values. The sorting closure needs to be a function of type (String, String) -> Bool.
One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as the sort method‘s parameter:

func backwards(s1: String, s2: String) -> Bool {
   return s1 > s2
}
let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
var reversed = names.sort(backwards)

The example compares the Strings in the array names, based on the backwards function.
However, this is a long-winded way to write what is really a function that contains a single-expression (a > b).
In this situation, it would be preferable to write the sorting closure inline, using closure expression syntax:

let names = ["Cc", "Aa", "Ee", "Bb", "Dd"]
reversed = names.sort({ (s1: String, s2: String) -> Bool in
   return s1 > s2
})

For the inline closure expression, the parameters and return type are written within the curly braces, rather than outside of them.
The in keyword is used to introduce the beginning of the closure’s body, and indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.

Inferring Type from Context

The sorting closure is passed as an argument to a function, making it possible for Swift to infer the types of its parameters and the type of the return value from the type of the sort method‘s second parameter. This parameter expects a function of type (String, String) -> Bool. This means that writing the (String, String) and Bool types as part of the closure expression’s definition is not necessary. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted:

reversed = names.sort( { s1, s2 in return s1 > s2 } )

The parameter types and return type can always be inferred when passing a closure to a function as an inline closure expression. As a result, it is unnecessary to write an inline closure in its fullest form when the closure is used as a function argument.
You still have the option of writing out the types. In fact, doing so is encouraged when you need to avoid ambiguity for others who might read your code.

Single-expression closures can implicitly return the result of their single expression, simply by omitting the return keyword from the declaration, as in this new version of the previous example:
reversed = names.sort( { s1, s2 in s1 > s2 } )

Here, the function type of the sort method‘s second argument makes it clear that a Bool value must be returned by the closure.
Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted.

Shorthand Argument Names

Swift automatically provides shorthand argument names for inline closures. These argument names can be used to refer to the values of the closure’s arguments, with the names $0, $1, $2, and so on.

If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, since the closure expression is entirely made up of its body:

reversed = names.sort( { $0 > $1 } )

Here, $0 and $1 refer to the closure’s first and second String arguments.

Operator Functions

There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sort method‘s second parameter. Just pass in the greater-than operator, and Swift will then infer that you want to use its string-specific implementation:

reversed = names.sort(>)
Closures in Swift

Some Additional Functionalities Of Swift – Part 2

Functions

In Swift, every function has a type that contains the function’s parameter types and return type. This type can be used like any other type in Swift, and this makes passing functions as parameters to other functions and returning functions from functions easier.
Functions can also be written within other functions to encapsulate useful functionality within a nested function scope.

Variadic Parameters

Variadic parameters indicate that the number of input values of a specified type passed to the parameter can vary. The variadic parameter can accept zero and/or more parameters of a certain type, and is indicated by adding three period characters (…) immediately following the parameter‘s type name.

The values passed to a variadic parameter appear as an array of the specified type in the function’s body.

In the example below, the function calculates the arithmetic mean, or average, for a list of numbers of any length:

func arithmeticMean(numbers: Double...) -> Double {
   var total: Double = 0
   for number in numbers {
     total += number
   }
   return (total / Double(numbers.count))
}

One variadic parameter is allowed per function. The variadic parameter must always be the last parameter in the list, to ensure clarity when calling the function with multiple parameters.
For a function with one or more parameters containing default values, as well as a variadic parameter, the variadic parameter is added at the very end of the list, following all defaulted parameters.

In-Out Parameters

A variable parameter is changeable only within the function. The in-out parameter is used as an alternative to the variable parameter in instances in which you want a change to continue after the function call ends.

The inout keyword is placed at the beginning of the parameter‘s definition. Its value is passed in to the function, where it is modified. It’s then passed back out of the function, where it replaces the original value.

This example swaps out two Integer values.

func swapInts(inout a: Int, inout b: Int) {
   let tempA = a
   a = b
   b = tempA
}

An in-out parameter cannot be assigned a default value. A variadic parameter cannot be marked as inout. A parameter that is marked as inout cannot also be marked as var or let.
An ampersand (&) that is inserted directly before a variable‘s name when it’s passed as an argument to an inout parameter, indicates that the variable can be modified by the function:

var someInt = 3
var anotherInt = 107
swapInts(&someInt, &anotherInt)

The in-out parameter presents an alternative method when a function is desired to have an effect outside of the scope of its function body.

Function Types

Every function has a specific function type that consists of the function’s parameter types and return type. Here’s an example:

func addInts(a: Int, b: Int) -> Int {
 return a + b
}
func multiplyInts(a: Int, b: Int) -> Int {
 return a * b
}

This example defines two simple mathematical functions called addInts and multiplyInts, which take two Int values, which return an Int value.
For both of these functions, the type is (Int, Int) -> Int. This can be interpreted as
“A function type that has two parameters, both of type Int; and that returns a value of type Int.”

Here’s another example. This one shows a function with no parameters or return value:

func printHelloWorld() {
   print("Hello, world")
}

The type of this function is () -> Void, which translates into “a function that has no parameters, and returns Void.”

Using Function Types

Function types are used in the same way as any other Swift types.
For example, define a constant or a variable to be of a function type. Then assign an appropriate function to that variable:

var mathFunction: (Int, Int) -> Int = addInts

You can now call the assigned function using its name, mathFunction.

print("Result: \(mathFunction(2, 3))")

A different function with the same type can be assigned to the same variable, in the same way as for non-function types.

Function Types as Parameter Types

A function type, such as (Int, Int) -> Int, can act as a parameter type for a different function, allowing for leaving some aspects of a function’s implementation for the function’s caller to provide calling the function.
The following example defines a function called printResult, which takes another function as its parameter and calls it as it’s implemented:

func printResult(mathFunc: (Int, Int) -> Int, a: Int, b: Int) {
   print("Result: \(mathFunc(a, b))")
}
printResult(addInts, 3, 5) 

It doesn’t matter what the called function’s implementation actually does – it matters only that the function is of the correct type.

Function Types as Return Types

A function type may be used as another function’s return type, by writing a complete function type immediately following the return arrow (->) in the returning function.

func plus(input: Int) -> Int {
   return input + 1
}
func minus(input: Int) -> Int {
   return input - 1
}
func chooseFunc(flag: Bool) -> (Int) -> Int {
   if(flag) {
     return plus
   }
   else {
     return minus
   }
}

In the above example, the chooseFunc function returns another function of type (Int) -> Int, based on the value of its flag parameter.

Nested Functions

You also have the option of defining functions inside the bodies of other functions. These are called nested functions.

By default, a nested function is hidden from the outside world. It can still be called and used by its enclosing function. An enclosing function can also return one of its nested functions, thus allowing the nested function to be used in another scope.

From the previous lesson, the function chooseFunc can be rewritten to use and return nested functions:

func chooseFunc(flag: Bool) -> (Int) -> Int {
   func plus(input: Int) -> Int { return input + 1 }
   func minus(input: Int) -> Int { return input - 1 }
   if(flag) {
     return plus
   }
   else {
     return minus
   }
}
Some Additional Functionalities Of Swift – Part 2

Sets & Set Operations

Sets

A set stores distinct values of the same type in a collection with no defined ordering. Sets are used as an alternative to arrays when item order is not a concern or when you need to ensure that an item appears only once.
For a Swift set, write the type as Set<T> where T is the type that the set is allowed to store. Unlike arrays, there is no equivalent shorthand for sets.
You can create an empty set of a certain type using initializer syntax:

var letters = Set<Character>()

Based on the initializer type, Swift infers the type of the letters to be Set<Character>.
An array literal will also work as shorthand when initializing a set with one or more values as a set collection.

var names: Set<String> = ["David", "Susan", "Robert"]

When initializing the type of set with an array literal that contains values of the same type, it is not necessary to write the type of set. The initialization could have been written in a shorter form:

var names: Set = ["David", "Susan", "Robert"]

Because all values in the array literal are of the same type, Swift infers that Set<String> is the correct type to use for the names variable.

Accessing and Modifying a Set

The count and isEmpty properties work the same way with a set as they do with an array.
Calling the set’s insert method adds a new item to a set.

names.insert("Paul")

You can remove an item from a set by calling the set’s remove method. The item is removed if it’s a member of the set, and the removed value is returned. It returns nil if the item is not contained in the set. Alternatively, use the set’s removeAll() method to remove all of the items in a set.

The contains method tells you whether or not a particular item is present in the set.

if names.contains("James") {
 print("James is here.")
} else {
 print("James is not with us.")
}

Iterating Over a Set

You can iterate over the values in a set with a for-in loop.

for name in names {
   print("\(name)")
}

Since Swift’s Set type does not provide defined ordering, use the sort() method to iterate over the values of a set in a specific order.

for name in names.sorted() {
   print("\(name)")
}

Set Operations

Swift allows you to efficiently perform fundamental set operations, such as combining sets, determining which values two sets have in common, or determining whether two sets contain all, some, or none of the same values.

Fundamental Set Operations

The illustration below depicts sets a and b, and shows the results of various set operations, as represented by the shaded regions:

The intersect method creates a new set, with only the values common to both sets.
The exclusiveOr method creates a new set with values in either set, but not both.
The union method creates a new set with all of the values in both sets.
The subtract method creates a new set with values not in the specified set.

For example, to combine the two sets: let oddDigits: Set = [1, 3, 5, 7, 9]

let evenDigits: Set = [0, 2, 4, 6, 8]
 
oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Set Membership and Equality

The illustration below depicts three sets: a, b, and c. The overlapping regions represent the elements that are shared among sets.
Set a is a superset of set b, because a contains all elements in b.
Conversely, set b is a subset of set a, because all elements in b are also contained by a.
Sets b and c are disjointed with one another, because they share no elements in common.
“is equal” operator (==): Determines whether two sets contain all of the same values.
isSubsetOf method: Determines whether all of the values of a set are contained in the specified set.
isSupersetOf method: Determines whether a set contains all of the values in a specified set.
isStrictSubsetOf or isStrictSupersetOf method: Determines whether a set is a subset or superset of, but not equal to, a specified set.
isDisjointWith method: determines whether two sets have any values in common.
Spend a little time playing with the methods to learn and understand their functions.


Sets & Set Operations

Some Additional Functionalities Of Swift – Part 1

Variable/Constant Declare & Assignment

let a,b,c : String //Can also take var
a = "T" // T
b = "T" // T
c = "T" // T

let d = "T" // T
d = "E" // Cannot assign to value: 'd' is a 'let' constant

let e,f,g : String
e="T";f="T";g="T" // Use Of SemiColon In Swift
print(e) // T
print(f) // T
print(g) // T

 

Comparison Operators

let a : AnyObject = "T" as NSString //Refrence Type Object
let b = a // Refrence Passed
let c = a // Refrence Passed

print(b === a) // True - Pointing Same Refrence
print(c !== a) // False - Pointing Same Refrence

 

Conditional Statements

let myPoint = (1, -1)
switch myPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}

The three switch cases declare placeholder constants x and y, which temporarily take on the two values from myPoint, creating a dynamic filter as part of a where clause. The switch case matches the current value of point only if the where clause’s condition evaluates to true for that value.

The final case matches all possible remaining values; a default case is not necessary to have an exhaustive switch statement.

Repeat-While

// Swift's repeat-while loop is similar to a do-while loop in other languages.
repeat {
x -= 1
} while x>0

Fallthrough

In Swift, switch statements do not fall through the bottom of each case into the next. Instead, the entire switch statement completes its execution when the first matching case is completed.
By contrast, C requires insertion of an explicit break statement at the end of every switch case to prevent fallthrough. By eliminating default fallthrough, Swift allows for more concise and predictable switch statements in comparison with C, and thus avoids inadvertently executing multiple switch cases.

In cases that require C-style fallthrough behavior, use the fallthrough keyword on a case-by-case basis. The example below uses fallthrough to create a number’s textual description.

let myInt = 5
var desc = "The number \(myInt) is"
switch myInt {
case 2, 3, 5, 7, 11, 13, 17, 19:
desc += " a prime number, and also"
 fallthrough
case 4:
desc += " add this without mathch and"
default:
desc += " an integer."
}
print(desc)

This prints “The number 5 is a prime number, and also add this without mathch and an integer.”

If myInt‘s value is one of the prime numbers in the list, text noting that the number is prime is appended to the end of the description. The fallthrough keyword then causes it to “fall into” the default case.
The fallthrough keyword does not check case conditions in the switch case into which execution falls. As with C’s standard switch statement behavior, the fallthrough keyword moves code execution directly to the statements inside the next (or default) case block.

Modifying an Array

Add an array of one or more compatible items using the addition assignment operator (+=):

 

shoppingList += ["Juice"]
shoppingList += ["Chocolate", "Cheese"]

 

Subscript syntax also changes a range of values all at once. This will even work with a replacement set of values with a length that is different from the original range.
In the following example, the elements with index 4, 5, 6 are replaced with two new values.

shoppingList[4...6] = ["Bananas", "Oranges"]

Don’t use subscript syntax to append a new item to an array.

Use the enumerate() method to iterate over an array when you need the integer index for each item in addition to its value. This returns a tuple for each item in the array that indicates that item’s index and value. You can decompose the tuple into temporary constants or variables as part of the iteration:

for (index, value) in shoppingList.enumerate() {
    print("Item \(index + 1): \(value)")
}

This will print the index and the value of the elements in the array.

Some Additional Functionalities Of Swift – Part 1

All about Properties in swift

First , let me talk about a property . Suppose if we need to change or access an iVar in your class using an object of your class, then there should be getter and setter methods assigned to the iVar. A property is used mainly when other objects need to change or access the ivars in your object, without manually defining getters and setters, or using @property (in objective – c).

In objective-c, @property declares a property in your class header. Here is an example:

@property (nonatomic, retain) NSString *myString;

@synthesize creates your setter and getter for your property (accessor methods). Without synthesize you have to write your own setter and getter implemention, like getMyString or setMyString (capitalize the first character of your property).

So, the above property declaration is equivalent to:

- (NSString*)myString {}
- (void)setMyString:(NSString*)newValue {}

Properties can be further classified into Stored properties and Computed properties.

Stored Property vs Computed property

Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value.

►Computed properties are provided by classes, structures, and enumerations.

►Stored properties are provided only by classes and structures.

In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the varkeyword) or constant stored properties (introduced by the let keyword).

The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created:

struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// the range represents integer values 0, 1, and 2
rangeOfThreeItems.firstValue = 6
// the range now represents integer values 6, 7, and 8

Instances of FixedLengthRange have a variable stored property called firstValue and a constant stored property called length. In the example above, length is initialized when the new range is created and cannot be changed thereafter, because it is a constant property.


Stored Properties of Constant Structure Instances

If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties:

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// this range represents integer values 0, 1, 2, and 3
rangeOfFourItems.firstValue = 6
// this will report an error, even though firstValue is a variable property

Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValueis a variable property.

NOTE: This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties.

The same is not true for classes, which are reference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties.


Lazy Stored Properties

A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration.

Please refer my article on lazy var : lazy var in ios swift

Computed Properties

In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

If you define get { } inside the property declaration, it makes that property to a computed property. And it cannot have initial value as when you access the property, it will always call get{} function declared in property.

We can skip the associated get and set keyword and their curly brackets if we do not have to set a value to the variable. Computed property with a getter but no setter is known as a read-only computed property. Check the below example:

var a:String{
return “a”
}
print(a) // prints a

The above declaration is same as:

var a:String{
get {
return “a”
}
}

►We can use an optional setter to the computed variable which accepts a newValue as parameter.

class Alphabets {
var _a:String?
var a:String {
get {
return _a ?? “not set”
}
set(newVal) { //you can use any name for the passed parameter.Default is newValue
_a = newVal
}
}
}
/*----------------------------------------------------*/
let alphabet1 = Alphabets()
alphabet1.a = “a”
print(alphabet1.a) // prints a

If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used. Here’s an alternative version of the Alphabets class, which takes advantage of this shorthand notation:

class Alphabets {
var _a:String?
var a:String {
get {
return _a ?? “not set”
}
set { // no values passed..
_a = newValue // default value name is newValue
}
}
}
/* — — — — — — — — — — — — — — — — — */
let alphabet1 = Alphabets()
alphabet1.a = “a”
print(alphabet1.a) // prints a

Well, what happens if you try to set a computed property in its own setter?

You cannot do that. It will call the same setter method again and again and it will create an endless loop. The app may crash due to a memory overrun.

By definition, a computed property is one whose value you cannot set because, well, it’s computed. It has no independent existence. The purpose of the setter in a computed property is not to set the value of the property but to set the values of other properties, from which the computed property is computed.

Property Observers:

Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value. You can add property observers to any stored properties you define, except for lazy stored properties. We can add property observers to ‘inherited’ property by method ‘overriding’.

You have the option to define either or both of these observers on a property:

  • willSet is called just before the value is stored.
  • didSet is called immediately after the new value is stored.

If you implement a willSet observer, it’s passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you don’t write the parameter name and parentheses within your implementation, the parameter is made available with a default parameter name of newValue.

Similarly, if you implement a didSet observer, it’s passed a constant parameter containing the old property value. You can name the parameter or use the default parameter name of oldValue.

Here is an example given by apple to explain the flow:

The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value. This is true even if the new value is the same as the current value.

Note:Computed property should be a variable.

let b:Int {
return 4 //error. error: ‘let’ declarations cannot be computed properties
}

Type Properties :

Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance.

You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.

In Swift, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports.

You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.

static and class both associate a method with a class, rather than an instance of a class. The difference is that subclasses can override class methods; they cannot override static methods.

The example below shows the syntax for type properties:

In the above example, we tried to override a static func in the subclass Enemybut got an error like : error: cannot override static method .

If you enjoyed reading this post and found it useful, please share and recommend it so others can find it 💚💚💚💚💚💚 !!!!

Thanks!!

All about Properties in swift