Please enable JavaScript.
Coggle requires JavaScript to display documents.
Swift Lang Guide ( Protocols ( Initializer Requirements (Class…
Swift Lang Guide
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.
- Protocol Syntax (superclass first)
-
-
- Mutating Method Requirements
-
-
-
- Adding Protocol Conformance with an Extension
- Declaring Protocol Adoption with an Extension
-
- Collections of Protocol Types
-
-
-
- Checking for Protocol Conformance
- Optional Protocol Requirements
- Providing Default Implementations
- Adding Constraints to Protocol Extensions
- String mutability is managed by choosing between a constant or a variable.
- String interpolation.
- Every string is composed of encoding-independent Unicode characters, and provides support for accessing those characters in various Unicode representations.
- Swift's String type is bridged with Foundation's NSString class
- String Literals
- multiline literal: """ """
- var emptyString = "" or String() => isEmpty()
- String Mutability (let or var)
diff: obj-c NSString and NSMutableString
- Strings Are Value Types
- issue a copy when it is passed around
- swift's compiler optimizes string usages!
- Working with Characters (for..in)
- Concatenating Strings and Characters
- String Interpolation
is a way to construct a new string value from a mix of constants, variables, literals and expressions ...
- Can't contain an unescaped backslash, a carriage return or a line feed.
- Unicode
Unicode is an international standard for encoding, representing, and processing text in different writing systems.
- Unicode Scalars
Behind the scenes, Swift's native String type is built from Unicode scalar values. A Unicode scalar is a unique 21-bit number for a character or modifier, such as U+0061 for LATIN SMALL LETTER A("a"), or U+1F425 for Front-Facing Baby Chick("xxx")
- in U+0000 to U+D7FF or U+E0000 to U+10FFFF; not in U+D800 to U+DFFF (all inclusive)
- Special Characters in String Literals
- \0 (null char), \ (blackslash), \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
- Extended Grapheme Clusters
Every instance of Swift's Character type represents a singer 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.
Eg: é (way1: LATIN SMALL LETTER E WITH ACUTE, or U+00E59; way2: LATIN SMALL LETTER E, or U+0065, and followed by the COMBINING ACUTE ACCENT scalar (U+0301)). The U+0301 is a graphically applied to the scalar that precedes it, turning an e into an é when it is rendered by a Unicode-aware text-rendering system.
- Incode: eAcute = "\u{E9}"; comEAcute: "\u{65}\u{301}"
- Counting Characters
use Count prop of string
*count NOT SAME NSString.length( count number of 16-bit code)
- Accessing and Modifying a String
(String.Index; not indexed by integer values)
for index in greeting.indices {}
use: startIndex, endIndex, index(before:),index(after:) and index(_:offsetBy:)
-
- Substrings
- prefix(_:) => instance of Substring not a string.
only use in short of time
- String and Character Equality
- extended grapheme clusters are canonically equipvalent(have same linguistic meaning and appearance, even if they are composed from different Unicode scalars behind the screen.)
- eg: é \u{65}\u{301} equals to \u{E9}; but LATIN CAPITAL LETTER A (U"0041, or "A") NOT Equals to CYRILLIC CAPITTAL LETTER A (U+0410, or "A"), as used in Russian. The characters are visually similar, but do not have the SAME LINGUISTIC MEANING.
- Prefix and Suffix Equality
hasPrefix(:); hasSuffix(:)
- theses methods perform a character-by-character canonical equivalence comparision between teh extended grapheme clusters in each string, as described in String and Character Equality
- Unicode Representations of Strings
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 know as code units. These include the UTF-8 encoding form (which encodes a string as 8-bit code units), the UTF-16 encoding form (which encodes a string as 16-bit code units), and same for UTF-32 encoding form
A Collection of UTF-8 code units (accessed with the string's utf8 property)
A collection of UTF-16 code units (... utf16 property)
A collection of 21-bit Unicode scalar values, equivalent to the string's UTF-32 encoding form (assecced with the string's unicodeScalars property)
-
- Terminology (Unary(!a,a!)/Binary/Ternary)
- Assignment (let (x, y) = (1,2))
- Arithmetic Operators
*default not overflow value
- Remainder (a%b same a%-b)
- Unary minus operator (before char not space) & Unary Plus Operator
- Compound Assignment Operators ( a += 2)
- Compare: [(1, "zebra") < (2, "apple") => true]; [(3, "apple") < (3, "bird") => true]; [(4, "dog") == (4, "dog") => true]
=> Rule: LEFT-TO-RIGHT
- Boolean cannot compare => tuple has a bool can not compare.
- Only support for tuples have fewer 7 elements
- Ternary Conditional Operator
**9. Nil-coalescing operator ( a ?? b)
- shorthand for a != nil ? a! : b**
- Closed Range Operator (a...b) => for .. in
- Half-Open Range Operator (a..<b)
- One-Sided Ranges
for name in names[2...]/names[...2]/names[..<2]
-
- tuples:
(array but item can be not same type)
- let http404Error = (404, "Not Found")
let (statusCode, statusMessage) = http404Error
let (justTheStatusCode, _) = http404Error
// or can use: http404Error.0, http404Error.1
- let http200Status = (statusCode: 200, description: "OK")
*Note: Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple
- Optionals
Where a value may be absent
If statement and Force Unwrapping
- if convertedNumber != nil {}
-
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.
find out whether an optional contains a value, to make sure value existed.
sample: if let/var actualNumber = Int(possibleNumber) { } else { }
NOTE
Constants and variables created with optional binding in an if statement are available only within the body of the if statement. In contrast, the constants and variables created with a guard statement are available in the lines of code that follow the guard statement, as described in Early Exit.
- 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.
These kinds of optionals are defined as implicitly unwrapped optionals. 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 optional.
do { try canThrowAnErr() } cacth Error.type1 { // an error has thrown } catch Error.type2(let abc) { funcUseParam(abc) }
- Assertions and Preconditions
(are checks that happen at runtime)
Use them to make sure an essential condition is satisfied before executing any further code If the Boolean condition in the assertion or precondition evaluates to true, code execution continues as usual. If the condition evaluates to false, the current state of the program is invalid; code execution ends, and your app is terminated
Diff: Assertions are checked only in debug builds. Preconditions are checked in both debug and production build.
In Production builds, the condition inside an assertion isn't evaluated. >> this means you can use as many assertions as you want during your development process, without impacting the performance in production.
Debugging with Assertions
- assert(::file:line:)
assert(age >= 0, "this error message"
- assertionFailure(_:file:line:)
Enforcing Precondition
precondition(::file:line:)
preconditionFailure(:file:line:)
*NOTE: (-0unchecked) mode compile, so preconditions are not checked. However fatalError(:file:line:) func always halts execution, regardless of optimization settings.
=> you can use fatalError func during prototyping and early development to create stub implementation. Because fatal erros are never optimized out, unlike assertions or preconditions, you can be sure that execution always halts if it encounters a stub implementation.
- Closures
are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages
- Closure can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables. Swift handles all of the memory management of capturing for you.
- Global Function: 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.
- Inferring parameter and return value types from context
- Implicit returns from single-expression closures
- Shorthand argument names
- Trailing closure syntax
-
- Closure Expression Syntax
{ (parameters) -> return type in statements }
- Inferring Type from Context
reversedNames = names.sorted(by: {s1, s2 in return s1 > s2 })
- Implicit Returns from Single-Expression Closures
reversedNames = names.sorted(by: {s1, s2 in s1 > s2})
- Shorthand Argument Name
reversedNames = names.sorted(by: { $0 > $1})
- Operator Methods
reversedNames = names.sorted(by: >)
- Trailing Closures
final argument
func someFuncTakeAClosure(closure: () -> Void) { // func body }
=> call this func without using a trailing closure
someFuncTakeAClosure(closure: { // closure's body goes here })
=> call this func with a trailing closure
someFuncTakeAClosure() { // trailing closure's body goes here }
eg: reversedNames = names.sorted { $0 > $1 }
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.
-
- Closures are references types
-
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns
One way that a closure can escape is by being stored in a variable that is defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later. For example:
var completionHandlers: [() -> Void] = []
func someFuncWithEscapingClosure(completionHandler: escaping () -> Void) { completionHandlers.append(completionHandler) }
An autoclosure is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function
Delay Execution
eg: let customerProvider = { customersInLine.remove(at: 0) } => not run until customerProvider()
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: autoclosure () -> String) {
print("Now serving (customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// Prints "Now serving Ewa!"
Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil
- Optional Chaining as an Alternative to Forced Unwrapping
- Defining Model Classes for Optional Chaining
- Accessing Properties Through Optional Chaining
- Calling Methods Through Optional Chaining
- Accessing Subscripts Through Optional Chaining
- Liking Multiple Level of Chaining
- Chaining on Methods with Optional Return Values
Extensions add new functionality to an existing class, structure, enumeration, or protocol type.
Extensions in Swift can:
- Add computed instance properties and computed type properties.
- Define instance methods and type methods
- Provide new initializers
- Define subscripts
- Define and use new nested types.
- Make an existing type conform to a protocol.
- In swift you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of.
*Note: extensions can add new functionality to a type, but they cannot override exisiting functionality.
- Extension Syntax:
extension SomeType { }
- an extension can extend an existing type to make it adopt one or more protocols. To add protocol conformance, you write the protocol names the same way as you write them for a class or structure:
extension SomeType: SomeProtocol, AnotherProtocol { }
- Computed Properties
=> but they can not add stored properties or add property observers to existing properties.
-
-
-
-
An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.
- Enumeration Syntax:
enum Test { case 1 /n case 2 /n case 3}
enum Planet { case mercury, venus, earth, mars, jupiter, satrun, uranus, neptune }
- The type of directionToHead is inferred when it is initialized with one of the possible values of CompassPoint. Once directionToHead is declared as a CompassPoint, you can set it to a different CompassPoint value using a shorter dot syntax: directionToHead = .east
- Matching Enumeration Values with a Switch Statement
-
- Implicitly Assigned Raw Values (number or origin string)
- Initializing from a Raw Value
-
-
- While loop (while; repeat-while)
-
-
- Interval Matching: case with 1..<5
- Tuples: (0,0),(,0),(0,),(-2...2, -2...2)
- Value Bindings: case (let x, 0)
- Where: case let (x, y) where x == y:
- Compound Class :case "a", "e", "i", "o", "u"
- Control Transfer Statements
-
-
-
-
-
-
- Early Exit
- guard always has else statement
- Checking API Availability
if #available([platform name] [version], macOS 10.12, *) {} else {}
Properties associate values with a particular class, structure, or enumeration
- type properties, property observers
- Stored Properties of Constant Structure Instances
- 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.
-
-
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
-
- Global and Local Variable
Not lazy, always set default value
-
-
- Comparing Classes and Structures
- Same
- Define properties and store values
- Define methods to provide functionality
- Define subcripts to provide access to their values using subscript syntax.
- Define initializers to set up their intial state
- Be extended to expand their functionality beyond a default implementation.
- Conform to protocols to provide standard functionality of a certain kind.
- Classes have additional capabilities that structures do not:
- 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.
-
- Class and Structure Instances
-
- Memberwise Initializers for Structure Types
- only structure have: let vga = Resolution(width: 640, height: 480)
- class must be initialize
- Structures and Enumerations Are Value Types
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.
- Classes Are Reference Types
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
Identity Operator (===, !==)
- Identical to: mean that 2 constants or variables of class type refer to exactly the same class instance.
- Equal to: means that 2 instances are considered "equal" or "equivalent" in value, for some appropriate meaning of "equal", as defined by the type's designer.
-
- Choosing Between Classes and Structures
- Structure instances are always passed by value versus class instances by reference
- creating struct when 1 or more of these conditions apply:
- The structure's primary purpose is to encapsulate a few relatively simple data values
- 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.
- Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced.
- The structure does not need to inherit properties or behavior from another existing type.
- Example of good candidates for structures include:
- The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double.
- A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int.
- A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double.
- Assignment and Copy Behavior for String, Arrays, and Dictionaries
- In swift: String, Array, Dictionary are implemented as structures
DIFF FROM Foundation: NSString, NSArray, and NSDictionary are implemented as classes, not structures
- Collection Types
(3 primary types: arrays/sets/dictionaries)
- Mutability of Collections (let or var)
- Array (sorted and duplicatable)
var threeDoubles = Array(repeating: 0.0, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
- for .. in
- for (index, value) in shoppingList.enumerated() {}
- Sets
stores distinct values of the same type in a collection with no defined ordering.
- Set<Element>()
- for .. in
- intersection/symmetricDifference/union/subtracting
- Dictionary
keys of same type and values of the same type with no defined ordering.
key type must conform to the Hashable protocol.
- create: var namesOfIntegers = Int: String
- create with literal: var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
- updateValue(_:forKey:) -> return old value
- for .. in loop
- String or String
Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence. You use subscripts to set and retrieve values by index without needing separate methods for setting and retrieval
-
-
Subscripts can use variadic parameters, but they can’t use in-out parameters or provide default parameter values.
-
-
-
- Accessing Superclass Methods, Properties, and Subscripts
-
-
- Preventing Overrides
(final: final var/func/class func/subscript)
=> all class: final class
- Defining a Class Hierarchy for Type Casting
- is (check operator) whether an instance is of a certain subclass type
- to sub class type: as!,as?
- Type Casting for Any and AnyObject
- Representing and Throwing Errors
- Handling Error (do-catch)
- Propagating Erros Using Through Functions
- Functions
- function type: consisting of the func's parameter types and return type
- Defining and Calling Functions
Function Argument Label(outside view), Parameter Name(inside view)
- Function Parameters and Return Values
- Function Without Parameters
- Function with multi parameters
- Functions without return values
- Function with Multiple Return Value
- Optional Tuple Return Types
- Function Argument Labels and Parameter Names
func (arglabel paramname x,...)
- Omitting Argument Labels (_)
-
- Variadic Parameters (Double...)
func swapTwoInts( a: inout Int, b: inout Int) {}
swapTwoInts(&someInt, &anotherInt)
- Using Func Type:
var mathFunction: (Int, Int) -> Int = addTwoInts
- Function Types as Parameters Type
- Func Types as Return Type
func chooseStepFun(backward: Bool) -> (Int) -> Int {}
- Nested Functions (all above is global func)
- Nested funcs are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing func can also return on of its nested functions to allow the nested function to be used in another scope.
- Methods (swift: all class, enum, struct)
- The self Property (count, parameter precedence)
- Modifying Value Types from Within Instance Methods
(struct, enum) => mutating func moveBy...
- Assigning to self Within a Mutating Method
can call another type methods, properties
-
- Referring to Nested Types
-
-
- Automatic Reference Counting
-
-
-