• swift---->swift tour


    Swift is a fantastic way to write software, whether it’s for phones, desktops, servers, or anything else that runs code. Swift defines away large classes of common programming errors by adopting modern programming patterns:

    • Variables are always initialized before use.
    • Array indices are checked for out-of-bounds errors.
    • Integers are checked for overflow.
    • Optionals ensure that nil values are handled explicitly.
    • Memory is managed automatically.
    • Error handling allows controlled recovery from unexpected failures.

    hello world
    print("Hello World")
    
    simple value
    • Use let to make a constant and var to make a variable.
    var myVariable = 42
    myVariable = 50
    let myConstant = 42
    
    • Values are never implicitly converted to another type.
    let label = "The width is "
    let width = 94
    let widthLabel = label + String(width)
    

    if we remove the conversion of String, it will get error following.

    image-20200605153358682

    • string interpolation, use ()
    let apples = 3
    let oranges = 5
    let appleSummary = "I have (apples) apples."
    let fruitSummary = "I have (apples + oranges) pieces of fruit."
    
    • multiple lines, use """
    let quotation = """
    I said "I have (apples) apples."
    And then I said "I have (apples + oranges) pieces of fruit."
    """
    
    • arrays and dictionaries creation, use []
    var shoppingList = ["catfish", "water", "tulips"]
    shoppingList[1] = "bottle of water"
    
    var occupations = [
        "Malcolm": "Captain",
        "Kaylee": "Mechanic",
    ]
    occupations["Jayne"] = "Public Relations"
    

    To create an empty array or dictionary, use the initializer syntax.

    let emptyArray = [String]()
    let emptyDictionary = [String: Float]()
    

    If type information can be inferred, you can writean empty array as [] and an empty dictionary as [:]

    shoppingList = []
    occupations = [:]
    

    Controll flow

    Use if and switch to make conditionals, and use for-in, while, and repeat-while to make loops. Parentheses around the condition or loop variable are optional. Braces around the body are required.

    • use if and for
    let individualScores = [75, 43, 103, 87, 12]
    var teamScore = 0
    for score in individualScores {
        if score > 50 {
            teamScore += 3
        } else {
            teamScore += 1
        }
    }
    print(teamScore) // 11
    
    • use ? as optional value
    // error: variable 'hello' used before being initialized 
    var hello: String
    print(hello == nil);
    
    // error: 'nil' cannot initialize specified type 'String'
    var hello: String = nil
    print(hello == nil);
    
    // success, print true
    var hello: String? = nil
    print(hello == nil);
    
    • use ?? asign nil variable default value
    // if name is nil, the defualt value "John Appleseed" is used instead.
    let name: String? = nil
    let username: String = name ?? "John Appleseed"
    
    • Switches

    Switches support any kind of data and a wide variety of comparison operations—they aren’t limited to integers and tests for equality.

    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.")
    case let x where x.hasSuffix("pepper"):
        print("Is it a spicy (x)?")
    default:
        print("Everything tastes good in soup.")
    }
    // "Is it a spicy red pepper?"
    

    After executing the code inside the switch case that matched, the program exits from the switch statement.

    • for-in to iterate

    You use for-in to iterate over items in a dictionary by providing a pair of names to use for each key-value pair.

    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 (kind, numbers) in interestingNumbers {
        for number in numbers {
            if number > largest {
                largest = number
            }
        }
    }
    print(largest) // 25
    
    • while and repeat while
    var n = 2
    while n < 100 {
        n *= 2
    }
    print(n) // 128
    
    var m = 2
    repeat {
        m *= 2
    } while m < 100
    print(m) // 128
    
    • ..< or ... to make a range of indexes

    Use ..< to make a range that omits its upper value, and use ... to make a range that includes both values.

    // total = 1 + 2 + 3
    var total = 0
    for i in 1..<4 {
        total += i
    }
    print(total) // 6
    
    // sum = 1 + 2 + 3 + 4
    var sum = 0
    for i in 1...4 {
        sum += i
    }
    print(sum) // 10
    

    Function and Closures

    Use func to declare a function. Call a function by following its name with a list of arguments in parentheses. Use -> to separate the parameter names and types from the function’s return type.

    • basic function call
    func greet(person: String, day: String) -> String {
        return "Hello (person), today is (day)."
    }
    greet(person: "Bob", day: "Tuesday")
    greet("Bob", "Tuesday") // will get compile error
    

    By default, functions use their parameter names as labels for their arguments. We can write a custom argument label before the parameter name, or write _ to use no argument label.

    func greet(_ person: String, on day: String) -> String {
        return "Hello (person), today is (day)."
    }
    greet("John", on: "Wednesday")
    greet(person: "John", on: "Wednesday") // will get error
    
    • tuple to make a compound value

    We can use tuple to return multiple values from a function.

    func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
        var min = scores[0]
        var max = scores[0]
        var sum = 0
    
        for score in scores {
            if score > max {
                max = score
            } else if score < min {
                min = score
            }
            sum += score
        }
    
        return (min, max, sum)
    }
    let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
    print(statistics.sum) // 120
    print(statistics.2) // 120
    
    • nested functions

    Nested functions have access to variables that were declared in the outer function. You can use nested functions to organize the code in a function that is long or complex.

    func returnFifteen() -> Int {
        var y = 10
        func add() {
            y += 5
        }
        add()
        return y
    }
    print(returnFifteen()) // 15
    

    Functions are a first-class type. This means that a function can return another function as its value.

    func makeIncrementer() -> ((Int) -> Int) {
        func addOne(number: Int) -> Int {
            return 1 + number
        }
        return addOne
    }
    var increment = makeIncrementer()
    print(increment(7)) // 8
    

    A function can take another function as one of its arguments.

    func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
        for item in list {
            if condition(item) {
                return true
            }
        }
        return false
    }
    func lessThanTen(number: Int) -> Bool {
        return number < 10
    }
    var numbers = [20, 19, 7, 12]
    let isMatches = hasAnyMatches(list: numbers, condition: lessThanTen)
    print(isMatches) // true
    
    • closures

    Functions are actually a special case of closures: blocks of code that can be called later.

    let numbers = [1,2,3]
    let result = numbers.map({ (number: Int) -> Int in
        let result = 3 * number
        return result
    })
    print(result) // [3, 6, 9]
    

    When a closure’s type is already known, such as the callback for a delegate, you can omit the type of its parameters, its return type, or both.

    let numbers = [1,2,3]
    let result = numbers.map({number in 3 * number})
    print(result) // [3, 6, 9]
    

    You can refer to parameters by number instead of by name—this approach is especially useful in very short closures.

    // the sorted method with two parameters
    let numbers = [1,2,3]
    let sortedNumbers = numbers.sorted { $0 > $1 }
    print(sortedNumbers) // [3, 2, 1]
    

    Object and Classed

    Use class followed by the class’s name to create a class.

    class Shape {
        var numberOfSides = 0
        func simpleDescription() -> String {
            return "A shape with (numberOfSides) sides."
        }
    }
    

    Create an instance of a class by putting parentheses after the class name.

    var shape = Shape()
    shape.numberOfSides = 7
    var shapeDescription = shape.simpleDescription()
    

    init method to set up the class when an instance is created.

    class NamedShape {
        var numberOfSides: Int = 0
        var name: String
    
        init(name: String) {
            self.name = name
        }
    
        func simpleDescription() -> String {
            return "A shape named (name) with (numberOfSides) sides."
        }
    }
    
    var shape = NamedShape(name: "huhx")
    print(shape.simpleDescription()) // A shape named huhx with 0 sides.
    

    Use deinit to create a deinitializer if you need to perform some cleanup before the object is deallocated.


    Methods on a subclass that override the superclass’s implementation are marked with override—overriding a method by accident, without override, is detected by the compiler as an error.

    class Square: NamedShape {
        var sideLength: Double
    
        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 4
        }
    
        func area() -> Double {
            return sideLength * sideLength
        }
    
        override func simpleDescription() -> String {
            return "A square with sides of length (sideLength)."
        }
    }
    let test = Square(sideLength: 5.2, name: "my test square")
    print(test.area()) // 27.040000000000003
    print(test.simpleDescription()) // A square with sides of length 5.2.
    

    In addition to simple properties that are stored, properties can have a getter and a setter.

    class EquilateralTriangle: NamedShape {
        var sideLength: Double = 0.0
    
        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 3
        }
    
        var perimeter: Double {
            get {
                return 3.0 * sideLength
            }
            set {
                sideLength = newValue / 3.0
            }
        }
    
        override func simpleDescription() -> String {
            return "An equilateral triangle with sides of length (sideLength)."
        }
    }
    var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
    print(triangle.perimeter) // 9.3
    triangle.perimeter = 9.9
    print(triangle.sideLength) // 3.3000000000000003
    

    In the setter for perimeter, the new value has the implicit name newValue. You can provide an explicit name in parentheses after set.

    Notice that the initializer for the EquilateralTriangle class has three different steps:

    1. Setting the value of properties that the subclass declares.
    2. Calling the superclass’s initializer.
    3. Changing the value of properties defined by the superclass. Any additional setup work that uses methods, getters, or setters can also be done at this point.

    If you don’t need to compute the property but still need to provide code that is run before and after setting a new value, use willSet and didSet.

    class TriangleAndSquare {
        var triangle: EquilateralTriangle {
            willSet {
                square.sideLength = newValue.sideLength
            }
        }
        var square: Square {
            willSet {
                triangle.sideLength = newValue.sideLength
            }
        }
        init(size: Double, name: String) {
            square = Square(sideLength: size, name: name)
            triangle = EquilateralTriangle(sideLength: size, name: name)
        }
    }
    var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
    print(triangleAndSquare.square.sideLength) // 10.0
    print(triangleAndSquare.triangle.sideLength) // 10.0
    triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
    print(triangleAndSquare.triangle.sideLength) // 50.0
    

    When working with optional values, you can write ? before operations like methods, properties, and subscripting.

    let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
    let sideLength = optionalSquare?.sideLength
    

    Enumerations and Structures

    Use enum to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.

    By default, Swift assigns the raw values starting at zero and incrementing by one each time, but you can change this behavior by explicitly specifying values. In the example below, Ace is explicitly given a raw value of 1, and the rest of the raw values are assigned in order.

    enum Rank: Int {
        case ace = 1
        case two, three, four, five, six, seven, eight, nine, ten
        case jack, queen, king
    
        func simpleDescription() -> String {
            switch self {
            case .ace:
                return "ace"
            case .jack:
                return "jack"
            case .queen:
                return "queen"
            case .king:
                return "king"
            default:
                return String(self.rawValue)
            }
        }
    }
    let ace = Rank.ace
    print(ace.simpleDescription()) // ace
    let aceRawValue = ace.rawValue
    print(aceRawValue) // 1
    

    Use the init?(rawValue:) initializer to make an instance of an enumeration from a raw value. I

    if let convertedRank = Rank(rawValue: 3) {
        let threeDescription = convertedRank.simpleDescription()
        print(threeDescription) // 3
    }
    

    enumeration can have values associated with the case—these values are determined when you make the instance, and they can be different for each instance of an enumeration case.

    enum ServerResponse {
        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 let .result(sunrise, sunset):
        print("Sunrise is at (sunrise) and sunset is at (sunset).")
    case let .failure(message):
        print("Failure...  (message)")
    }
    // Prints "Sunrise is at 6:00 am and sunset is at 8:09 pm."
    

    Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.

    struct Card {
        var rank: Rank
        var suit: Suit
        func simpleDescription() -> String {
            return "The (rank.simpleDescription()) of (suit.simpleDescription())"
        }
    }
    let threeOfSpades = Card(rank: .three, suit: .spades)
    let threeOfSpadesDescription = threeOfSpades.simpleDescription()
    print(threeOfSpadesDescription) // The 3 of spades
    

    Protocols and Extensions

    Use protocol to declare a protocol.

    protocol ExampleProtocol {
        var simpleDescription: String { get }
        mutating func adjust()
    }
    

    Classes, enumerations, and structs can all adopt protocols.

    protocol ExampleProtocol {
        var simpleDescription: String { get }
        mutating func adjust()
    }
    
    class SimpleClass: ExampleProtocol {
        var simpleDescription: String = "A very simple class."
        var anotherProperty: Int = 69105
        func adjust() {
            simpleDescription += "  Now 100% adjusted."
        }
    }
    var a = SimpleClass()
    a.adjust()
    let aDescription = a.simpleDescription
    
    struct SimpleStructure: ExampleProtocol {
        var simpleDescription: String = "A simple structure"
        mutating func adjust() {
            simpleDescription += " (adjusted)"
        }
    }
    var b = SimpleStructure()
    b.adjust()
    let bDescription = b.simpleDescription
    

    Use extension to add functionality to an existing type, such as new methods and computed properties.

    extension Int: ExampleProtocol {
        var simpleDescription: String {
            return "The number (self)"
        }
        mutating func adjust() {
            self += 42
        }
    }
    print(7.simpleDescription) // The number 7
    

    You can use a protocol name just like any other named type

    let protocolValue: ExampleProtocol = a
    print(protocolValue.simpleDescription) // A very simple class.  Now 100% adjusted.
    print(protocolValue.anotherProperty)  // Uncomment to see the error
    

    Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.

    Error handling

    You represent errors using any type that adopts the Error protocol.

    enum PrinterError: Error {
        case outOfPaper
        case noToner
        case onFire
    }
    

    Use throw to throw an error and throws to mark a function that can throw an error.

    func send(job: Int, toPrinter printerName: String) throws -> String {
        if printerName == "Never Has Toner" {
            throw PrinterError.noToner
        }
        return "Job sent"
    }
    

    There are several ways to handle errors. One way is to use do-catch.

    do {
        let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
        print(printerResponse)
    } catch {
        print(error)
    }
    // Prints "Job sent"
    

    You can provide multiple catch blocks that handle specific errors.

    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)
    }
    // Prints "Job sent"
    

    Another way to handle errors is to use try? to convert the result to an optional.

    let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
    let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")
    

    Use defer to write a block of code that is executed after all other code in the function, just before the function returns.

    var fridgeIsOpen = false
    let fridgeContent = ["milk", "eggs", "leftovers"]
    
    func fridgeContains(_ food: String) -> Bool {
        fridgeIsOpen = true
        defer {
            fridgeIsOpen = false
        }
    
        let result = fridgeContent.contains(food)
        return result
    }
    fridgeContains("banana")
    print(fridgeIsOpen) // false
    

    Generics

    Write a name inside angle brackets to make a generic function or type.

    func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
        var result = [Item]()
        for _ in 0..<numberOfTimes {
            result.append(item)
        }
        return result
    }
    makeArray(repeating: "knock", numberOfTimes: 4)
    

    You can make generic forms of functions and methods, as well as classes, enumerations, and structures.

    // Reimplement the Swift standard library's optional type
    enum OptionalValue<Wrapped> {
        case none
        case some(Wrapped)
    }
    var possibleInteger: OptionalValue<Int> = .none
    possibleInteger = .some(100)
    

    Use where right before the body to specify a list of requirements—for example, to require the type to implement a protocol, to require two types to be the same, or to require a class to have a particular superclass.

    func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
        where T.Element: Equatable, T.Element == U.Element
    {
        for lhsItem in lhs {
            for rhsItem in rhs {
                if lhsItem == rhsItem {
                    return true
                }
            }
        }
        return false
    }
    anyCommonElements([1, 2, 3], [3])
    

  • 相关阅读:
    java 8 stream sql left join =》 jooq & Flink & Scala
    Maven error: lambda expressions are not supported in -source 1.7
    error C2039: 'SetWindowTextA' : is not a member of 'CString'
    循环队列(循环数组)中元素个数的计算
    数据结构之堆
    理解C语言声明的优先级规则
    内联汇编中的asm和__asm__
    程序启动时的堆栈
    局部变量与堆栈
    BCD码干什么用的?
  • 原文地址:https://www.cnblogs.com/huhx/p/13050786.html
Copyright © 2020-2023  润新知