Swift基础

这篇具有很好参考价值的文章主要介绍了Swift基础。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

1、相等性比较

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

struct Point: Comparable, CustomStringConvertible {
    let x: Int
    let y: Int
    
    var description: String {
        return "Point(\(x), \(y))"
    }
    
    
    static func ==(lhs: Point, rhs: Point) -> Bool {
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
    
    static func <(lhs: Point, rhs: Point) -> Bool {
        return lhs.x < rhs.x && lhs.y < rhs.y
    }
    
    static func + (left: Point, right: Point) -> Point {
        return Point(x: left.x + right.x, y: left.y + right.y)
    }
}

let a = Point(x: 3, y: 4)
let b = Point(x: 3, y: 4)
let abEqual = (a == b)
a != b

let c = Point(x: 2, y: 6)
let d = Point(x: 3, y: 7)
c == d
c < d
c <= d
c > d
c >= d

c + d


class Person: Equatable {
    let name: String
    let age: Int
    weak var brother: Person?
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
}

let p1 = Person(name: "JJF", age: 33)
let p2 = Person(name: "JZF", age: 36)
var people = [p1, p2]
if let p1Index = people.firstIndex(where: { $0 == p2 }) {
    print(p1Index)
}

//自定义运算符
infix operator +++

func +++(lhs: Person, rhs: Person) {
    lhs.brother = rhs
    rhs.brother = lhs
}
p1 +++ p2
p1.brother?.name
p2.brother?.name

2、日期和时间

import Foundation

let date = Date.now

let dateFormatter = DateFormatter()
//dateFormatter.locale = Locale(identifier: "zh_CN")
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"

// typealias TimeInterval = Double
// A number of seconds.
// TimeInterval 是 Double 类型,单位是秒,可精确到微秒
//时间戳,1970到现在的毫秒数
let timestamp = Int(date.timeIntervalSince1970 * 1000)
print("timestamp = \(timestamp)")

//取当前时间的年/月/日/时/分/秒/毫秒
var calendar = Calendar.current
let year = calendar.component(.year, from: date)
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
let milliSecond = calendar.component(.nanosecond, from: date) / 1000_000
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))")

//使用 DateFormatter 格式化时间
print("\(dateFormatter.string(from: date))")


let str = "Hello World!"
let start = str.index(str.startIndex, offsetBy: 6)
let end = str.index(str.startIndex, offsetBy: 11)
let substr = String(str[start..<end])
print(substr)

3、处理异常 

enum Token {
    case number(Int)
    case plus
}

class Lexer {
    enum Error: Swift.Error {
        case invalidCharacter(Character)
    }
    let input: String
    var position: String.Index
    
    init(input: String) {
        self.input = input
        self.position = self.input.startIndex
    }
    
    func peek() -> Character? {
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    
    func advance() {
        //断言只在调试模式下生效,发布模式下可使用 precondition(_:_:) 替代
        assert(position < input.endIndex, "Cannot advance past endIndex!")
        position = input.index(after: position)
    }
    
    func lex() throws -> [Token] {
        var tokens = [Token]()
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0"..."9":
                tokens.append(.number(getNumber()))
            case "+":
                tokens.append(.plus)
                advance()
            case " ":
                advance()
            default:
                throw Lexer.Error.invalidCharacter(nextCharacter)
            }
        }
        return tokens
    }
    
    func getNumber() -> Int {
        var value = 0
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0"..."9":
                let digitValue = Int(String(nextCharacter))!
                value = 10 * value + digitValue
                advance()
            default:
                return value
            }
        }
        return value
    }
}


class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(Token)
    }
    let tokens: [Token]
    var position = 0
    
    init(tokens: [Token]) {
        self.tokens = tokens
    }
    
    func nextToken() -> Token? {
        guard position < tokens.count else {
            return nil
        }
        let token = tokens[position]
        position += 1
        return token
    }
    
    func getNumber() throws -> Int {
        guard let token = nextToken() else {
            throw Parser.Error.unexpectedEndOfInput
        }
        switch token {
        case .number(let value):
            return value
        case .plus:
            throw Parser.Error.invalidToken(token)
        }
    }
    
    func parse() throws -> Int {
        var value = try getNumber()
        
        while let token = nextToken() {
            switch token {
            case .plus:
                let nextNumber = try getNumber()
                value += nextNumber
            case .number:
                throw Parser.Error.invalidToken(token)
            }
        }
        return value
    }
}

func evaluate(_ input: String) {
    print("Evaluating: \(input)")
    let lexer = Lexer(input: input)
//    let tokens = try! lexer.lex()//强制执行可能抛出错误的方法,发生错误时触发陷阱
//    guard let tokens = try? lexer.lex() else {
//        print("Lexing failed, but I don't know why")
//        return
//    }
    do {
        let tokens =  try lexer.lex()
        print("Lexer ouput: \(tokens)")
        let parser = Parser(tokens: tokens)
        let value = try parser.parse()
        print(value)
    } catch Lexer.Error.invalidCharacter(let character) {
        print("Input contained an invalid character: \(character)")
    } catch Parser.Error.unexpectedEndOfInput {
        print("Unexpected end of input during parsing")
    } catch Parser.Error.invalidToken(let token) {
        print("Invalid token during parsing: \(token)")
    } catch {
        print("An error occurred: \(error)")
    }
}
evaluate("10 + 3 + 5 +")

4、扩展

(1)扩展类/结构体

typealias Velocity = Double

extension Velocity {
    var kph: Velocity { return self * 1.60934 }
    var mph: Velocity { return self }
}

protocol Vehicle {
    var topSpeed: Velocity { get }
    var numberOfDoors: Int { get }
    var hasFlatbed: Bool { get }
}

struct Car {
    let make: String
    let model: String
    let year: Int
    let color: String
    let nickname: String
    var gasLevel: Double {
        willSet {
            precondition(newValue <= 1.0 && newValue >= 0.0, "New value must between 0 and 1.")
        }
    }
}

//利用拓展使 Car 实现协议
extension Car: Vehicle {
    var topSpeed: Velocity { return 180 }
    var numberOfDoors: Int { return 4 }
    var hasFlatbed: Bool { return false }
}

//利用拓展给 Car 增加初始化方法,这样会保留默认的成员初始化方法
extension Car {
    init(make: String, model: String, year: Int) {
        self.init(make: make, model: model, year: year, color: "Black", nickname: "N/A", gasLevel: 1.0)
    }
}

var c = Car(make: "Ford", model: "Fusion", year: 2013)

extension Car {
    enum Kind {
        case coupe, sedan
    }
    var kind: Kind {
        if numberOfDoors == 2 {
            return .coupe
        } else {
            return .sedan
        }
    }
}
c.kind

extension Car {
    mutating func  emptyGas(by amount: Double) {
        precondition(amount <= 1 && amount > 0, "Amount to remove must be between 0 and 1.")
        gasLevel -= amount
    }
    
    mutating func fillGas() {
        gasLevel = 1.0
    }
}
c.emptyGas(by: 0.3)
c.gasLevel
c.fillGas()
c.gasLevel

(2)扩展协议

protocol Exercise: CustomStringConvertible {
    var name: String { get }
    var caloriesBurned: Double { get } //消耗的卡路里
    var minutes: Double { get }//锻炼的时长
}

extension Exercise {
    var description: String {
        return "Exercise(\(name), burned \(caloriesBurned) calories in \(minutes) minutes)"
    }
}

extension Exercise {
    var title: String {
        return "\(name) - \(minutes) minutes"
    }
}

struct EllipticalWorkout: Exercise {
    let name: String = "Elliptical Workout"
    let title: String = "Workout using the Go Fast Elliptical Trainer 3000"
    let caloriesBurned: Double
    let minutes: Double
}

struct TreadmillWorkout: Exercise {
    let name: String = "Treadmill Workout"
    let caloriesBurned: Double
    let minutes: Double
    let laps: Double //跑步的圈数
}
extension TreadmillWorkout {
    var description: String {
        return "TreadmillWorkout(\(caloriesBurned) calories and \(laps) laps in \(minutes) minutes)"
    }
}

let ellipticalWorkout = EllipticalWorkout(caloriesBurned: 335, minutes: 30)
let runningWorkout = TreadmillWorkout(caloriesBurned: 350, minutes: 25, laps: 10.5)
//使用范型定义函数:计算每分钟消耗的卡路里
func caloriesBurnedPerMinute<E: Exercise>(for exercise: E) -> Double {
    return exercise.caloriesBurned / exercise.minutes
}
print(caloriesBurnedPerMinute(for: ellipticalWorkout))
print(caloriesBurnedPerMinute(for: runningWorkout))

//拓展协议
extension Exercise {
    //所有实现该协议的类型都可以使用通过拓展为该协议添加的属性和方法
    var caloriesBurnedPerMinute: Double {
        return caloriesBurned / minutes
    }
}

print(ellipticalWorkout.caloriesBurnedPerMinute)
print(runningWorkout.caloriesBurnedPerMinute)
print(ellipticalWorkout)
print(runningWorkout)

//带 where 子句的协议拓展
extension Sequence where Iterator.Element == Exercise {
    func totalCaloriesBurned() -> Double {
        var total: Double = 0
        for exercise in self {
            total += exercise.caloriesBurned
        }
        return total
    }
}

let mondayWorkout: [Exercise] = [ellipticalWorkout, runningWorkout]
print(mondayWorkout.totalCaloriesBurned())


for exercise in mondayWorkout {
    print(exercise.title)
}
print(ellipticalWorkout.title)

5、范型

struct StackIterator<T>: IteratorProtocol {
//    typealias Element = T
    
    var stack: Stack<T>
    
    mutating func next() -> T? {
        return stack.pop()
    }
}

// Sequence 是实现 for-in 循环在内部使用的协议
struct Stack<E>: Sequence {
    var items = [E]()
    
    // 使用 where 子句约束 Sequence 的元素类型
    mutating func pushAll<S: Sequence>(_ sequence: S) where S.Iterator.Element == E {
        for item in sequence {
            self.push(item)
        }
    }
    
    mutating func push(_ newItem: E) {
        items.append(newItem)
    }
    
    mutating func pop() -> E? {
        guard !items.isEmpty else {
            return nil
        }
        return items.removeLast()
    }
    
    func map<U>(_ f: (E) -> U) -> Stack<U> {
        var mappedItems = [U]()
        for item in items {
            mappedItems.append(f(item))
        }
        return Stack<U>(items: mappedItems)
    }
    
    func makeIterator() -> StackIterator<E> {
        return StackIterator(stack: self)
    }
}

var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
var doubledStack = intStack.map { 2 * $0 }

print(intStack.pop())
print(intStack.pop())
print(intStack.pop())
print(doubledStack.pop())
print(doubledStack.pop())

func myMap<T, U>(_ items: [T], _ f: (T) -> U) -> [U] {
    var result = [U]()
    for item in items {
        result.append(f(item))
    }
    return result
}
let strings = ["one", "two", "three"]
//let stringLengths = myMap(strings, {(str: String) -> Int in
//    return str.count
//})
let stringLengths = myMap(strings) { $0.count }
print(stringLengths)

//类型约束
func checkIfEqual<T: Equatable>(_ first: T, _ second: T) -> Bool {
    return first == second
}
print(checkIfEqual(1, 1))
print(checkIfEqual("a string", "a string"))
print(checkIfEqual("a string", "a different string"))

//每个占位类型都可以有一个类型约束
func checkIfDescriptionsMatch<T: CustomStringConvertible, U: CustomStringConvertible>(_ first: T, _ second: U) -> Bool {
    return first.description == second.description
}

print(checkIfDescriptionsMatch(Int(1), UInt(1)))
print(checkIfDescriptionsMatch(1, 1.0))
print(checkIfDescriptionsMatch(Float(1.0), Double(1.0)))


var myStack = Stack<Int>()
myStack.push(10)
myStack.push(20)
myStack.push(30)
var myStackIterator = StackIterator(stack: myStack)
while let value = myStackIterator.next() {
    print("got \(value)")
}

for value in myStack {
    print("for-in loop: got \(value)")
}
myStack.pushAll([1, 2, 3])
for value in myStack {
    print("after pushing: got \(value)")
}
var myOtherStack = Stack<Int>()
myOtherStack.pushAll([1, 2, 3])
myStack.pushAll(myOtherStack)
for value in myStack {
    print("after pushing item onto stack, got \(value)")
}

6、协议

protocol TabularDataSource {
    var numberOfRows: Int { get }
    var numberOfColumns: Int { get }
    func label(forColumn column: Int) -> String
    func itemFor(row: Int, column: Int) -> String
}

protocol PrintableTabularDataSource: TabularDataSource, CustomStringConvertible {
    //
}

//组合协议,让 printTable 的参数符合 CustomStringConvertible 协议
func printTable(_ dataSource: TabularDataSource & CustomStringConvertible) {
    print(dataSource)
    var firstRow = "|"
    var columnWidths = [Int]()
    for i in 0..<dataSource.numberOfColumns {
        let columnLabel = dataSource.label(forColumn: i)
        let columnHeader = " \(columnLabel) |"
        firstRow += columnHeader
        columnWidths.append(columnLabel.count)
    }
    print(firstRow)
    
    for i in 0..<dataSource.numberOfRows {
        var out = "|"
        for j in 0..<dataSource.numberOfColumns {
            let item = dataSource.itemFor(row: i, column: j)
            let paddingNeeded = columnWidths[j] - item.count
            let padding = repeatElement(" ", count: paddingNeeded).joined(separator: "")
            out += " \(padding)\(item) |"
        }
        print(out)
    }
}


struct Person {
    let name: String
    let age: Int
    let yearsOfExperience: Int
}

struct Department: TabularDataSource, CustomStringConvertible {
    let name: String
    var people = [Person]()
    
    var description: String {
        return "Department (\(name))"
    }
    
    init(name: String) {
        self.name = name
    }
    
    mutating func add(_ person: Person) {
        people.append(person)
    }
    
    var numberOfRows: Int {
        return people.count
    }
    
    var numberOfColumns: Int {
        return 3
    }
    
    func label(forColumn column: Int) -> String {
        switch column {
        case 0: return "Employee Name"
        case 1: return "Age"
        case 2: return "Years of Experience"
        default: fatalError("Invalid column!")
        }
    }
    
    func itemFor(row: Int, column: Int) -> String {
        let person = people[row]
        switch column {
        case 0: return person.name
        case 1: return String(person.age)
        case 2: return String(person.yearsOfExperience)
        default: fatalError("Invalid column!")
        }
    }
}

var department = Department(name: "Engineering")
department.add(Person(name: "Joe", age: 30, yearsOfExperience: 6))
department.add(Person(name: "Karen", age: 40, yearsOfExperience: 18))
department.add(Person(name: "Fred", age: 50, yearsOfExperience: 20))

printTable(department)

7、字符串

import Cocoa

extension String {
    /// 截取字符串
    /// - Parameter start: 起始索引(包含)
    /// - Parameter end: 结束索引(不包含)
    func substring(start: Int, end: Int) -> String {
        let firstIndex = index(startIndex, offsetBy: start)
        let lastIndex = index(startIndex, offsetBy: end)
        return String(self[firstIndex..<lastIndex])
    }
    
    /// 16进制字符串(可以有空格)转换成二进制数据
    func toData() -> Data {
        let hex = self.replacingOccurrences(of: " ", with: "")
        var arr = Array<UInt8>()
        for i in 0..<hex.count where i % 2 == 0 {
            let byteStr = hex.substring(start: i, end: i + 2)
    //        print("byteStr = \(byteStr)")
            arr.append(UInt8(byteStr, radix: 16) ?? 0)
        }
        return Data(arr)
    }
}

extension Data {
    
    /// 按照 ASCII 转换成字符串
    func toAscii() -> String {
        return subdata2ascii(start: 0, end: self.count)
    }
    
    /// 转换成16进制字符串
    /// - Parameter withSpace: 可选参数,默认true,输出的字符串是否每两个字节之间放一个空格
    func toHex(withSpace: Bool = true) -> String {
        return subdata2hex(start: 0, end: self.count, withSpace: withSpace)
    }
    
    /// 将指定范围的数据转换成ASCII字符串
    /// - Parameter start: 起始索引(包含)
    /// - Parameter end: 结束索引(不包含)
    func subdata2ascii(start: Int, end: Int) -> String {
        if let str = String(data: self[start..<end], encoding: .ascii) {
            return str
        }
        return ""
    }
    
    /// 将指定范围的数据转换成16进制字符串
    /// - Parameter start: 起始索引(包含)
    /// - Parameter end: 结束索引(不包含)
    /// - Parameter withSpace: 可选参数,默认true,输出的字符串是否每两个字节之间放一个空格
    func subdata2hex(start: Int, end: Int, withSpace: Bool = true) -> String {
        let arr = Array<UInt8>(self[start..<end])
        let hex = arr.map({ byte -> String in
            return String(format: "%02X", byte)
        }).joined(separator: withSpace ? " " : "")
        return hex
    }
}

  
func test() {
    let hexString = "5A 58 48 0C 83 0E 47 07 22 2B 42 41 30 34 56 30 35"
    let data = hexString.toData()
    print("head = \(data.subdata2ascii(start: 0, end: 3))")
    print("mac = \(data.subdata2hex(start: 3, end: 9))")
    print("DeviceType = \(data.subdata2ascii(start: 9, end: 14))")
    print("version = \(data.subdata2ascii(start: 14, end: data.count))")
    print(data.toHex(withSpace: true))
}

test()

let apples = 3
let oranges = 5
//只要与结束引号(""")的缩进匹配,就会删除每一行开始处的缩进
let quotation = """
        Even though there's whitespace to the left,
        the actual lines aren't indented.
            Except for this line.
        Double quotes (") can appear without being escaped.

        I still have \(apples + oranges) pieces of fruit.
        """
print(quotation)

8、类和结构体

/** struct 类似 Kotlin 的 data class,等价写法是:
 data class Person(var firstName: String = "Matt", var lastName: String = "Mathias")
 */
struct Person {
    var firstName = "Matt"
    var lastName = "Mathias"
}

var p = Person(firstName: "Jia", lastName: "Jiefei")
print(p)


//如果属性没有提供默认值,结构体会根据属性生成默认的成员初始化方法,并且直接打印结构体可以看到所有存储属性的值
struct Device {
    var name: String
    var address: String
    // text 是计算属性,打印时不会输出
    var text: String {
        return "name=\(name), address=\(address)"
    }
}
print(Device(name: "Device", address: "11:22:33:44:55:66"))

//而类就没有默认成员初始化方法了,需要自己编写初始化方法,并且直接打印类实例,不会输出各存储属性的值
class BleDevice {
    var name: String
    var address: String
    
    required init(name: String, address: String) {
        self.name = name
        self.address = address
    }
}
print(BleDevice(name: "BleDevice", address: "AA:BB:CC:DD:EE:FF"))

9、值类型和引用类型

//类是引用类型
class GreekGod {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

let hecate = GreekGod(name: "Hecate")
let athena = GreekGod(name: "Athena")
let zeus = GreekGod(name: "Zeus")
let anotherHecate = hecate
anotherHecate.name = "AnotherHecate"
hecate.name //类是引用类型,改变 anotherHecate.name,hecate.name也会变

//结构体是值类型
struct Pantheon {
    var chiefGod: GreekGod
}

let pantheon = Pantheon(chiefGod: hecate)

pantheon.chiefGod.name // AnotherHecate
let greekPantheon = pantheon
hecate.name = "Trivia"
greekPantheon.chiefGod.name // Trivia

let gods = [athena, hecate, zeus]
let godsCopy = gods
gods.last?.name = "Jupiter"
godsCopy.last?.name // Jupiter


//探究写时复制(copy on write, COW)
fileprivate class IntArrayBuffer {
    var storage: [Int]
    
    init() {
        storage = []
    }
    
    init(buffer: IntArrayBuffer) {
        storage = buffer.storage
    }
}

struct IntArray {
    private var buffer: IntArrayBuffer
    
    init() {
        buffer = IntArrayBuffer()
    }
    
    func describe() {
        let str = buffer.storage.map { i in
            String(i)
        }.joined(separator: ", ")
        print("[\(str)]")
//        print(buffer.storage)
    }
    
    private mutating func copyIfNeeded() {
        //判断引用类型是否只有一个引用
        if !isKnownUniquelyReferenced(&buffer) {
            print("Making a copy of \(buffer.storage)")
            buffer = IntArrayBuffer(buffer: buffer)
        }
    }
    
    
    mutating func insert(_ value: Int, at index: Int) {
        copyIfNeeded()
        buffer.storage.insert(value, at: index)
    }
    
    mutating func append(_ value: Int) {
        copyIfNeeded()
        buffer.storage.append(value)
    }
    
    mutating func remove(at index: Int) {
        copyIfNeeded()
        buffer.storage.remove(at: index)
    }
}

var integers = IntArray()
integers.append(1)
integers.append(2)
integers.append(4)
integers.describe()
var ints = integers
ints.insert(3, at: 2)
integers.describe()
ints.describe()

10、继承

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

Town.swift

struct Town {
    let region: String
    var population: Int {
        didSet {
            print("The population has changed to \(population) from \(oldValue)")
        }
    }
    var numberOfStoplights: Int
    
    //自定义初始化方法,问号表示可失败的初始化方法
    init?(region: String, population: Int, stoplights: Int) {
        guard population > 0 else {
            return nil
        }
        self.region = region
        self.population = population
        numberOfStoplights = stoplights
    }
    
    //委托初始化
    init?(population: Int, stoplights: Int) {
        self.init(region: "N/A", population: population, stoplights: stoplights)
    }
    
    enum Size {
        case small
        case medium
        case large
    }
    
    //计算属性
    var townSize: Size {
        get {
            print("town size")//每次调用都会打印
            switch self.population {
            case 0...10_000:
                return Size.small
            case 10_001...100_000:
                return Size.medium
            default:
                return Size.large
            }
        }
    }
    
    //惰性存储属性,注意这里的等号以及结尾的圆括号
    lazy var name: String = {
        print("town name")//这里只会打印一次,即第一次访问该属性时
        return "XiShe"
    }()
    
    
    func printDescription() {
        print("Population: \(population), number of stoplights: \(numberOfStoplights), region: \(region)")
    }
    
    /* 如果结构体(确切的说,应该是值类型,结构体和枚举都是值类型)的一个实例方法需要修改结构体的属性,就必须使用 mutating 标记该方法 */
    mutating func changePopulation(by amount: Int) {
        population += amount
    }
    
    /* 对于值类型,类型方法使用static标记 */
    static func xxx() {
        
    }
}

Monster.swift

class Monster {
    // static 属性无法被子类覆盖
    static let isTerrifying = true
    // class 属性可被子类覆盖
    class var spookyNoise: String {
        return "Grrr"
    }
    var town: Town?
    var name: String
    
    var victimPool: Int {
        get {
            return town?.population ?? 0
        }
        set {
            town?.population = newValue
        }
    }
    
    //子类必须得实现的初始化方法
    required init(town: Town?, monsterName: String) {
        self.town = town
        name = monsterName
    }
    
    
    func terrorizeTown() {
        if town != nil {
            print("\(name) is terrorizing a town!")
        } else {
            print("\(name) hasn't found a town to terrorize yet...")
        }
    }
    
    /* 对于类,类型方法使用class或者static标记,区别在于static标记的方法无法被子类重写,也可以使用final class代替static */
    static func makeSpookyNoise() {
        print("Brains...")
    }
}

Zombie.swift

class Zombie: Monster {
    override class var spookyNoise: String {
        return "Brains..."
    }
    var walkWithLimp: Bool
    //只将 set 属性设置为私有,get 属性为默认的 internal
    private(set) var isFallingApart: Bool
    
    //指定初始化方法
    init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) {
        walkWithLimp = limp
        isFallingApart = fallingApart
        //如果有父类,子类的指定初始化方法必须调用父类的指定初始化方法
        super.init(town: town, monsterName: monsterName)
    }
    
    //便捷初始化方法,必须调用指定初始化方法或者其他便捷初始化方法,但最终都要调用指定初始化方法,以确保所有属性都进行了初始化
    convenience init(limp: Bool, fallingApart: Bool) {
        self.init(limp: limp, fallingApart: fallingApart, town: nil, monsterName: "Fred")
        if walkWithLimp {
            print("This zombie has a bad knee.")
        }
    }
    
    
    required init(town: Town?, monsterName: String) {
        walkWithLimp = false
        isFallingApart = false
        super.init(town: town, monsterName: monsterName)
    }
    
    //实例被清除出内存时会触发反初始化
    deinit {
        print("Zombie named \(name) is no longer with use.")
    }
    
    //final 禁止子类重写该方法
    final override func terrorizeTown() {
        if !isFallingApart {
            town?.changePopulation(by: -10)
        }
        super.terrorizeTown()
    }
}

 测试代码文章来源地址https://www.toymoban.com/news/detail-724508.html

var town = Town(region: "West", population: 10, stoplights: 6)
town?.printDescription()
for _ in 0..<3 {
    if let townSize = town?.townSize, let townName = town?.name {
        print(townSize)
        print(townName)
    }
    town?.changePopulation(by: 1_000_000)
}
//let genericMonster = Monster()
//genericMonster.town = town
//genericMonster.terrorizeTown()
var fredTheZombie: Zombie? = Zombie(limp: false, fallingApart: false, town: town, monsterName: "Fred")
//fredTheZombie.terrorizeTown()
//fredTheZombie.town?.printDescription()
//Monster.makeSpookyNoise()
print("Victim pool: \(fredTheZombie?.victimPool)")
fredTheZombie?.victimPool = 500
fredTheZombie = nil
print(Monster.spookyNoise)
print(Zombie.spookyNoise)

11、数组和字典

//初始化数组的3种方式,本人习惯上倾向使用第一种
//使用 var 就是可变数组,let就是不可变数组
var bucketList: Array<String> = []
var bucketList2:[String] = ["haha"]
var arr = [Int]()
arr.append(1)
arr.append(3)
arr.append(2)
//print("bucketList.count=\(bucketList.count) arr[0]=\(arr[0])")
//数组排序
let sortedArray = arr.sorted(by: {a, b in
    a < b
})
print(sortedArray)
//注:只有Array<String> 才有 joined 方法,如果元素类型不是 String,得先通过 map 方法转一次
let joinedString = arr.map { i in
    String(i)
}.joined(separator: ", ")
print("[\(joinedString)]")

//字典也有多种初始化方式,这里只列出其中一种
//使用 var 就是可变字典,let就是不可变字典
var dict: Dictionary<String, Int> = [:]
dict["one"] = 1
dict["two"] = 2
dict["three"] = 3
//遍历字典
for (key, value) in dict {
    print("\(key) = \(value)")
}
dict.removeValue(forKey: "one")
dict["two"] = nil //将值设置为nil来删除键值对
print(dict)

到了这里,关于Swift基础的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • iOS开发Swift-控制流

    (1)复合匹配 (2)区间匹配 (3)元组匹配 (4)值绑定匹配 (5)where continue, break, fallthrough, return, throw continue: 停止本次循环,开始下次循环 break: 立即结束整个控制流。可以使用break忽略switch的分支。 fallthrough贯穿: switch中的case加入贯穿,case会穿透到下一个case/ default。

    2024年02月11日
    浏览(52)
  • iOS开发Swift-类型转换

    1.Int或Double转字符串 2.Double转Int(去掉小数点后面的) 3.Int转Double 4.向上转型 5.向下转型

    2024年02月09日
    浏览(46)
  • iOS开发Swift-集合类型

    集合基本类型:数组 Array (有序), 集合 Set (无序不重复), 字典 Dictionary (无序键值对) (1)数组的表示 (2)创建空数组 (3)带值数组 (4)两数组相加创建数组 (5)字面量创造数组 (6)访问数组 (7)添加 (8)修改 (9)删除 (10)遍历 同时需要索引和值时: (1)集合的表示 (2)构造一个集合 (3)字面

    2024年02月11日
    浏览(103)
  • iOS开发Swift-基本运算符

    一元 单一操作对象 -a    !b    c! 二元 两个操作对象 2 + 3 三元 三目运算符 a ? b : c 赋值运算符不返回任何值,所以 if x = y { ... } 无效。 +   -   *   / 默认不允许数值运算中溢出。 溢出运算符:   a + b a % b = 余数 a = (b * 倍数) + 余数 所以a % b = a % -b ==     !=         

    2024年02月11日
    浏览(44)
  • iOS开发Swift-1-Xcode创建项目

    1.创建项目 双击Xcode App,选择Create a new Xcode project。  选择创建一个iOS普通的App项目。选择Single View App,点击Next。  填写项目名,组织名称等,点击next。  选择好文件的存储路径,点击create。  2.为前端添加组件 点击Main,选中View,在右下角show the Object library中找到label组件,

    2024年02月10日
    浏览(39)
  • iOS开发Swift-字符串与字符

     前一个\\\"\\\"\\\"前和后一个\\\"\\\"\\\"后无换行  想要实现在代码编写时换行而在实际运行后不换行:  (1)转义字符 \\0 空字符 \\\\ 反斜线 t 水平制表符 n 换行符 r 回车符 \\\" 双引号 \\\' 单引号 要在\\\"\\\"\\\"中使用(\\\"\\\"\\\")时,必须至少写一个转义符。例如 \\\"\\\"\\\" 或 \\\"\\\"\\\" (2)Unicode标量 u{24} 两位十六进制

    2024年02月11日
    浏览(41)
  • iOS(一):Swift纯代码模式iOS开发入门教程

    1.修改 AppDelegate.swift 和 ViewController.swift 文件 2.删除 SceneDelegate.swift 和 Main.storyboard 文件 3.修改如图所示项 安装 CocoaPods 初始化项目(添加 Podfile 配置文件) 修改 Podfile 文件 安装 打开 ExDemoApp.xcworkspace 项目并向 ViewController.swift 添加示例代码 运行效果 安装 QMUIKit 方式一:触发

    2024年02月09日
    浏览(45)
  • 【iOS】—— swift基础语法及一些第三方库使用

    只能赋值一次 它的值不要求在编译时期确定,但使用之前必须赋值一次 可以被赋值多次 跟常量一样,在使用之前必须给他赋值,否则编译器会报错 这个第三方库和Masonry的作用和用法都很相似 其中这块我们看到和oc不同的是 Int(SIZE_HEIGHT) 这块有个强制类型转化,这块原因是

    2024年02月08日
    浏览(49)
  • Swift语言基础

    Swift 是一种支持多编程范式和编译式的开源编程语言,苹果于2014年WWDC(苹果开发者大会)发布,用于开发 iOS,OS X 和 watchOS 应用程序。 Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。 Swift 在 Mac OS 和 iOS 平台可以和 Object-C 使用相同的运行环境。 官方手册: swift官

    2024年02月12日
    浏览(40)
  • iOS开发Swift-2-图片视图、App图标-赏月App

    1.创建新项目 点击File - New - Project。  选择Single View App,点击Next。  填写文件信息,点击Next。  选择文件位置,点击Create。   修改App显示名称为 “赏月”。 2.设置背景色 选择Main,点击View界面,选择右边属性,点击Background选择背景色。  3.创建图片视图  在组件库中找到

    2024年02月11日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包