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
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
andendIndex
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
- 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:)
orisStrictSuperset(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 matchingswitch
case is completed, without requiring an explicitbreak
statement. - The body of each case must contain at least one executable statement.
Besides, the case value can be:
-
Range
switch approximateCount { case 0: naturalCount = "no" case 1..<5: naturalCount = "a few" case 5..<12: naturalCount = "several" default: naturalCount = "many" }
-
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") }
-
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))") }
-
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 = 在不满足条件的情况下才执行代码。
注意事项:
-
Guard must be inside the function
-
Guard must have else
-
Guard else must have control statement
-
Guard 的 else 语句简单,其中不应该放大量的代码
When guard?
-
多个optional解包,并且需要都满足条件(比如登录功能
guard let username = usernameTextField.text, !username.isEmpty else { show("用户名不能为空") return }
-
中断当前流程,当不满足条件时,不需要执行后面的逻辑 (比如校验手机号码是否正确)
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 aDictionary
, 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.
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 theclass
modifier.They achieve the same goal.
static
makes a property or a function static and not overridable. Usingclass
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
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)