extensionInt { //前缀++ staticprefixfunc++(num:inoutInt) -> Int { num +=1 return num } //后缀++ staticpostfixfunc++(num:inoutInt) -> Int { let temp = num num +=1 return temp } //前缀-- staticprefixfunc--(num:inoutInt) -> Int { num -=1 return num } //后缀-- staticpostfixfunc--(num:inoutInt) -> Int { let temp = num num -=1 return temp } }
var aInt =0 var b = aInt++ print("aInt:\(aInt),b:\(b)") //输出:aInt:1,b:0
var c =++aInt print("aInt:\(aInt),c:\(c)") //输出:aInt:2,c:2
使用自增运算符:
1 2 3
var a =1 a +=2 // a is now equal to 3
这里a += 2是a = a + 2的简写形式。
2.String
String.Index
表示字符在字符串中的位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
let greeting ="Guten Tag!" greeting[greeting.startIndex] // G greeting[greeting.index(before: greeting.endIndex)] // ! greeting[greeting.index(after: greeting.startIndex)] // u let index = greeting.index(greeting.startIndex, offsetBy: 7) greeting[index] // a greeting[greeting.endIndex] // 报错:越界 greeting.index(after: greeting.endIndex) // 报错:越界
for index in greeting.indices { print("\(greeting[index]) ", terminator: "") } // Prints "G u t e n T a g ! "
增删字符
1 2 3 4 5 6 7 8 9 10 11 12 13
//增 var welcome ="hello" welcome.insert("!", at: welcome.endIndex) // welcome now equals "hello!" welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex)) // welcome now equals "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类型:
1 2 3 4 5 6 7
let greeting ="Hello, world!" let index = greeting.firstIndex(of: ",") ?? greeting.endIndex let beginning = greeting[..<index] // beginning is "Hello"
// Convert the result to a String for long-term storage. let newString =String(beginning)
3.集合
1.Array
Array<Element>表示数组的类型,简写作:[Element]。
1 2 3 4 5
var someInts: [Int] = [] print("someInts is of type [Int] with \(someInts.count) items.") // Prints "someInts is of type [Int] with 0 items." someInts.append(3) // someInts now contains 1 value of type Int
var shoppingList = ["Eggs", "Milk"] if shoppingList.isEmpty { print("The shopping list is empty.") } else { print("The shopping list isn't empty.") } // Prints "The shopping list isn't empty."
// 增 shoppingList.append("Flour") // shoppingList now contains 3 items, and someone is making pancakes shoppingList += ["Baking Powder"] // shoppingList now contains 4 items shoppingList += ["Chocolate Spread", "Cheese", "Butter"] // shoppingList now contains 7 items
// 读 var firstItem = shoppingList[0] // firstItem is equal to "Eggs" // 修改指定索引处的元素 shoppingList[0] ="Six eggs" // the first item in the list is now equal to "Six eggs" rather than "Eggs" shoppingList[4...6] = ["Bananas", "Apples"] // shoppingList now contains 6 items
// 插入 shoppingList.insert("Maple Syrup", at: 0) // shoppingList now contains 7 items // "Maple Syrup" is now the first item in the list
// 删除 let mapleSyrup = shoppingList.remove(at: 0) // the item that was at index 0 has just been removed // shoppingList now contains 6 items, and no Maple Syrup // the mapleSyrup constant is now equal to the removed "Maple Syrup" string
// 遍历 for item in shoppingList { print(item) } for (index, value) in shoppingList.enumerated() { print("Item \(index +1): \(value)") }
2.Set
Set是无序集合。
1 2 3 4 5 6 7 8 9 10 11 12 13
var letters =Set<Character>()
// 增 letters.insert("a") // letters now contains 1 value of type Character // 置空 letters = [] // letters is now an empty set, but is still of type Set<Character>
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"] favoriteGenres.insert("Jazz") // favoriteGenres now contains 4 items iflet removedGenre = favoriteGenres.remove("Rock") { print("\(removedGenre)? I'm over it.") } else { print("I never much cared for that.") } // Prints "Rock? I'm over it." if favoriteGenres.contains("Funk") { print("I get up on the good foot.") } else { print("It's too funky in here.") } // Prints "It's too funky in here."
// 遍历 for genre in favoriteGenres { print("\(genre)") }
// 更新 airports["LHR"] ="London Heathrow" iflet oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") { print("The old value for DUB was \(oldValue).") } // Prints "The old value for DUB was Dublin."
// 取值 iflet airportName = airports["DUB"] { print("The name of the airport is \(airportName).") } else { print("That airport isn't in the airports dictionary.") } // Prints "The name of the airport is Dublin Airport."
// 删除 iflet removedValue = airports.removeValue(forKey: "DUB") { print("The removed airport's name is \(removedValue).") } else { print("The airports dictionary doesn't contain a value for DUB.") } // Prints "The removed airport's name is Dublin Airport."
// 遍历字典 for (airportCode, airportName) in airports { print("\(airportCode): \(airportName)") } // 遍历键 for airportCode in airports.keys { print("Airport code: \(airportCode)") } // 遍历值 for airportName in airports.values { print("Airport name: \(airportName)") } // 取所有键 let airportCodes = [String](airports.keys) // 取所有值 let airportNames = [String](airports.values)
enumCompassPoint { case north case south case east case west }
var directionToHead =CompassPoint.west directionToHead = .east
directionToHead = .south switch directionToHead { case .north: print("Lots of planets have a north") case .south: print("Watch out for penguins") case .east: print("Where the sun rises") case .west: print("Where the skies are blue") } // Prints "Watch out for penguins"
遍历枚举
1 2 3 4 5 6 7 8
enumBeverage: CaseIterable { case coffee, tea, juice } let numberOfChoices =Beverage.allCases.count // 遍历 for beverage inBeverage.allCases { print(beverage) }
原始值
原始值可以是字符串、字符、或者任何整型值或浮点型值。
1 2 3 4 5 6 7
enumRank: Int { // 默认从0开始,往后递增。 case ace =1// 自定义case对应的值 case two, three, four, five, six, seven, eight, nine, ten case jack, queen, king } let ace =Rank.ace let aceRawValue = ace.rawValue
Int类型的枚举默认从0开始,往后递增。手动指定某个case的值后,其后面的枚举值也是递增。
1 2 3 4 5
enumCompassPoint: String { case north, south, east, west } let direction =CompassPoint.north.rawValue // "north" let south =CompassPoint(rawValue: "south") // "south"
CompassPoint.south隐式的原始值是字符串”south”。
相关值
1 2 3 4 5 6 7 8 9 10 11 12 13 14
enumServerResponse { case result(String, String) case failure(String) } let success =ServerResponse.result("6:00 am", "8:09 pm") let failure =ServerResponse.failure("Out of cheese.")
switch success { case .result(let sunrise, let sunset): print("Sunrise is at \(sunrise) and sunset is at \(sunset).") caselet .failure(message): print("Failure... \(message)") } // Prints "Sunrise is at 6:00 am and sunset is at 8:09 pm."
5.属性
1.存储属性
1 2 3 4 5 6 7 8 9
structNumber { var digits: Int let pi =3.1415 }
var n =Number(digits: 12345) n.digits =67 n.pi =3.1// 报错,pi是常量,不能修改
structNumber { var digits: Int let pi =3.1415 // 1.延迟属性 lazyvar aBool =TextBool() // 2.首次赋值使用默认语句 var onceInt:Int= { print("init Int at first call") return3 }() // 3.延迟+默认赋值语句 lazyvar onceDouble:Double= { print("init lazy Double at first call") returnDouble(pi+1) }() }
var n =Number(digits: 1) n.digits =2 print("\(n.digits)") print("This is \(n.aBool)") print(n.onceInt) print(n.onceDouble)
打印日志:
1 2 3 4 5 6 7
init Intatfirstcall 2 Init TextBool This is TextBool(aInt: 0) 3 init lazy Doubleatfirstcall 4.141500000000001
@propertyWrapper structTwelveOrLess { privatevar number =0 var wrappedValue: Int { get { return number } set { number =min(newValue, 12) } // 属性值不能>12 } }
@propertyWrapper structSmallNumber { privatevar maximum: Int privatevar number: Int
var wrappedValue: Int { get { return number } set { number =min(newValue, maximum) } }
//构造器1,不使用外部值,内部给定默认值 init() { maximum =12 number =0 } //构造器2,外部预设wrappedValue的值 init(wrappedValue: Int) { maximum =12 number =min(wrappedValue, maximum) } //构造器3,全部使用外部设置的值 init(wrappedValue: Int, maximum: Int) { self.maximum = maximum number =min(wrappedValue, maximum) } }
示例:调用构造器1
1 2 3 4 5 6 7
structZeroRectangle { @SmallNumbervar height: Int @SmallNumbervar width: Int } var zeroRectangle =ZeroRectangle() //调用默认构造器1 print(zeroRectangle.height, zeroRectangle.width) // Prints "0 0"
示例:调用构造器2
1 2 3 4 5 6 7
structUnitRectangle { @SmallNumbervar height: Int=1// 使用构造器2 @SmallNumbervar width: Int=1// 使用构造器2 } var unitRectangle =UnitRectangle() print(unitRectangle.height, unitRectangle.width) // Prints "1 1"
示例:调用构造器3
1 2 3 4 5 6 7 8 9 10 11 12 13
structNarrowRectangle { @SmallNumber(wrappedValue: 2, maximum: 5) var height: Int// 使用构造器3 @SmallNumber(wrappedValue: 3, maximum: 4) var width: Int// 使用构造器3 }
var narrowRectangle =NarrowRectangle() print(narrowRectangle.height, narrowRectangle.width) // Prints "2 3"
narrowRectangle.height =100 narrowRectangle.width =100 print(narrowRectangle.height, narrowRectangle.width) // Prints "5 4"
3.映射值
属性包装器中 projected value 是可以用来暴露额外功能的第二个值,它可以是任意类型。要通过属性包装器来映射值,需要在包装器的类型上定义projectedValue实例属性。编译器通过在包装属性的名称前面加上美元符号($)来合成映射值的标识符。
@propertyWrapper structSmallNumber { privatevar number: Int private(set)var projectedValue: Bool// 定义映射值(外部只读,内部可写)
var wrappedValue: Int { get { return number } set { if newValue >12 { number =12 projectedValue =true// 根据业务需求,设置映射值的内容 } else { number = newValue projectedValue =false } } }
classBook: NSCopying { var name: String? // 实现copy协议方法 funccopy(withzone: NSZone? =nil) -> Any { let copy =Book() copy.name = name return copy } }
classBooksShelf { @NSCopyingvar book: Book? }
//调用及日志 let book1 =Book() book1.name ="swift" let bookShelf =BooksShelf() bookShelf.book = book1 print(bookShelf.book === book1)//false
6.控制流
1.if else
1.一般用法:
1 2 3 4 5 6 7 8 9 10 11
let individualScores = [75, 43, 103, 87, 12] var teamScore =0 for score in individualScores { if score >50 { teamScore +=3 } else { teamScore +=1 } } print(teamScore) // Prints "11"
2.变量赋值:
可以在=号之后使用if或switch语句根据条件取变量的值:
1 2 3 4 5 6 7
let scoreDecoration =if teamScore >10 { "🎉"//省略了return } else { "" } print("Score:", teamScore, scoreDecoration) // Prints "Score: 11 🎉"
3.可选绑定
1 2 3 4 5 6 7 8 9
var optionalString: String? ="Hello" print(optionalString ==nil) // Prints "false"
var optionalName: String? ="John Appleseed" var greeting ="Hello!" iflet name = optionalName { //不为nil时 值绑定到常量name上 greeting ="Hello, \(name)" }
可选绑定的简写用法:
1 2 3 4 5
let nickname: String? =nil iflet nickname { // 省略了赋值:if let x = nickName print("Hey, \(nickname)") // 使用同名变量代替拆包后的值 } // Doesn't print anything, because nickname is nil.
2.switch
case中支持任何数据类型。
1 2 3 4 5 6 7 8 9 10
let someCharacter: Character="z" switch someCharacter { case"a": print("The first letter of the Latin alphabet") case"z": print("The last letter of the Latin alphabet") default: print("Some other character") } // Prints "The last letter of the Latin alphabet"
let anotherCharacter: Character="a" switch anotherCharacter { case"a", "A": // 写在同一行,逗号隔开 print("The letter A") default: print("Not the letter A") } // Prints "The letter A"
变量赋值
1 2 3 4 5 6 7 8 9 10 11
let aCharacter: Character="a" let message =switch aCharacter { case"a": "The first letter of the Latin alphabet" case"z": "The last letter of the Latin alphabet" default: "Some other character" } print(message) // Prints "The first letter of the Latin alphabet"
间隔匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
let approximateCount =62 let countedThings ="moons orbiting Saturn" let naturalCount: String switch approximateCount { case0: naturalCount ="no" case1..<5: naturalCount ="a few" case5..<12: naturalCount ="several" case12..<100: naturalCount ="dozens of" case100..<1000: naturalCount ="hundreds of" default: naturalCount ="many" } print("There are \(naturalCount)\(countedThings).") // Prints "There are dozens of moons orbiting Saturn."
支持where语句:
1 2 3 4 5 6 7 8 9 10 11 12
let vegetable ="red pepper" switch vegetable { case"celery": print("Add some raisins and make ants on a log.") case"cucumber", "watercress": print("That would make a good tea sandwich.") caselet x where x.hasSuffix("pepper"): print("Is it a spicy \(x)?") default: print("Everything tastes good in soup.") } // Prints "Is it a spicy red pepper?"
3.for
for-in遍历集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], "Square": [1, 4, 9, 16, 25], ] var largest =0 for (_, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number } } } print(largest) // Prints "25"
支持..<右不包含、...左右都包含的区间遍历:
1 2 3 4 5 6
var total =0 for i in0..<4 { total += i } print(total) // Prints "6"
4.while
1.一般用法:
1 2 3 4 5 6
var n =2 while n <100 { n *=2 } print(n) // Prints "128"
2.repeat用法:
1 2 3 4 5 6
var m =2 repeat { m *=2 } while m <100 print(m) // Prints "128"
funcgreet(_person: String, onday: String) -> String { return"Hello \(person), today is \(day)." } greet("John", on: "Wednesday")
_、on即为外部参数名,其中_表示外部参数名可省略,调用时无需书写。
3.inout参数
在函数中定义的参数默认都是常量参数,函数体内不可以修改它的值;
如果想声明一个变量参数,可以在参数定义前加上inout关键字:
1 2 3 4 5 6 7 8 9 10
funcswapTwoInts(_a: inoutInt, _b: inoutInt) { let temporaryA = a a = b b = temporaryA } var someInt =3 var anotherInt =107 swapTwoInts(&someInt, &anotherInt) print("someInt is now \(someInt), and anotherInt is now \(anotherInt)") // Prints "someInt is now 107, and anotherInt is now 3"
4.参数默认值
1 2 3 4 5 6
funcsomeFunction(a: Int, b: Int=12) { // If you omit the second argument when calling this function, then // the value of b is 12 inside the function body. } someFunction(a: 3, b: 6) // b is 6 someFunction(a: 4) // b is 12
finalclassA { var aInt: Int{ get{ return1 } } funccallFunction() { print("A") } } classB:A { // 报错“Inheritance from a final class 'A'” overridevar aInt: Int { // 报错“Property overrides a 'final' property” get { return2 } } overridefunccallFunction() { //报错“Instance method overrides a 'final' instance method” print("B") } }
final修饰类的属性、方法时只是将其标记为不能重写,并不会将其变成类属性或类方法。
2.static
修饰类中元素,强调属于类、不可重写。
static 可以修饰类中的元素,但不能修饰类本身;
static 可以修饰结构体中的元素,但不能修饰结构体本身;
static 不能修饰枚举及其元素;
static 可以修饰计算属性或存储属性,并保存在类的内存中(而非实例中);
static 修饰的属性或方法,不能重写,可通过类型名来调用;
#示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classA { staticvar aInt: Int=1 staticfunccallFunction() { print("A.aInt:\(aInt)") } } classB:A { var aInt: Int=2// 属性前不能加override 否则会报错“Property does not override any property from its superclass”
funccallFunction() { // 方法前不能加override 否则会报错“Method does not override any method from its superclass” print("B.aInt:\(aInt)") } } A.aInt // 1 B.aInt // 1 A.callFunction() // A.aInt:1 let b =B() b.aInt // 2 b.callFunction() // 打印 B.aInt:2
classA { classvaraInt: Int { get { return1 } set { } } classfunccallFunction() { print("A") } } classB:A { overrideclassvaraInt: Int { get { return2 } set { } } overrideclassfunccallFunction() { print("B") } } A.aInt // 打印:1 B.aInt // 打印:2 let b =B() B.callFunction() // 打印:B
12.Equal
Note that identical to (represented by three equals signs, or ===) doesn’t 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 structures and classes, it’s your responsibility to decide what qualifies as two instances being equal.
五种访问修饰符,按从高到低排序是:open > public > interal > fileprivate > private。
open:可以被任何模块的代码访问,可以被继承和重写。
public: 可以被任何模块的代码访问,模块外不可继承和重写。
internal:默认访问级别,源代码所在的整个模块都可以访问。
fileprivate:只能在当前文件中访问,当前类的扩展中也可以。
private:只能在当前类与其扩展中访问,子类中无法访问。
14.API可用性
#available+if:
1 2 3 4 5
if#available(iOS10, macOS10.12, *) { // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS } else { // Fall back to earlier iOS and macOS APIs }
#available+guard:
1 2 3 4 5 6 7 8 9 10 11 12
@available(macOS10.12, *) structColorPreference { var bestColor ="blue" }
extensionInt { var add: Int { returnself+1 } var sub: Int { returnself-1 } var mul: Int { returnself*1 } var div: Int { returnself/1 } } let addition =1.add print("加法运算:\(addition)")
protocolCalculator { var add: Int { get } var sub: Int { get } var mul: Int { get } var div: Int { get }
} extensionInt: Calculator { var add: Int { returnself+100 } var sub: Int { returnself-10 } var mul: Int { returnself*10 } var div: Int { returnself/5 } } let addition =3.add print("加法运算后的值:\(addition)")
protocolSomeProtocol { var mustBeSettable: Int { getset } // 可读可写 var doesNotNeedToBeSettable: Int { get } // 只读 staticvar someTypeProperty: Int { getset } // 类型属性 }
protocolCalculator { var add: Int { get } var sub: Int { get } var mul: Int { get } var div: Int { get }
} extensionInt: Calculator { var add: Int { returnself+100 } var sub: Int { returnself-10 } var mul: Int { returnself*10 } var div: Int { returnself/5 } } let addition =3.add print("加法运算后的值:\(addition)")
guardlet location = person["location"] else { print("I hope the weather is nice near you.") return }
print("I hope the weather is nice in \(location).") }
greet(person: ["name": "John"]) // Prints "Hello John!" // Prints "I hope the weather is nice near you." greet(person: ["name": "Jane", "location": "Cupertino"]) // Prints "Hello Jane!" // Prints "I hope the weather is nice in Cupertino."
funcswapTwoValues<T>(_a: inoutT, _b: inoutT) { let temporaryA = a a = b b = temporaryA } var someInt =3 var anotherInt =107 swapTwoValues(&someInt, &anotherInt) // someInt is now 107, and anotherInt is now 3
var someString ="hello" var anotherString ="world" swapTwoValues(&someString, &anotherString) // someString is now "world", and anotherString is now "hello"
用在自定义的类型中:
1 2 3 4 5 6 7 8 9 10 11 12 13
structStack<Element> { var items: [Element] = [] mutatingfuncpush(_item: Element) { items.append(item) } mutatingfuncpop() -> Element { return items.removeLast() } } // 使用 var aStack =Stack<String>() // 指定具体类型 aStack.push("uno") let fromTheTop = aStack.pop()
funcfindIndex<T: Equatable>(ofvalueToFind: T, inarray:[T]) -> Int? { for (index, value) in array.enumerated() { if value == valueToFind { return index } } returnnil } let doubleIndex = findIndex(of: 9.3, in: [3.14159, 0.1, 0.25]) // doubleIndex is an optional Int with no value, because 9.3 isn't in the array let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"]) // stringIndex is an optional Int containing a value of 2