Chapters: The Basics - Properties
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 2 Prerelease).” iBooks. https://itun.es/us/k5SW7.l
The Basics
Fundamental types: Bool, Int, Float, Double, String, Array, Set, Dictionary
Advanced types: tuples, optionals
-
How to declare multiple variables of the same type on a single line?
var red, green, blue: Double
-
Can a multiline comment be nested inside another multiline comment?
“Unlike multiline comments in C, multiline comments in Swift can be nested inside other multiline comments.”
-
When to properly use semicolons?
“Swift does not require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. Semicolons are required, however, if you want to write multiple separate statements on a single line:”
let helloStr = “Hello world”; print(helloStr)
-
What are all the integer types in Swift?
“Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names.”
-
What are the sizes of Int and UInt? When to use each?
- On a 32-bit platform, Int is the same size as Int32.
- On a 64-bit platform, Int is the same size as Int64.
- On a 32-bit platform, UInt is the same size as UInt32.
- On a 64-bit platform, UInt is the same size as UInt64.
“Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative.”
-
What are the sizes of floating point numbers?
- Double represents a 64-bit floating-point number.
- Float represents a 32-bit floating-point number.
“Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. In situations where either type would be appropriate, Double is preferred.”
-
What are the conventions for numeric literals?
- A decimal number, with no prefix
- A binary number, with a 0b prefix
- An octal number, with a 0o prefix
- A hexadecimal number, with a 0x prefix
- An uppercase or lowercase e for decimal floats
- 1.25e2 means 1.25 x 10^2, or 125.0
- An uppercase or lowercase p for hexadecimal floats
- 0xFp2 means 15 x 2^2, or 60.0
- Both integers and floats can be padded with extra zeroes and can contain underscores to help with readability
let paddedDouble = 000123.456
let justOverOneMillion = 1_000_000.000_000_1
-
How to add two basic types?
“Because each numeric type can store a different range of values, you must opt in to numeric type conversion on a case-by-case basis. SomeType(ofInitialValue) is the default way to call the initializer of a Swift type and pass in an initial value."
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one) -
How to use typealias?
typealias AudioSample = UInt16
-
How to use tuples?
let http404Error = (404, "Not Found") let (statusCode, statusMessage) = http404Error let (justTheStatusCode, \_) = http404Error print("The status code is \\(http404Error.0)") let http200Status = (statusCode: 200, description: "OK") print("The status code is \\(http200Status.statusCode)")
-
What is the benefit of using optionals?
"The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structures, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants."
-
What is the difference of optional in Swift and Objective C?
“Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a nonexistent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.”
-
What is force unwarpping of an optional value?
if convertedNumber != nil { print("convertedNumber has an integer value of \(convertedNumber!).") }
-
What is optional binding?
if let constantName = someOptional, var variableName = someOptional { statements }
-
What is Implicitly unwrapped optionals?
"Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make."
let possibleString: String? = "An optional string." let forcedString: String = possibleString! // requires an exclamation mark let assumedString: String! = "An implicitly unwrapped optional string." let implicitString: String = assumedString // no need for an exclamation mark
-
How to use error handling to response to error conditions?
func makeASandwich() throws { // ... } do { try makeASandwich() eatASandwich() } catch Error.OutOfCleanDishes { washDishes() } catch Error.MissingIngredients(let ingredients) { buyGroceries(ingredients) }
-
How to trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value?
let age = -3 assert(age >= 0, "A person's age cannot be less than zero")
-
When to use assertions?
- An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high.
- A value is passed to a function, but an invalid value means that the function cannot fulfill its task.
- An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully.
What is the relationship between basic types in objective C and Swift? For instance, can we cast NSArray to Array, NSDictionary to Dictionary?
Basic Operators
-
What is the difference between basic operators in Swift and C?
“The assignment operator (=) does not return a value, to prevent it from being mistakenly used when the equal to operator (==) is intended. Arithmetic operators (+, -, *, /, % and so forth) detect and disallow value overflow, to avoid unexpected results when working with numbers that become larger or smaller than the allowed value range of the type that stores them. You can opt in to value overflow behavior by using Swift’s overflow operators (such as a &+ b). Unlike C, Swift lets you perform remainder (%) calculations on floating-point numbers. Swift also provides two range operators (a..<b and a...b) not found in C, as a shortcut for expressing a range of values.”
-
What is the unary plus operator?
“The unary plus operator (+) simply returns the value it operates on, without any change. Although the unary plus operator doesn’t actually do anything, you can use it to provide symmetry in your code for positive numbers when also using the unary minus operator for negative numbers.”
-
What are identity operators?
“Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance.”
-
What is nil coalesing operator?
“The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.”
a ?? b a != nil ? a! : b
-
What are range operators in Swift?
-
“The closed range operator (a...b) defines a range that runs from a to b, and includes the values a and b. The value of a must not be greater than b.”
for index in 1...5 { print("\(index) times 5 is \(index * 5)") }
“The half-open range operator (a..<b) defines a range that runs from a to b, but does not include b. It is said to be half-open because it contains its first value, but not its final value. As with the closed range operator, the value of a must not be greater than b. If the value of a is equal to b, then the resulting range will be empty.”
-
-
What is the order of evaluation when there are multiple AND and OR in the same statement?
“The Swift logical operators && and || are left-associative, meaning that compound expressions with multiple logical operators evaluate the leftmost subexpression first.”
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword { print("Welcome!") } // is equivalent to if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword { print("Welcome!") }
Strings and Characters
-
What is "String" in Swift? What is the difference between String and NSString?
“A string is an ordered collection of characters, such as "hello, world" or "albatross". Swift strings are represented by the String type, which in turn represents a collection of values of Character type. Swift’s String and Character types provide a fast, Unicode-compliant way to work with text in your code.”
“Swift’s String type is bridged with Foundation’s NSString class. The entire NSString API is available to call on any String value you create when type cast to NSString. You can also use a String value with any API that requires an NSString instance.”
-
How to check if a String is empty except from using (aString == "")?
if emptyString.isEmpty { print("Nothing to see here") }
-
How to create a mutable string in Swift?
“You indicate whether a particular String can be modified (or mutated) by assigning it to a variable (in which case it can be modified), or to a constant (in which case it cannot be modified)”
“This approach is different from string mutation in Objective-C and Cocoa, where you choose between two classes (NSString and NSMutableString) to indicate whether a string can be mutated.”
-
Is String passed by value or reference?
“Swift’s String type is a value type. If you create a new String value, that String value is copied when it is passed to a function or method, or when it is assigned to a constant or variable. In each case, a new copy of the existing String value is created, and the new copy is passed or assigned, not the original version.”
“This behavior differs from that of NSString in Cocoa. When you create an NSString instance in Cocoa, and pass it to a function or method or assign it to a variable, you are always passing or assigning a reference to the same single NSString. No copying of the string takes place, unless you specifically request it.”
-
What characters are not allowed in string interpolation?
“The expressions you write inside parentheses within an interpolated string cannot contain an unescaped double quote (") or backslash (), and cannot contain a carriage return or line feed.”
-
What are special String literals?
- The escaped special characters \0 (null character), \ (backslash), \t (horizontal tab), \n (line feed), \r (carriage return), " (double quote) and ' (single quote)
- An arbitrary Unicode scalar, written as \u{n}, where n is a 1–8 digit hexadecimal number with a value equal to a valid Unicode code point.
-
What is a Character in Swift?
“Every instance of Swift’s Character type represents a single extended grapheme cluster. An extended grapheme cluster is a sequence of one or more Unicode scalars that (when combined) produce a single human-readable character.”
“Note that Swift’s use of extended grapheme clusters for Character values means that string concatenation and modification may not always affect a string’s character count.”
-
How to access and modify a String?
“Each String value has an associated index type, String.Index, which corresponds to the positions of each Character it contains.”
“Use the startIndex property to access the position of the first Character of a String. The endIndex property returns the “past-the-end” position of the last character, If the String is empty, startIndex and endIndex are equal.”
“A String.Index value can access its immediately preceding index by calling the predecessor() method, and its immediately succeeding index by calling the successor() method. Any index in a String can be accessed from any other index by chaining these methods together, or by using the global advance(start:n:) function.”
“Use the global function indices(_:) to create a Range of all of the indexes used to access individual characters in a string.”
“To insert a character into a string at a specified index, use the insert(_:atIndex:) method.”
“To insert another string at a specified index, use the splice(_:atIndex:) method.”
“To remove a character from a string at a specified index, use the removeAtIndex(_:) method.”
“To remove a substring at a specified range, use the removeRange(_:) method:”
-
How is string equality determined?
“Two String values (or two Character values) are considered equal if their extended grapheme clusters are canonically equivalent. Extended grapheme clusters are canonically equivalent if they have the same linguistic meaning and appearance, even if they are composed from different Unicode scalars behind the scenes.”
“To check whether a string has a particular string prefix or suffix, call the string’s hasPrefix(_:) and hasSuffix(_:) methods, both of which take a single argument of type String and return a Boolean value.”
-
How is Unicode represented?
“When a Unicode string is written to a text file or some other storage, the Unicode scalars in that string are encoded in one of several Unicode-defined encoding forms. Each form encodes the string in small chunks known as code units.”
You can access a String value in one of three other Unicode-compliant representations:
- A collection of UTF-8 code units (accessed with the string’s utf8 property)
- A collection of UTF-16 code units (accessed with the string’s utf16 property)
- A collection of 21-bit Unicode scalar values, equivalent to the string’s UTF-32 encoding form (accessed with the string’s unicodeScalars property)”
Collection Types
-
What are the collection types that Swift provides?
- Arrays are ordered collections of values.
- Sets are unordered collections of unique values.
- Dictionaries are unordered collections of key-value associations.
-
How to define mutable and immutable collection types? Which one is preferred?
“If you create an array, a set, or a dictionary, and assign it to a variable, the collection that is created will be mutable. If you assign an array, a set, or a dictionary to a constant, that collection is immutable, and its size and contents cannot be changed.”
“It is good practice to create immutable collections in all cases where the collection does not need to change. Doing so enables the Swift compiler to optimize the performance of the collections you create.”
-
What is the syntax for each collection type?
- “The type of a Swift array is written in full as Array<T>, where T is the type of values the array is allowed to store. You can also write the type of an array in shorthand form as [T].”
- “The type of a Swift set is written as Set<T>, where T is the type that the set is allowed to store. Unlike arrays, sets do not have an equivalent shorthand form.”
- “The type of a Swift dictionary is written in full as Dictionary<Key, Value>, where Key is the type of value that can be used as a dictionary key, and Value is the type of value that the dictionary stores for those keys. You can also write the type of a dictionary in shorthand form as [Key: Value]. The shorthand form is preferred and is used throughout this guide when referring to the type of a dictionary.”
-
Examples of valid operations on different collections.
// Arrays var someInts = [Int]() someInts = [] if someInts.isEmpty { print "array is empty" } someInts = [1, 2, 3] someInts = [Int](count: 3, repeatedValue: 10) var otherInts = [Int](count: 3, repeatedValue: 20) var totalInts = someInts + otherInts totalInts.append(30) totalInts += [40, 50] totalInts[7...8] = [30, 30] totalInts.insert(0, atIndex: 0) totalInts.removeAtIndex(0) totalInts.removeLast() for item in totalInts { print("\(item)") } for (index,value) in totalInts.enumerate() { print("\(index) \(value)") } // Sets var genres = Set<String>() genres = ["Rock", "Classical", "Hip hop"] let songs:Set<String> = ["A", "B", "C", "D", "E"] var singers:Set = ["A", "B", "C"] singers.insert("D") singers.remove("A") singers.removeAll() if songs.contains("A") { print("Awesome") } for song in songs.sort() { print("\(song)") } let otherSongs = ["D", "E", "F", "G"] let allSongs:Set = songs.union(otherSongs).sort() // "A", "B", "C", "D", "E", "F", "G" songs.intersect(otherSongs).sort() // "D", "E" songs.subtract(otherSongs).sort() // "A", "B", "C" songs.exclusiveOr(otherSongs).sort() // "A", "B", "C", "F", "G" songs.isSubsetOf(allSongs) // true songs.isStrictSubsetOf(allSongs) // true songs.isSupersetOf(allSongs) // false songs.isDisjointWith(otherSongs) // false // Dictionaries var namesOfIntegers = [Int:String]() namesOfIntegers = [:] namesOfIntegers = [1:"One", 2:"Two"] namesOfIntegers[3] = "Three" if let oldValue = namesOfIntegers.updateValue("三", forKey:3) { print("The old value for 3 was \(oldValue)") } namesOfIntegers[1] = nil if let removedValue = namesOfIntegers.removeValueForKey(3) { print("The removed value for 3 was \(removeValue)") } for (anInt, name) in namesOfIntegers { print("The name of \(anInt) is \(name)") } print("\(namesOfIntegers.keys") print("\(namesOfIntegers.values")
Control Flow
-
For loops
// for-in loop let names = ["A", "B", "C", "D"] for name in names { print(name) } let numberOfLegs = ["Cat": 4, "Dog": 4, "Spider":6] for (animal, legCount) in numberOfLegs { print("\(animal)s have \(legCount) legs") } // Traditional C-style for loop for var index = 0; index < 10; index++ { print("\(index)...") }
-
While loops
// while evaluates its condition at the start of each pass through the loop while condition { statements } // repeat-while evaluates its condition at the end of each pass through the loop repeat { statements } while condition
-
Conditional Statements
// if statement if condition { statements } else if condition { statements } else { statements } // switch statement switch some_value_to_consider { case value1: respond to value1 case value2, value3: respond to value2 or 3 default: otherwise, do something else } // switch: interval matching switch grade { case 6...12: schoolStr = "elementary school" case 13...15: schoolStr = "junior high school" case 16...18: schoolStr = "senior high school" case 19...22: schoolStr = "college" default: schoolStr = "unknown" } // switch: tuples switch aPoint { case (0, 0): return "origin" case (\_, 0): return "on x axis" case (0, \_): return "on y axis" case (-2...2, -2...2): return "inside box" default: return "outside box" } // switch: value binding switch aPoint { case (0, 0): return "origin" case (let x, 0): return "on x axis with value \(x)" case (0, let y): return "on y axis with value \(y)" case (let x, let y): return "at (\(x), \(y))" } // switch: where switch aPoint { case let (x, y) where x == y: return "Point (\(x), \(y)) is on the line x == y" case let (x, y) where x == -y: return "Point (\(x), \(y)) is on the line x == -y" case (let x, let y): return "Point is at unknown position (\(x), \(y))" }
“In contrast with switch statements in C and Objective-C, switch statements in Swift do not fall through the bottom of each case and into the next one by default. The body of each case must contain at least one executable statement. To opt in to fallthrough behavior for a particular switch case, use the fallthrough keyword”
-
Control Transfer Statements
-
continue
“The continue statement tells a loop to stop what it is doing and start again at the beginning of the next iteration through the loop. It says “I am done with the current loop iteration” without leaving the loop altogether.”
-
break
“The break statement ends execution of an entire control flow statement immediately. The break statement can be used inside a switch statement or loop statement when you want to terminate the execution of the switch or loop statement earlier than would otherwise be the case.”
-
fallthrough
switch integerToDescribe { case 2, 3, 5, 7, 11, 13, 17, 19: description += " a prime number, and also" fallthrough default: description += " an integer." }
return
-
-
Labeled Statements
label_name: while condition { statements // continue label_name // break label_name }
-
Early Exit
guard let name = person["name"] else { return }
“A guard statement, like an if statement, executes statements depending on the Boolean value of an expression. You use a guard statement to require that a condition must be true in order for the code after the guard statement to be executed. Unlike an if statement, a guard statement always has an else clause — the code inside the else clause is executed if the condition is not true.”
-
Checking API Availability
if #available(iOS 9, OSX 10.10, \*) { // Use iOS 9 APIs on iOS, and use OS X v10.10 APIs on OS X } else { // Fall back to earlier iOS and OS X APIs }
Functions
-
What do functions without return value really return?
“Strictly speaking, a function with no return value is defined, does still return a value. Functions without a defined return type return a special value of type Void. This is simply an empty tuple, in effect a tuple with zero elements, which can be written as ().”
-
How is function named?
“Function parameters have both an external parameter name and a local parameter name. An external parameter name is used to label arguments passed to a function call. A local parameter name is used in the implementation of the function.”
“By default, the first parameter omits its external name, and the second and subsequent parameters use their local name as their external name. All parameters must have unique local names, but may share external parameter in common.”
“If you do not want to use an external name for the second or subsequent parameters of a function, write an underscore (_) instead of an explicit external name for that parameter.”
“You can define a default value for any parameter in a function by assigning a value to the parameter after that parameter’s type. If a default value is defined, you can omit that parameter when calling the function. Place parameters with default values at the end of a function’s parameter list. This ensures that all calls to the function use the same order for their non-default arguments, and makes it clear that the same function is being called in each case.”
func someFunction(externalParameterName localParameterName:Int = 12) { // function could use localParameterName to refer to the argument }
-
What is variadic parameter?
“A variadic parameter accepts zero or more values of a specified type. You use a variadic parameter to specify that the parameter can be passed a varying number of input values when the function is called. Write variadic parameters by inserting three period characters (...) after the parameter’s type name. The values passed to a variadic parameter are made available within the function’s body as an array of the appropriate type. For example, a variadic parameter with a name of numbers and a type of Double... is made available within the function’s body as a constant array called numbers of type [Double].”
“A function may have at most one variadic parameter, and it must always appear last in the parameter list, to avoid ambiguity when calling the function with multiple parameters. If your function has one or more parameters with a default value, and also has a variadic parameter, place the variadic parameter after all the defaulted parameters at the very end of the list.”
-
What is a variable parameter?
“Variable parameters are available as variables rather than as constants, and give a new modifiable copy of the parameter’s value for your function to work with. Define variable parameters by prefixing the parameter name with the keyword var. Note that the changes you make to a variable parameter do not persist beyond the end of each call to the function, and are not visible outside the function’s body. The variable parameter only exists for the lifetime of that function call.”
-
What is a in-out parameter?
“If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead. You write an in-out parameter by placing the inout keyword at the start of its parameter definition. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.”
“You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an inout parameter, to indicate that it can be modified by the function.”
“In-out parameters cannot have default values, and variadic parameters cannot be marked as inout. If you mark a parameter as inout, it cannot also be marked as var or let.”
-
What are nested and global functions?
“Global functions are defined at a global scope. You can also define functions inside the bodies of other functions, known as nested functions.Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.”
Closures
-
What are the three forms of closures?
- Global functions are closures that have a name and do not capture any values.
- Nested functions are closures that have a name and can capture values from their enclosing function.
- Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
Note that a closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
Functions and closures are reference types. Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure.
-
What is the general form of closure expression syntax?
{ (parameters) -> return_type in statements }
-
Examples of simplified closures.
// inferring type from context reversed = names.sort( {s1, s2 in return s1>s2 } ) // inexplicit returns from single-expression closures reversed = names.sort( {s2, s2 in s1>s2} ) // shorthand argument names reversed = names.sort( {$0>$1} ) // operator functions reversed = names.sort(>) // trailing closures reversed = names.sort() {$0>$1}
Enumerations
- When can one use the shorthand dot syntax?
“Once a variable is declared as a enum class object, you can set it to a different value using a shorter dot syntax. This makes for highly readable code when working with explicitly-typed enumeration values.”
- What are associated values?
“You can define Swift enumerations to store associated values of any given type, and the value types can be different for each member of the enumeration if needed. ”
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
- What are raw values?
“As an alternative to associated values, enumeration members can come prepopulated with default values (called raw values), which are all of the same type.”
enum ASCIIControlCharacter : Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
Classes and structures
-
Common characteristics of classes and structures.
- Define properties to store values
- Define methods to provide functionality
- Define subscripts to provide access to their values using subscript syntax
- Define initializers to set up their initial state
- Be extended to expand their functionality beyond a default implementation
- Conform to protocols to provide standard functionality of a certain kind
-
Additional capabilities of classes.
- Inheritance enables one class to inherit the characteristics of another.
- Type casting enables you to check and interpret the type of a class instance at runtime.
- Deinitializers enable an instance of a class to free up any resources it has assigned.
- Reference counting allows more than one reference to a class instance. (Structures are copied when they are passed around in code, and do not use referecen counting.)
-
What is memberwise initializer?
“All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances.”
struct Resolution { var width = 0 var height = 0 } let vga = Resolution(width: 640, height:480)
-
What is the difference between value type and reference type?
“A value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function. Structures and enumrations are value types. Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.”
“Unlike value types, reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead. Classes and functions are reference types.”
-
Identity operators (===) and (!==).
“Note that “identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==).”
“Identical to(===)” means that two constants or variables of class type refer to exactly the same class instance.”
“Equal to(==)” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer.”
“When you define your own custom classes and structures, it is your responsibility to decide what qualifies as two instances being “equal”. ”
Properties
-
Can we change the property of a constant value type or reference type?
“If a value type is declared as a constant (with the let keyword), it is not possible to change its property, even though the property is a variable property. he 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.”
-
What is a lazy stored property?
“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.”
“If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.”
-
What are 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.”