• Swift基础


    本文是个比较简单的学习笔记,更详细的内容见 Swift官方文档

    1、相等性比较

    Swift标准库用 < 和 == 运算符定义了 >、>=、<=,所以实现 Comparable 的 < 运算符就会自动得到这些运算符的实现,实际上 Comparable 继承自 Equatable,所以 == 运算也是必须实现的,以下是示例代码

    1. struct Point: Comparable, CustomStringConvertible {
    2. let x: Int
    3. let y: Int
    4. var description: String {
    5. return "Point(\(x), \(y))"
    6. }
    7. static func ==(lhs: Point, rhs: Point) -> Bool {
    8. return lhs.x == rhs.x && lhs.y == rhs.y
    9. }
    10. static func <(lhs: Point, rhs: Point) -> Bool {
    11. return lhs.x < rhs.x && lhs.y < rhs.y
    12. }
    13. static func + (left: Point, right: Point) -> Point {
    14. return Point(x: left.x + right.x, y: left.y + right.y)
    15. }
    16. }
    17. let a = Point(x: 3, y: 4)
    18. let b = Point(x: 3, y: 4)
    19. let abEqual = (a == b)
    20. a != b
    21. let c = Point(x: 2, y: 6)
    22. let d = Point(x: 3, y: 7)
    23. c == d
    24. c < d
    25. c <= d
    26. c > d
    27. c >= d
    28. c + d
    29. class Person: Equatable {
    30. let name: String
    31. let age: Int
    32. weak var brother: Person?
    33. init(name: String, age: Int) {
    34. self.name = name
    35. self.age = age
    36. }
    37. static func ==(lhs: Person, rhs: Person) -> Bool {
    38. return lhs.name == rhs.name
    39. }
    40. }
    41. let p1 = Person(name: "JJF", age: 33)
    42. let p2 = Person(name: "JZF", age: 36)
    43. var people = [p1, p2]
    44. if let p1Index = people.firstIndex(where: { $0 == p2 }) {
    45. print(p1Index)
    46. }
    47. //自定义运算符
    48. infix operator +++
    49. func +++(lhs: Person, rhs: Person) {
    50. lhs.brother = rhs
    51. rhs.brother = lhs
    52. }
    53. p1 +++ p2
    54. p1.brother?.name
    55. p2.brother?.name

    2、日期和时间

    1. import Foundation
    2. let date = Date.now
    3. let dateFormatter = DateFormatter()
    4. //dateFormatter.locale = Locale(identifier: "zh_CN")
    5. dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
    6. // typealias TimeInterval = Double
    7. // A number of seconds.
    8. // TimeInterval 是 Double 类型,单位是秒,可精确到微秒
    9. //时间戳,1970到现在的毫秒数
    10. let timestamp = Int(date.timeIntervalSince1970 * 1000)
    11. print("timestamp = \(timestamp)")
    12. //取当前时间的年/月/日/时/分/秒/毫秒
    13. var calendar = Calendar.current
    14. let year = calendar.component(.year, from: date)
    15. let month = calendar.component(.month, from: date)
    16. let day = calendar.component(.day, from: date)
    17. let hour = calendar.component(.hour, from: date)
    18. let minute = calendar.component(.minute, from: date)
    19. let second = calendar.component(.second, from: date)
    20. let milliSecond = calendar.component(.nanosecond, from: date) / 1000_000
    21. print("\(year)-\(String(format: "%02D", month))-\(String(format: "%02D", day)) \(String(format: "%02D", hour)):\(String(format: "%02D", minute)):\(String(format: "%02D", second)).\(String(format: "%03D", milliSecond))")
    22. //使用 DateFormatter 格式化时间
    23. print("\(dateFormatter.string(from: date))")
    24. let str = "Hello World!"
    25. let start = str.index(str.startIndex, offsetBy: 6)
    26. let end = str.index(str.startIndex, offsetBy: 11)
    27. let substr = String(str[start..<end])
    28. print(substr)

    3、处理异常 

    1. enum Token {
    2. case number(Int)
    3. case plus
    4. }
    5. class Lexer {
    6. enum Error: Swift.Error {
    7. case invalidCharacter(Character)
    8. }
    9. let input: String
    10. var position: String.Index
    11. init(input: String) {
    12. self.input = input
    13. self.position = self.input.startIndex
    14. }
    15. func peek() -> Character? {
    16. guard position < input.endIndex else {
    17. return nil
    18. }
    19. return input[position]
    20. }
    21. func advance() {
    22. //断言只在调试模式下生效,发布模式下可使用 precondition(_:_:) 替代
    23. assert(position < input.endIndex, "Cannot advance past endIndex!")
    24. position = input.index(after: position)
    25. }
    26. func lex() throws -> [Token] {
    27. var tokens = [Token]()
    28. while let nextCharacter = peek() {
    29. switch nextCharacter {
    30. case "0"..."9":
    31. tokens.append(.number(getNumber()))
    32. case "+":
    33. tokens.append(.plus)
    34. advance()
    35. case " ":
    36. advance()
    37. default:
    38. throw Lexer.Error.invalidCharacter(nextCharacter)
    39. }
    40. }
    41. return tokens
    42. }
    43. func getNumber() -> Int {
    44. var value = 0
    45. while let nextCharacter = peek() {
    46. switch nextCharacter {
    47. case "0"..."9":
    48. let digitValue = Int(String(nextCharacter))!
    49. value = 10 * value + digitValue
    50. advance()
    51. default:
    52. return value
    53. }
    54. }
    55. return value
    56. }
    57. }
    58. class Parser {
    59. enum Error: Swift.Error {
    60. case unexpectedEndOfInput
    61. case invalidToken(Token)
    62. }
    63. let tokens: [Token]
    64. var position = 0
    65. init(tokens: [Token]) {
    66. self.tokens = tokens
    67. }
    68. func nextToken() -> Token? {
    69. guard position < tokens.count else {
    70. return nil
    71. }
    72. let token = tokens[position]
    73. position += 1
    74. return token
    75. }
    76. func getNumber() throws -> Int {
    77. guard let token = nextToken() else {
    78. throw Parser.Error.unexpectedEndOfInput
    79. }
    80. switch token {
    81. case .number(let value):
    82. return value
    83. case .plus:
    84. throw Parser.Error.invalidToken(token)
    85. }
    86. }
    87. func parse() throws -> Int {
    88. var value = try getNumber()
    89. while let token = nextToken() {
    90. switch token {
    91. case .plus:
    92. let nextNumber = try getNumber()
    93. value += nextNumber
    94. case .number:
    95. throw Parser.Error.invalidToken(token)
    96. }
    97. }
    98. return value
    99. }
    100. }
    101. func evaluate(_ input: String) {
    102. print("Evaluating: \(input)")
    103. let lexer = Lexer(input: input)
    104. // let tokens = try! lexer.lex()//强制执行可能抛出错误的方法,发生错误时触发陷阱
    105. // guard let tokens = try? lexer.lex() else {
    106. // print("Lexing failed, but I don't know why")
    107. // return
    108. // }
    109. do {
    110. let tokens = try lexer.lex()
    111. print("Lexer ouput: \(tokens)")
    112. let parser = Parser(tokens: tokens)
    113. let value = try parser.parse()
    114. print(value)
    115. } catch Lexer.Error.invalidCharacter(let character) {
    116. print("Input contained an invalid character: \(character)")
    117. } catch Parser.Error.unexpectedEndOfInput {
    118. print("Unexpected end of input during parsing")
    119. } catch Parser.Error.invalidToken(let token) {
    120. print("Invalid token during parsing: \(token)")
    121. } catch {
    122. print("An error occurred: \(error)")
    123. }
    124. }
    125. evaluate("10 + 3 + 5 +")

    4、扩展

    (1)扩展类/结构体

    1. typealias Velocity = Double
    2. extension Velocity {
    3. var kph: Velocity { return self * 1.60934 }
    4. var mph: Velocity { return self }
    5. }
    6. protocol Vehicle {
    7. var topSpeed: Velocity { get }
    8. var numberOfDoors: Int { get }
    9. var hasFlatbed: Bool { get }
    10. }
    11. struct Car {
    12. let make: String
    13. let model: String
    14. let year: Int
    15. let color: String
    16. let nickname: String
    17. var gasLevel: Double {
    18. willSet {
    19. precondition(newValue <= 1.0 && newValue >= 0.0, "New value must between 0 and 1.")
    20. }
    21. }
    22. }
    23. //利用拓展使 Car 实现协议
    24. extension Car: Vehicle {
    25. var topSpeed: Velocity { return 180 }
    26. var numberOfDoors: Int { return 4 }
    27. var hasFlatbed: Bool { return false }
    28. }
    29. //利用拓展给 Car 增加初始化方法,这样会保留默认的成员初始化方法
    30. extension Car {
    31. init(make: String, model: String, year: Int) {
    32. self.init(make: make, model: model, year: year, color: "Black", nickname: "N/A", gasLevel: 1.0)
    33. }
    34. }
    35. var c = Car(make: "Ford", model: "Fusion", year: 2013)
    36. extension Car {
    37. enum Kind {
    38. case coupe, sedan
    39. }
    40. var kind: Kind {
    41. if numberOfDoors == 2 {
    42. return .coupe
    43. } else {
    44. return .sedan
    45. }
    46. }
    47. }
    48. c.kind
    49. extension Car {
    50. mutating func emptyGas(by amount: Double) {
    51. precondition(amount <= 1 && amount > 0, "Amount to remove must be between 0 and 1.")
    52. gasLevel -= amount
    53. }
    54. mutating func fillGas() {
    55. gasLevel = 1.0
    56. }
    57. }
    58. c.emptyGas(by: 0.3)
    59. c.gasLevel
    60. c.fillGas()
    61. c.gasLevel

    (2)扩展协议

    1. protocol Exercise: CustomStringConvertible {
    2. var name: String { get }
    3. var caloriesBurned: Double { get } //消耗的卡路里
    4. var minutes: Double { get }//锻炼的时长
    5. }
    6. extension Exercise {
    7. var description: String {
    8. return "Exercise(\(name), burned \(caloriesBurned) calories in \(minutes) minutes)"
    9. }
    10. }
    11. extension Exercise {
    12. var title: String {
    13. return "\(name) - \(minutes) minutes"
    14. }
    15. }
    16. struct EllipticalWorkout: Exercise {
    17. let name: String = "Elliptical Workout"
    18. let title: String = "Workout using the Go Fast Elliptical Trainer 3000"
    19. let caloriesBurned: Double
    20. let minutes: Double
    21. }
    22. struct TreadmillWorkout: Exercise {
    23. let name: String = "Treadmill Workout"
    24. let caloriesBurned: Double
    25. let minutes: Double
    26. let laps: Double //跑步的圈数
    27. }
    28. extension TreadmillWorkout {
    29. var description: String {
    30. return "TreadmillWorkout(\(caloriesBurned) calories and \(laps) laps in \(minutes) minutes)"
    31. }
    32. }
    33. let ellipticalWorkout = EllipticalWorkout(caloriesBurned: 335, minutes: 30)
    34. let runningWorkout = TreadmillWorkout(caloriesBurned: 350, minutes: 25, laps: 10.5)
    35. //使用范型定义函数:计算每分钟消耗的卡路里
    36. func caloriesBurnedPerMinute<E: Exercise>(for exercise: E) -> Double {
    37. return exercise.caloriesBurned / exercise.minutes
    38. }
    39. print(caloriesBurnedPerMinute(for: ellipticalWorkout))
    40. print(caloriesBurnedPerMinute(for: runningWorkout))
    41. //拓展协议
    42. extension Exercise {
    43. //所有实现该协议的类型都可以使用通过拓展为该协议添加的属性和方法
    44. var caloriesBurnedPerMinute: Double {
    45. return caloriesBurned / minutes
    46. }
    47. }
    48. print(ellipticalWorkout.caloriesBurnedPerMinute)
    49. print(runningWorkout.caloriesBurnedPerMinute)
    50. print(ellipticalWorkout)
    51. print(runningWorkout)
    52. //带 where 子句的协议拓展
    53. extension Sequence where Iterator.Element == Exercise {
    54. func totalCaloriesBurned() -> Double {
    55. var total: Double = 0
    56. for exercise in self {
    57. total += exercise.caloriesBurned
    58. }
    59. return total
    60. }
    61. }
    62. let mondayWorkout: [Exercise] = [ellipticalWorkout, runningWorkout]
    63. print(mondayWorkout.totalCaloriesBurned())
    64. for exercise in mondayWorkout {
    65. print(exercise.title)
    66. }
    67. print(ellipticalWorkout.title)

    5、范型

    1. struct StackIterator<T>: IteratorProtocol {
    2. // typealias Element = T
    3. var stack: Stack<T>
    4. mutating func next() -> T? {
    5. return stack.pop()
    6. }
    7. }
    8. // Sequence 是实现 for-in 循环在内部使用的协议
    9. struct Stack<E>: Sequence {
    10. var items = [E]()
    11. // 使用 where 子句约束 Sequence 的元素类型
    12. mutating func pushAll<S: Sequence>(_ sequence: S) where S.Iterator.Element == E {
    13. for item in sequence {
    14. self.push(item)
    15. }
    16. }
    17. mutating func push(_ newItem: E) {
    18. items.append(newItem)
    19. }
    20. mutating func pop() -> E? {
    21. guard !items.isEmpty else {
    22. return nil
    23. }
    24. return items.removeLast()
    25. }
    26. func map<U>(_ f: (E) -> U) -> Stack<U> {
    27. var mappedItems = [U]()
    28. for item in items {
    29. mappedItems.append(f(item))
    30. }
    31. return Stack<U>(items: mappedItems)
    32. }
    33. func makeIterator() -> StackIterator<E> {
    34. return StackIterator(stack: self)
    35. }
    36. }
    37. var intStack = Stack<Int>()
    38. intStack.push(1)
    39. intStack.push(2)
    40. var doubledStack = intStack.map { 2 * $0 }
    41. print(intStack.pop())
    42. print(intStack.pop())
    43. print(intStack.pop())
    44. print(doubledStack.pop())
    45. print(doubledStack.pop())
    46. func myMap<T, U>(_ items: [T], _ f: (T) -> U) -> [U] {
    47. var result = [U]()
    48. for item in items {
    49. result.append(f(item))
    50. }
    51. return result
    52. }
    53. let strings = ["one", "two", "three"]
    54. //let stringLengths = myMap(strings, {(str: String) -> Int in
    55. // return str.count
    56. //})
    57. let stringLengths = myMap(strings) { $0.count }
    58. print(stringLengths)
    59. //类型约束
    60. func checkIfEqual<T: Equatable>(_ first: T, _ second: T) -> Bool {
    61. return first == second
    62. }
    63. print(checkIfEqual(1, 1))
    64. print(checkIfEqual("a string", "a string"))
    65. print(checkIfEqual("a string", "a different string"))
    66. //每个占位类型都可以有一个类型约束
    67. func checkIfDescriptionsMatch<T: CustomStringConvertible, U: CustomStringConvertible>(_ first: T, _ second: U) -> Bool {
    68. return first.description == second.description
    69. }
    70. print(checkIfDescriptionsMatch(Int(1), UInt(1)))
    71. print(checkIfDescriptionsMatch(1, 1.0))
    72. print(checkIfDescriptionsMatch(Float(1.0), Double(1.0)))
    73. var myStack = Stack<Int>()
    74. myStack.push(10)
    75. myStack.push(20)
    76. myStack.push(30)
    77. var myStackIterator = StackIterator(stack: myStack)
    78. while let value = myStackIterator.next() {
    79. print("got \(value)")
    80. }
    81. for value in myStack {
    82. print("for-in loop: got \(value)")
    83. }
    84. myStack.pushAll([1, 2, 3])
    85. for value in myStack {
    86. print("after pushing: got \(value)")
    87. }
    88. var myOtherStack = Stack<Int>()
    89. myOtherStack.pushAll([1, 2, 3])
    90. myStack.pushAll(myOtherStack)
    91. for value in myStack {
    92. print("after pushing item onto stack, got \(value)")
    93. }

    6、协议

    1. protocol TabularDataSource {
    2. var numberOfRows: Int { get }
    3. var numberOfColumns: Int { get }
    4. func label(forColumn column: Int) -> String
    5. func itemFor(row: Int, column: Int) -> String
    6. }
    7. protocol PrintableTabularDataSource: TabularDataSource, CustomStringConvertible {
    8. //
    9. }
    10. //组合协议,让 printTable 的参数符合 CustomStringConvertible 协议
    11. func printTable(_ dataSource: TabularDataSource & CustomStringConvertible) {
    12. print(dataSource)
    13. var firstRow = "|"
    14. var columnWidths = [Int]()
    15. for i in 0..<dataSource.numberOfColumns {
    16. let columnLabel = dataSource.label(forColumn: i)
    17. let columnHeader = " \(columnLabel) |"
    18. firstRow += columnHeader
    19. columnWidths.append(columnLabel.count)
    20. }
    21. print(firstRow)
    22. for i in 0..<dataSource.numberOfRows {
    23. var out = "|"
    24. for j in 0..<dataSource.numberOfColumns {
    25. let item = dataSource.itemFor(row: i, column: j)
    26. let paddingNeeded = columnWidths[j] - item.count
    27. let padding = repeatElement(" ", count: paddingNeeded).joined(separator: "")
    28. out += " \(padding)\(item) |"
    29. }
    30. print(out)
    31. }
    32. }
    33. struct Person {
    34. let name: String
    35. let age: Int
    36. let yearsOfExperience: Int
    37. }
    38. struct Department: TabularDataSource, CustomStringConvertible {
    39. let name: String
    40. var people = [Person]()
    41. var description: String {
    42. return "Department (\(name))"
    43. }
    44. init(name: String) {
    45. self.name = name
    46. }
    47. mutating func add(_ person: Person) {
    48. people.append(person)
    49. }
    50. var numberOfRows: Int {
    51. return people.count
    52. }
    53. var numberOfColumns: Int {
    54. return 3
    55. }
    56. func label(forColumn column: Int) -> String {
    57. switch column {
    58. case 0: return "Employee Name"
    59. case 1: return "Age"
    60. case 2: return "Years of Experience"
    61. default: fatalError("Invalid column!")
    62. }
    63. }
    64. func itemFor(row: Int, column: Int) -> String {
    65. let person = people[row]
    66. switch column {
    67. case 0: return person.name
    68. case 1: return String(person.age)
    69. case 2: return String(person.yearsOfExperience)
    70. default: fatalError("Invalid column!")
    71. }
    72. }
    73. }
    74. var department = Department(name: "Engineering")
    75. department.add(Person(name: "Joe", age: 30, yearsOfExperience: 6))
    76. department.add(Person(name: "Karen", age: 40, yearsOfExperience: 18))
    77. department.add(Person(name: "Fred", age: 50, yearsOfExperience: 20))
    78. printTable(department)

    7、字符串

    1. import Cocoa
    2. extension String {
    3. /// 截取字符串
    4. /// - Parameter start: 起始索引(包含)
    5. /// - Parameter end: 结束索引(不包含)
    6. func substring(start: Int, end: Int) -> String {
    7. let firstIndex = index(startIndex, offsetBy: start)
    8. let lastIndex = index(startIndex, offsetBy: end)
    9. return String(self[firstIndex..<lastIndex])
    10. }
    11. /// 16进制字符串(可以有空格)转换成二进制数据
    12. func toData() -> Data {
    13. let hex = self.replacingOccurrences(of: " ", with: "")
    14. var arr = Array<UInt8>()
    15. for i in 0..<hex.count where i % 2 == 0 {
    16. let byteStr = hex.substring(start: i, end: i + 2)
    17. // print("byteStr = \(byteStr)")
    18. arr.append(UInt8(byteStr, radix: 16) ?? 0)
    19. }
    20. return Data(arr)
    21. }
    22. }
    23. extension Data {
    24. /// 按照 ASCII 转换成字符串
    25. func toAscii() -> String {
    26. return subdata2ascii(start: 0, end: self.count)
    27. }
    28. /// 转换成16进制字符串
    29. /// - Parameter withSpace: 可选参数,默认true,输出的字符串是否每两个字节之间放一个空格
    30. func toHex(withSpace: Bool = true) -> String {
    31. return subdata2hex(start: 0, end: self.count, withSpace: withSpace)
    32. }
    33. /// 将指定范围的数据转换成ASCII字符串
    34. /// - Parameter start: 起始索引(包含)
    35. /// - Parameter end: 结束索引(不包含)
    36. func subdata2ascii(start: Int, end: Int) -> String {
    37. if let str = String(data: self[start..<end], encoding: .ascii) {
    38. return str
    39. }
    40. return ""
    41. }
    42. /// 将指定范围的数据转换成16进制字符串
    43. /// - Parameter start: 起始索引(包含)
    44. /// - Parameter end: 结束索引(不包含)
    45. /// - Parameter withSpace: 可选参数,默认true,输出的字符串是否每两个字节之间放一个空格
    46. func subdata2hex(start: Int, end: Int, withSpace: Bool = true) -> String {
    47. let arr = Array<UInt8>(self[start..<end])
    48. let hex = arr.map({ byte -> String in
    49. return String(format: "%02X", byte)
    50. }).joined(separator: withSpace ? " " : "")
    51. return hex
    52. }
    53. }
    54. func test() {
    55. let hexString = "5A 58 48 0C 83 0E 47 07 22 2B 42 41 30 34 56 30 35"
    56. let data = hexString.toData()
    57. print("head = \(data.subdata2ascii(start: 0, end: 3))")
    58. print("mac = \(data.subdata2hex(start: 3, end: 9))")
    59. print("DeviceType = \(data.subdata2ascii(start: 9, end: 14))")
    60. print("version = \(data.subdata2ascii(start: 14, end: data.count))")
    61. print(data.toHex(withSpace: true))
    62. }
    63. test()
    64. let apples = 3
    65. let oranges = 5
    66. //只要与结束引号(""")的缩进匹配,就会删除每一行开始处的缩进
    67. let quotation = """
    68. Even though there's whitespace to the left,
    69. the actual lines aren't indented.
    70. Except for this line.
    71. Double quotes (") can appear without being escaped.
    72. I still have \(apples + oranges) pieces of fruit.
    73. """
    74. print(quotation)

    8、类和结构体

    1. /** struct 类似 Kotlin 的 data class,等价写法是:
    2. data class Person(var firstName: String = "Matt", var lastName: String = "Mathias")
    3. */
    4. struct Person {
    5. var firstName = "Matt"
    6. var lastName = "Mathias"
    7. }
    8. var p = Person(firstName: "Jia", lastName: "Jiefei")
    9. print(p)
    10. //如果属性没有提供默认值,结构体会根据属性生成默认的成员初始化方法,并且直接打印结构体可以看到所有存储属性的值
    11. struct Device {
    12. var name: String
    13. var address: String
    14. // text 是计算属性,打印时不会输出
    15. var text: String {
    16. return "name=\(name), address=\(address)"
    17. }
    18. }
    19. print(Device(name: "Device", address: "11:22:33:44:55:66"))
    20. //而类就没有默认成员初始化方法了,需要自己编写初始化方法,并且直接打印类实例,不会输出各存储属性的值
    21. class BleDevice {
    22. var name: String
    23. var address: String
    24. required init(name: String, address: String) {
    25. self.name = name
    26. self.address = address
    27. }
    28. }
    29. print(BleDevice(name: "BleDevice", address: "AA:BB:CC:DD:EE:FF"))

    9、值类型和引用类型

    1. //类是引用类型
    2. class GreekGod {
    3. var name: String
    4. init(name: String) {
    5. self.name = name
    6. }
    7. }
    8. let hecate = GreekGod(name: "Hecate")
    9. let athena = GreekGod(name: "Athena")
    10. let zeus = GreekGod(name: "Zeus")
    11. let anotherHecate = hecate
    12. anotherHecate.name = "AnotherHecate"
    13. hecate.name //类是引用类型,改变 anotherHecate.name,hecate.name也会变
    14. //结构体是值类型
    15. struct Pantheon {
    16. var chiefGod: GreekGod
    17. }
    18. let pantheon = Pantheon(chiefGod: hecate)
    19. pantheon.chiefGod.name // AnotherHecate
    20. let greekPantheon = pantheon
    21. hecate.name = "Trivia"
    22. greekPantheon.chiefGod.name // Trivia
    23. let gods = [athena, hecate, zeus]
    24. let godsCopy = gods
    25. gods.last?.name = "Jupiter"
    26. godsCopy.last?.name // Jupiter
    27. //探究写时复制(copy on write, COW)
    28. fileprivate class IntArrayBuffer {
    29. var storage: [Int]
    30. init() {
    31. storage = []
    32. }
    33. init(buffer: IntArrayBuffer) {
    34. storage = buffer.storage
    35. }
    36. }
    37. struct IntArray {
    38. private var buffer: IntArrayBuffer
    39. init() {
    40. buffer = IntArrayBuffer()
    41. }
    42. func describe() {
    43. let str = buffer.storage.map { i in
    44. String(i)
    45. }.joined(separator: ", ")
    46. print("[\(str)]")
    47. // print(buffer.storage)
    48. }
    49. private mutating func copyIfNeeded() {
    50. //判断引用类型是否只有一个引用
    51. if !isKnownUniquelyReferenced(&buffer) {
    52. print("Making a copy of \(buffer.storage)")
    53. buffer = IntArrayBuffer(buffer: buffer)
    54. }
    55. }
    56. mutating func insert(_ value: Int, at index: Int) {
    57. copyIfNeeded()
    58. buffer.storage.insert(value, at: index)
    59. }
    60. mutating func append(_ value: Int) {
    61. copyIfNeeded()
    62. buffer.storage.append(value)
    63. }
    64. mutating func remove(at index: Int) {
    65. copyIfNeeded()
    66. buffer.storage.remove(at: index)
    67. }
    68. }
    69. var integers = IntArray()
    70. integers.append(1)
    71. integers.append(2)
    72. integers.append(4)
    73. integers.describe()
    74. var ints = integers
    75. ints.insert(3, at: 2)
    76. integers.describe()
    77. ints.describe()

    10、继承

    虽然是讲继承,但代码中的注释也会涉及其他知识点!例子涉及3个.swift文件

    Town.swift

    1. struct Town {
    2. let region: String
    3. var population: Int {
    4. didSet {
    5. print("The population has changed to \(population) from \(oldValue)")
    6. }
    7. }
    8. var numberOfStoplights: Int
    9. //自定义初始化方法,问号表示可失败的初始化方法
    10. init?(region: String, population: Int, stoplights: Int) {
    11. guard population > 0 else {
    12. return nil
    13. }
    14. self.region = region
    15. self.population = population
    16. numberOfStoplights = stoplights
    17. }
    18. //委托初始化
    19. init?(population: Int, stoplights: Int) {
    20. self.init(region: "N/A", population: population, stoplights: stoplights)
    21. }
    22. enum Size {
    23. case small
    24. case medium
    25. case large
    26. }
    27. //计算属性
    28. var townSize: Size {
    29. get {
    30. print("town size")//每次调用都会打印
    31. switch self.population {
    32. case 0...10_000:
    33. return Size.small
    34. case 10_001...100_000:
    35. return Size.medium
    36. default:
    37. return Size.large
    38. }
    39. }
    40. }
    41. //惰性存储属性,注意这里的等号以及结尾的圆括号
    42. lazy var name: String = {
    43. print("town name")//这里只会打印一次,即第一次访问该属性时
    44. return "XiShe"
    45. }()
    46. func printDescription() {
    47. print("Population: \(population), number of stoplights: \(numberOfStoplights), region: \(region)")
    48. }
    49. /* 如果结构体(确切的说,应该是值类型,结构体和枚举都是值类型)的一个实例方法需要修改结构体的属性,就必须使用 mutating 标记该方法 */
    50. mutating func changePopulation(by amount: Int) {
    51. population += amount
    52. }
    53. /* 对于值类型,类型方法使用static标记 */
    54. static func xxx() {
    55. }
    56. }

    Monster.swift

    1. class Monster {
    2. // static 属性无法被子类覆盖
    3. static let isTerrifying = true
    4. // class 属性可被子类覆盖
    5. class var spookyNoise: String {
    6. return "Grrr"
    7. }
    8. var town: Town?
    9. var name: String
    10. var victimPool: Int {
    11. get {
    12. return town?.population ?? 0
    13. }
    14. set {
    15. town?.population = newValue
    16. }
    17. }
    18. //子类必须得实现的初始化方法
    19. required init(town: Town?, monsterName: String) {
    20. self.town = town
    21. name = monsterName
    22. }
    23. func terrorizeTown() {
    24. if town != nil {
    25. print("\(name) is terrorizing a town!")
    26. } else {
    27. print("\(name) hasn't found a town to terrorize yet...")
    28. }
    29. }
    30. /* 对于类,类型方法使用class或者static标记,区别在于static标记的方法无法被子类重写,也可以使用final class代替static */
    31. static func makeSpookyNoise() {
    32. print("Brains...")
    33. }
    34. }

    Zombie.swift

    1. class Zombie: Monster {
    2. override class var spookyNoise: String {
    3. return "Brains..."
    4. }
    5. var walkWithLimp: Bool
    6. //只将 set 属性设置为私有,get 属性为默认的 internal
    7. private(set) var isFallingApart: Bool
    8. //指定初始化方法
    9. init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) {
    10. walkWithLimp = limp
    11. isFallingApart = fallingApart
    12. //如果有父类,子类的指定初始化方法必须调用父类的指定初始化方法
    13. super.init(town: town, monsterName: monsterName)
    14. }
    15. //便捷初始化方法,必须调用指定初始化方法或者其他便捷初始化方法,但最终都要调用指定初始化方法,以确保所有属性都进行了初始化
    16. convenience init(limp: Bool, fallingApart: Bool) {
    17. self.init(limp: limp, fallingApart: fallingApart, town: nil, monsterName: "Fred")
    18. if walkWithLimp {
    19. print("This zombie has a bad knee.")
    20. }
    21. }
    22. required init(town: Town?, monsterName: String) {
    23. walkWithLimp = false
    24. isFallingApart = false
    25. super.init(town: town, monsterName: monsterName)
    26. }
    27. //实例被清除出内存时会触发反初始化
    28. deinit {
    29. print("Zombie named \(name) is no longer with use.")
    30. }
    31. //final 禁止子类重写该方法
    32. final override func terrorizeTown() {
    33. if !isFallingApart {
    34. town?.changePopulation(by: -10)
    35. }
    36. super.terrorizeTown()
    37. }
    38. }

     测试代码

    1. var town = Town(region: "West", population: 10, stoplights: 6)
    2. town?.printDescription()
    3. for _ in 0..<3 {
    4. if let townSize = town?.townSize, let townName = town?.name {
    5. print(townSize)
    6. print(townName)
    7. }
    8. town?.changePopulation(by: 1_000_000)
    9. }
    10. //let genericMonster = Monster()
    11. //genericMonster.town = town
    12. //genericMonster.terrorizeTown()
    13. var fredTheZombie: Zombie? = Zombie(limp: false, fallingApart: false, town: town, monsterName: "Fred")
    14. //fredTheZombie.terrorizeTown()
    15. //fredTheZombie.town?.printDescription()
    16. //Monster.makeSpookyNoise()
    17. print("Victim pool: \(fredTheZombie?.victimPool)")
    18. fredTheZombie?.victimPool = 500
    19. fredTheZombie = nil
    20. print(Monster.spookyNoise)
    21. print(Zombie.spookyNoise)

    11、数组和字典

    1. //初始化数组的3种方式,本人习惯上倾向使用第一种
    2. //使用 var 就是可变数组,let就是不可变数组
    3. var bucketList: Array<String> = []
    4. var bucketList2:[String] = ["haha"]
    5. var arr = [Int]()
    6. arr.append(1)
    7. arr.append(3)
    8. arr.append(2)
    9. //print("bucketList.count=\(bucketList.count) arr[0]=\(arr[0])")
    10. //数组排序
    11. let sortedArray = arr.sorted(by: {a, b in
    12. a < b
    13. })
    14. print(sortedArray)
    15. //注:只有Array 才有 joined 方法,如果元素类型不是 String,得先通过 map 方法转一次
    16. let joinedString = arr.map { i in
    17. String(i)
    18. }.joined(separator: ", ")
    19. print("[\(joinedString)]")
    20. //字典也有多种初始化方式,这里只列出其中一种
    21. //使用 var 就是可变字典,let就是不可变字典
    22. var dict: Dictionary<String, Int> = [:]
    23. dict["one"] = 1
    24. dict["two"] = 2
    25. dict["three"] = 3
    26. //遍历字典
    27. for (key, value) in dict {
    28. print("\(key) = \(value)")
    29. }
    30. dict.removeValue(forKey: "one")
    31. dict["two"] = nil //将值设置为nil来删除键值对
    32. print(dict)

  • 相关阅读:
    【C/C++】C语言获取键盘输入
    【21天python打卡】第14天 网络爬虫(5)
    C++特性——inline内联函数
    Vue双向绑定的原理
    前端Vue篇之Vuex中action和mutation的区别、Vuex 和 localStorage 的区别
    Java如何使用DOM4j解析XML呢?
    如何快速通过阿里云ACP 认证?
    高通量筛选——离子化合物
    基于昇腾AI 使用AscendCL实现垃圾分类和视频物体分类应用
    数据结构-归并排序与基数排序
  • 原文地址:https://blog.csdn.net/jjf19891208/article/details/133828462