Swift基础语法速通(突击学会

Swift Grammar

!从各路教程官方文档节选的内容➕一些个人理解
适合
初学者考试突击

需要短时间快速浏览swift语言特点
的朋友

Introduction

Swift doesn't have header file

Compiled language

Variables、Constants、Literals

Variables Constants
var let

A literal is the source code representation of a value of an integer, floating-point number, or string type.

起名:可以是任意unicode表示的包括pi,包括emoji,但是数学符号箭头空格不行,且不能以数字开头。

Definition:

var siteName:String = "Northeastern"
var id: Int
  • 类型注释 Type annotation: let money : Int = 15
  • 类型推论 Type Inference: let thisIsInteger = 15

Boolean:

Swift has type safety, which prevent non-Boolean values using as bool

即不能用1和0代替true和false

Operations

Range

Operator Description
闭区间 (a...b) defines a range that runs from a to b, and includes the values a and b.
半开半闭区间 (a..< b) defines a range that runs from a to b, but does not include b.
单边区间 a... or ...a defines a range that runs from a to end of elements or form start of elements to a

Ternery Condition

Condition ? X : Y

If Condition is true ? Then value X : Otherwise value Y

Identity Operators

=== and !==

References are to the same object instance

String and Characters

Create Character

let char : Character  = “?”
let catCharacters: [ Character ] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters) //可以从字符list转String

Multiline String Literals

../_images/multilineStringWhitespace_2x.png

Initialize String

To create an empty String value as the starting point for building a longer string, either assign an empty string literal to a variable, or initialize a new String instance with initializer syntax:

var emptyString = ""               // empty string literal
var anotherEmptyString = String()  // initializer syntax

Find out whether a String value is empty by checking its Boolean isEmpty property:

if emptyString.isEmpty {
    print("Nothing to see here")
}

.count to get string length and .isEmpty to check if length is 0

直接用+或者append()连接string和character都可以,但不能直接append给character类型

String Indice

  • startIndex property to access the position of the first character of a String.

  • endIndex property is the position after the last character in a String.

    As a result, the endIndex property isn't a valid argument to a string's subscript.

    If a String is empty, startIndex and endIndex are equal.

let greeting = "Hello,World!"
greeting[greeting.startIndex]
// H
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// e
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// o

! Index() return a variable type 'Index'

//循环遍历
for index in greeting.indices {
    print("\(greeting[index]) ", terminator: "")
}

Insert and remove

var welcom = "hello there!"
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"

let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals "hello"

SubString

let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is "Hello"

String Compare

use == and != 即可

Two String values (or two Character values) are considered equal if their extended grapheme clusters are canonically equivalent.

就是实际输出看起来一样就一样。

查找特定前后缀: hasPrefix() / hasSuffix()

Collection Type

Mutability

Assigned to variable will be mutable, assigned to constants will be immutable.

Arrays

//Create array
var someInts: [Int] = []

//add element
someInts.append(3)

//other initialize
var three = Array(repeating: 0.0, count: 3) //[0.0, 0.0, 0.0]

//combine two arrays
var arrayC = arrayA + arrayB //append()也可

//insert and remove
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
let apples = shoppingList.removeLast() //remove last element

//replace
shoppingList[4...6] = ["Bananas", "Apples"]//数量不一样也可以replace

Sets

//Creat set
var letters = Set<Character>()

Sets Operation

../_images/setVennDiagram_2x.png

  • Use the isSubset(of:) method to determine whether all of the values of a set are contained in the specified set.
  • Use the isSuperset(of:) method to determine whether a set contains all of the values in a specified set.
  • Use the isStrictSubset(of:) or isStrictSuperset(of:) methods to determine whether a set is a subset or superset, but not equal to, a specified set.
  • Use the isDisjoint(with:) method to determine whether two sets have no values in common.

Dictionary

// create dict
var namesOfIntegers: [Int: String] = [:]
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

//Iterating Over a Dictionary
for (airportCode, airportName) in airports {
    print("\(airportCode): \(airportName)")
}

Subscripts

subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence.

包括数组访问index,字典获取某键的值都是Subscript访问。

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// Prints "six times three is 18"
enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    static subscript(n: Int) -> Planet {
        return Planet(rawValue: n)!
    }
}
let mars = Planet[4]
print(mars)

Optional

There is another data type in Swift called Optional, whose default value is a null value (nil). You can use optional when you want a variable or constant contain no value in it. An optional type may contain a value or absent a value (a null value).

If an optional contains a value in it, it returns value as Optional<Value>, if not it returns nil.

let someValue:Int? = 5
print(someValue) //Optional(5)
print(someValue!) //5

如果不确定有值不要用!unwrapping,程序会crush

//Better use
var someValue:Int?
if someValue != nil {
	print("It has some value \(someValue!)")
} else {
	print("doesn't contain value")
}

Note:

“nil” cannot be used with nonoptional constants and variables.

If a constant or variable needs to work with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type.

Optional Binding (if-let)

if let unwrappedGrade = grade{
	print(unwrappedGrade)
}else{
	print("________")
}

Nil-coalescing operator 双问号默认值

通过双问号给Optional赋一个为空时的默认值

var someValue:Int? = 10
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue

//more useful 🌰
let name: String? = nil
print("你好,"+(name ?? "匿名用户"))

Optional Chaining

Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. “Optional chaining using ?. to call an object either returns value else return nil”. This prevents crashes at runtime and helps you write more productive code.

let isPNG = imagePaths["star"]?.hasSuffix(".png")

Enum

  • Enumeration name starts with Uppercase
  • Raw Value should be unique in declaration
enum Season {
  case spring, summer, autumn, winter
}

Enum Iterate

Use caseIterable protocol to iterate.

enum Season: caseIterable {
  case spring, summer, autumn, winter 
}
for currentSeason in Season.allCases {
  print(currentSeason)
}
Initializing form a raw Value
enum Size : Int {
  case small = 10
  case medium = 12
  case large = 14
}

// access raw value of python case
var result = Size.small.rawValue

//Implicitly Assigned
enum Planet: Int { 
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune 
}
let possiblePlanet = Planet(rawValue: 7) 
// possiblePlanet is of type Planet? and equals Planet.uranus

Control Flow

For loop

For In

Use the for-in loop to iterate over a sequence (items in an array, ranges of numbers, or characters in a string

let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
    print("Hello, \(name)!")
}

​ Also it can iterate over a dictionary to access its key-value pairs.

let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)s have \(legCount) legs")
}

Use the

stride(from:to:by:) or stride(from:through:by)

Functions to skip the unwanted marks, by = 步长

let interval = 3,min = 60,hour = 24
// 开区间结束用to
for tick in stride(from: 0, to: min, by:interval) {
}
//闭区间结束用through
for tickH in stride(from: 0, through: hour, by:interval){
}

While loop

Just normal while conditions{ statements}

Repeat-While loop

The repeat-while loop performs a single pass through the loop block first, before considering the loop’s condition. It then continues to repeat the loop until the condition is false.

repeat {
    statements
} while condition

//打印从i到n到所有数字
repeat {
 	print(i)
  i = i + 1
} while (i <= n)

Switch

switch some value to consider {
case value 1:
    respond to value 1
case value 2,
     value 3:
    respond to value 2 or 3
default:
    otherwise, do something else
}
Notes:
  • The entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit break statement.
  • The body of each case must contain at least one executable statement.

Besides, the case value can be:

  1. Range

    switch approximateCount {
    case 0:
        naturalCount = "no"
    case 1..<5:
        naturalCount = "a few"
    case 5..<12:
        naturalCount = "several"
    default:
        naturalCount = "many"
    }
    
  2. Tuple

    Alternatively, use the underscore character (_), also known as the wildcard pattern, to match any possible value. (注:通配符模式)

    switch somePoint {
    case (0, 0):
        print("\(somePoint) is at the origin")
    case (_, 0):
        print("\(somePoint) is on the x-axis")
    case (0, _):
        print("\(somePoint) is on the y-axis")
    case (-2...2, -2...2):
        print("\(somePoint) is inside the box")
    default:
        print("\(somePoint) is outside of the box")
    }
    
  3. Value Bindings

    A case can name the value or values it matches to temporary constants or variables, for use in the body of the case.

    let anotherPoint = (2, 0)
    switch anotherPoint {
    case (let x, 0):
        print("on the x-axis with an x value of \(x)")
    case (0, let y):
        print("on the y-axis with a y value of \(y)")
    case let (x, y):
        print("somewhere else at (\(x), \(y))")
    }
    
  4. Where

    Use a where clause to check for additional conditions.

    switch yetAnotherPoint {
    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")
    }
    

Control Transfer Statements

  • continue
  • break
  • fallthrough
  • return
  • throw
fallthrough

使用该关键字使switch中执行了一个匹配的case之后仍然落入default.

var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}

Label

可以给循环和条件语句加标签,方便指示正在操作的是哪个循环/条件。

gameLoop: while square != finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        continue gameLoop
    default:
        square += diceRoll
        square += board[square]
    }
}

Guard statement

guard expression else { 
    statement
    control statement:return,break,continue or throw
}

Guard = 在不满足条件的情况下才执行代码。

How guard statement works in Swift

注意事项:

  • Guard must be inside the function

  • Guard must have else

  • Guard else must have control statement

  • Guard 的 else 语句简单,其中不应该放大量的代码

When guard?
  1. 多个optional解包,并且需要都满足条件(比如登录功能

    guard let username = usernameTextField.text, !username.isEmpty else {
        show("用户名不能为空")
        return
    }
    
  2. 中断当前流程,当不满足条件时,不需要执行后面的逻辑 (比如校验手机号码是否正确)

    func verifyMobilePhoneNumber(_ phoneNumber: String) -> Bool {
        guard !phoneNumber.isEmpty {
            return false
        }
        // 检验逻辑。。。
    }
    

About the program

Functions

定义方法:

Indicate the function's return type with the arrow -> (a - and > together), which is followed by the name of return type.

func greet(person: String) -> String {
    let greeting = "Hello, " + person + "!"
    return greeting
}

Notes:

  • 没有返回值的可以省略void直接不写(。

  • If the entire body of the function is a single expression, the function implicitly returns that expression.

    func anotherGreeting(for person: String) -> String {
        return "Hello, " + person + "!"
    }
    
  • 可以返回多个值

    func minMax(array: [Int]) -> (min: Int, max: Int) {
        。。。
        return (currentMin, currentMax)
    }
    

Parameters of Functions

  • function parameter has both an argument label and a parameter name.

    argument label 用于调用函数时指定参数.

    //不写的话默认直接用参数名
    func someFunction(p1: Int, p2: Int) {...}
    someFunction(p1: 1, p2: 2)
    
    //或者专门指定argument label
    func greet(person: String, from hometown: String) -> String{
        return "Hi \(person), you are from \(hometown)."
    }
    print(greet(person: "Bill", from: "Cupertino"))
    
    //通配符忽略argument label,在调用时直接赋值
    func someFunction(_ p1: Int, p2: Int) {
    }
    someFunction(1, p2: 2)
    
  • 参数可以拥有默认值(则调用时不需要赋值

    func someFunction(p1: Int, p2hasDefault: Int = 12) {
    }
    someFunction(p1: 3, p2hasDefault: 6) //p2值为6
    someFunction(p1: 4) //此时p2值为12
    
  • Variadic Parameters 可变参数

    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.

    *此时传入的参数类型是array[Double]

    //求平均值
    func arithmeticMean(_ numbers: Double...) -> Double {
        var total: Double = 0
        for number in numbers {
            total += number
        }
        return total / Double(numbers.count)
    }
    arithmeticMean(1, 2, 3, 4, 5)
    
  • In-Out Parameters

    需要在func中更改传入的参数值并保留更改时使用,func参数前使用inout标记,调用func时传入参数前使用&标记

    //swap
    func swapTwoInts(_ a: inout Int, _ b: inout Int) {
        let temporaryA = a
        a = b
        b = temporaryA
    }
    var someInt = 3
    var anotherInt = 107
    swapTwoInts(&someInt, &anotherInt)
    

Function Type

Function type, made up of the parameter types and the return type of the function.

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}
// Type is (Int, Int) -> Int

Use function types just like any other types in Swift. For example, define a variable to be of a function type and assign an appropriate function to that variable:

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

因此可以把这个函数直接当参数传,也可以当返回值传:

  • Function Types as Parameter Types

    func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
        print("Result: \(mathFunction(a, b))")
    }
    printMathResult(addTwoInts, 3, 5)
    // Prints "Result: 8"
    
  • Function Types as Return Types

    func stepForward(_ input: Int) -> Int {
        return input + 1
    }
    func stepBackward(_ input: Int) -> Int {
        return input - 1
    }
    
    func chooseStepFunction(backward: Bool) -> (Int) -> Int {
        return backward ? stepBackward : stepForward
    }
    
Swift 函数可以嵌套。

Closures

Closures are self-contained blocks of functionality that can be passed around and used in your code.

Closures can capture and store references to any constants and variables from the context in which they're defined.

{ (parameters) -> return type in
    statements
}
  • 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.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
var thing = "cars"

let closure = { [thing] in
  print("I love \(thing)")
}
thing = "airplanes"

closure() // return I love cars.

The capture list creates a copy of thing when you declare the closure. This means that captured value doesn't change even if you assign a new value to thing.

Specific Functions

map(_😃

Returns an array containing the results of mapping the given closure over the sequence’s elements.

let strings = ["one","two","three"]

let ints = strings.map { (string) -> Int in
    return string.count
}
// $0 is a shortcut to mean "first argument" in a closure.
let ints = strings.map { $0.count }

在Dictionary中使用:

//把键值对转成数字
let ints = countries.map { $0.value.count }
//只把值转成数字保留dict格式和键
let ints = countries.mapValues { $0.count }

$0 is a shorthand name for first argument passed to closure. In this case, as you're mapping a Dictionary, that argument is a tuple - hence $0.0 is a key, and $0.1 is a value

reduce(_😃

跟map相似,不过是逐个组合所有元素。

takes two parameters, the first being the initial value and the second is a closure taking two parameters.

In the Closure, the first parameter is the previous value (or a starter value) and the second parameter is the current value in the collection. The operation is applied between these two values, which becomes the value to feed into the next iteration. The operation is repeated until the end of the collection is reached.

let nums = [1, 2, 3, 4]
let total1 = nums.reduce(0, { x, y in
    x + y  })
//输出结果是10
//逐渐简写
let total2 = nums.reduce(0) { x, y in x + y }
let total3 = nums.reduce(0) { $0 + $1 }
let total4 = nums.reduce(0, +)

//注意初始值
print("Product 0 = \(nums.reduce(0, *))")
// Product 0 = 0
print("Product 1 = \(nums.reduce(1, *))")
// Product 1 = 120

filter(_😃

The filter() method returns all the elements from the array that satisfy the provided condition.

var numbers = [2, 3, 6, 9]
var result = numbers.filter({ $0 > 5})
// Output: [6, 9]

var languages = ["Swedish", "Nepali", "Slovene", "Norwegian"]
var result = languages.filter( { $0.hasPrefix("N") } )
// return all the elements that start with "N"

Structures/Classes

Classes are reference types, and Structs are value types.

Reference Type:

When you copy a reference type, each instance shares the data, the reference itself is copied.When you change one, the other changes too.

Value Type:

When you copy a value type, each instance keeps a unique copy of the data. If you change one instance, the other doesn't change too.

Classes support a few more capabilities than struct:

  • Classes can inherit from another class
  • Classes can be deinitialized
  • Classes come with the built-in notion of identity, with the identity operator === you can check if two references refer to the same object.

Structs

  • Automatically generate memberwise initializer. 直接就调参数不用自己写
  • Structs is value types.

When Structs?

  • Simple Data Types

    不需要对象之间的复杂关系,结构简单

  • Thread Safety

    In a multi-threaded environment, for instance with a database connection that’s opened in a different thread, structs are safer. They can be copied from one thread to another thread, without running the risk of a race condition or deadlock.

  • Mostly Structs Scenario

    When the properties of a struct are mostly value types too, like String, it makes sense to wrap them in a struct instead of a class.

When Classes?

  • When Copying Doesn’t Make Sense

    e.g. with Window or UIViewController. It doesn't make sense to copy an app window, since there's only one active at a time

  • External Effects or Data

    Such as using a file on the disk, it doesn’t make sense to create two copies of a reference to the sam file.

  • Intermediaries

    When instances are merely conduits for external states, in those cases the class is only a conduit, something that passes along information, and it doesnt make sense to create a copy of that.

Properties

Stored Property Computed Property
Store constant and variable values as instance Calculate a value rather than storing the value
Stored Properties

The properties store actual values for each instance of the class.

class Calculator {
  // define two stored properties
  var num1: Int = 0
  var num2: Int = 0
}
Computed Properties

Rather than storing the values computed properties provide a getter and an optional setter to retrieve and set other properties and values indirectly.

class sample {
   var no1 = 0.0, no2 = 0.0
   var length = 300.0, breadth = 150.0

   var middle: (Double, Double) {
      get {
         return (length / 2, breadth / 2)
      }    
      set(axis){
         no1 = axis.0 - (length / 2)
         no2 = axis.1 - (breadth / 2)
      }
   }
}

Or make it easier,

class Calculator { 
  // define one computed property
  var sum: Int {
    num1 + num2
  }
}

Get 和 Set 方法可以直接通过赋值语句调用。

x = middle 调用get方法取得middle的值。

middle = x 调用set方法传入参数x,并根据其改变stored property的值。

Static Properties

Swift also has static properties which can be accessed and modified without creating objects, just modify it via Class name.

class University {
  static var name: String = ""
}

University.name = "Northeastern"

Here, name is the static property. Now to access and modify the value of a static property, we use the class name.

Lazy Stored Properties

Lazy stored properties are a way to defer the initialization of a property until it is first used.

Lazy Properties are used:

  • To delay object creation.
  • When the property is dependent on other parts of a class, that are not known yet

Always declare a lazy property as a variable (with the var keyword)

class sample {
   lazy var x = number()
}
class number {
   var name = "Northeastern"
}
var firstsample = sample()
print(firstsample.x.name)
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.

  • willSet is called just before the value is stored.
  • didSet is called immediately after the new value is stored.
var totalSteps: Int = 0 {
	willSet(newTotalSteps) {
  	print("set totalSteps to \(newTotalSteps)")
  }
  didSet {
  	if totalSteps > oldValue {
    	print("Added \(totalSteps - oldValue) steps")
		}
  }
}
Property wrappers

定义:

@propertyWrapper
struct TwelveOrLess {
    private var number = 0
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

调用:

struct SmallRectangle {
    @TwelveOrLess var height: Int
    @TwelveOrLess var width: Int
}

var rectangle = SmallRectangle()

rectangle.height = 24
print(rectangle.height)
// Prints "12"

Property wrapper 也可以在初始化时接收参数(直接加括号

Type Properties

A type property belongs to the type itself.

Regardless of whether an instance is created or not, the value of the type property is set. Type properties are useful for defining values common to all instances of a particular to a type.

struct someStructure{
    static var storedTypeProperty = "Some value"
    static var computedTypeProperty : Int{
        return 1
    }
}

Initialization

Customizing Initialization

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
//指定调用哪个初始化器
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
let freezingPointOfWater = Celsius(fromKelvin: 273.15)

和其他普通方法一样使用参数标签label(不是参数名),定义了标签必须使用

Initializer Delegation

Initializers can call other initializers to perform part of an instance’s initialization.

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

调用时若不传参则默认自动初始化Size和Point。

//记得通过label指定哪个初始化方法
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))

Designated Initializers and Convenience Initializers

//Designated initializer 主要
init(parameters) {
    statements
}
//Convenience Initializer 次要
convenience init(parameters) {
    statements
}

Rules:

  • A designated initializer must call a designated initializer from its immediate superclass.

  • A convenience initializer must call another initializer from the same class.

  • A convenience initializer must ultimately call a designated initializer.

../_images/initializersExample02_2x.png

Failable Initializers

不可跟nonfailable的重名。

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

Deinitialization

  • Called immediately before a class instance is deallocated
  • Can be used to perform some additional cleanup
class Player {
    var coinsInPurse: Int
    init(coins: Int) {
        coinsInPurse = Bank.distribute(coins: coins)
    }
    func win(coins: Int) {
        coinsInPurse += Bank.distribute(coins: coins)
    }
    deinit {
        Bank.receive(coins: coinsInPurse)
    }
}

Methods

Methods are functions that are associated with a particular type.

  • Instance methods: defined by classes, structures, and enumerations to encapsulate specific tasks and functionality for working with an* instance *of a given type.
  • Type methods are defined by classes, structures, and enumerations and are associated with the type itself.

Inheritance

  • Base Class: class without a superclass
//inheritance
class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "traveling at \(currentSpeed) miles per hour"
    }
    func makeNoise() {}
}

//Override
class Car: Vehicle {
    var gear = 1
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}
Prevent Override

writing the final modifier before the method, property, or subscript’s introducer to prevent final

It's possible to use either the static or the class modifier.

They achieve the same goal.

static makes a property or a function static and not overridable. Using class lets you override the property or function.

Type Casting

is operator

if A is B to check whether an instance is of a certain subclass type. Return Boolean

var movieCount = 0
var songCount = 0

for item in library {
    if item is Movie {
        movieCount += 1
    } else if item is Song {
        songCount += 1
    }
}
as operator downcasting

Use as? when there is a possiblity that casting failed

Only use as! while the downcasting will secceed in sure.

for item in library {
    if let movie = item as? Movie {
        print("Movie: \(movie.name), dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: \(song.name), by \(song.artist)")
    }
}

Extensions

  • Extensions cannot override existing functionality.
  • Extensions cannot add stored properties
  • Extensions cannot add property observers to existing properties.
extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")

总之就是可以往已有的类上加东西

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}

3.repetitions {
    print("Hello!")
}
//此处打印三次hello!

利用extension使类遵守新protocol

protocol TextRepresentable {
    var textualDescription: String { get }
}

extension Dice: TextRepresentable {
    var textualDescription: String {
        return "A \(sides)-sided dice"
    }
}

Protocols

if a class has a superclass, we can define any protocols after the superclass name:

class TheClass: ItsSuperclass, FirstProtocol, SecondProtocol {
}
  • A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits.

Mutable function in protocols

Place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and any properties of that instance.

protocol Togglable {
    mutating func toggle()
}

//!!!!In this situation the instance should be variable with var

Initialization protocol required

The use of the required modifier ensures that you provide an explicit or inherited implementation of the initializer requirement on all subclasses of the conforming class

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // initializer implementation goes here
    }
}

Error Handle

do {    
	let printerResponse = try 
	send(job: 1440, toPrinter: "Gutenberg")    	print(printerResponse)

} catch PrinterError.onFire {    
   print("I'll just put this over here, with the rest of the fire.")

} catch let printerError as  PrinterError {    
	print("Printer error: \(printerError).")

} catch {    
	print(error)
}

Generics

使类和函数可以使用通用数据类型。

func的例子:

//之前的swap函数
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

类和结构的例子(构造栈

struct Stack<Element> {
    var items: [Element] = []
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}

//Using
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
Type Constraint

func someFunction <T: SomeClass, U: SomeProtocol> (someT: T, someU: U)

func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == valueToFind {
            return index
        }
    }
    return nil
}
Associated Type

An associated type gives a placeholder name to a type that’s used as part of the protocol. The actual type to use for that associated type isn’t specified until the protocol is adopted.

protocol Container {
    associatedtype Item: Equatable //此处有constrain
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}
Where clause
extension Stack where Element: Equatable {}

Concurrency

An asynchronous function or asynchronous method is a special kind of function or method that can be suspended while it’s partway through execution.

func listPhotos(inGallery name: String) async -> [String] {
    let result = // ... some asynchronous networking code ...
    return result
}
async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1]) 
async let thirdPhoto = downloadPhoto(named: photoNames[2]) 

let photos = await [firstPhoto, secondPhoto, thirdPhoto] 

所有三个调用都downloadPhoto(named:)无需等待前一个调用完成即可开始。如果有足够的系统资源可用,它们可以同时运行。

Photos 处程序需要这些异步调用的结果,因此编写await暂停执行,直到所有三张照片完成下载。

Actor

Like classes, actors are reference types.

Unlike classes, actors allow only one task to access their mutable state at a time, which makes it safe for code in multiple tasks to interact with the same instance of an actor.

actor TemperatureLogger {
    let label: String
    var measurements: [Int]
    private(set) var max: Int

    init(label: String, measurement: Int) {
        self.label = label
        self.measurements = [measurement]
        self.max = measurement
    }
}
posted @ 2022-10-30 07:20  Lamplight  阅读(86)  评论(0编辑  收藏  举报