Swift_Apprentice_v2.0语法中

作者: Mg明明就是你 | 来源:发表于2017-07-07 11:40 被阅读66次
    • 六、第六部分:Structures

    • 1.Structures(结构体)

    • 举个栗子

    let restaurantLocation = (2, 4)
    let restaurantRange = 2.5
    // Pythagorean Theorem # $
    func distance(from source: (x: Int, y: Int), to target: (x: Int, y: Int))
    -> Double {
            let distanceX = Double(source.x - target.x)
            let distanceY = Double(source.y - target.y)
            return sqrt(distanceX * distanceX + distanceY * distanceY)
    }
    func isInDeliveryRange(location: (x: Int, y: Int)) -> Bool {
            let deliveryDistance = distance(from: location, to: restaurantLocation)
            return deliveryDistance < restaurantRange
    }
    
    let restaurantLocation = (2, 4)
    let restaurantRange = 2.5
    let otherRestaurantLocation = (7, 8)
    let otherRestaurantRange = 1.5
    // Pythagorean Theorem # $
    func distance(from source: (x: Int, y: Int), to target: (x: Int, y: Int))
    -> Double {
            let distanceX = Double(source.x - target.x)
              let distanceY = Double(source.y - target.y)
              return sqrt(distanceX * distanceX + distanceY * distanceY)
    }
    func isInDeliveryRange(location: (x: Int, y: Int)) -> Bool {
              let deliveryDistance =
        distance(from: location,
                   to: restaurantLocation)
              let secondDeliveryDistance =
        distance(from: location,
                   to: otherRestaurantLocation)
              return deliveryDistance < restaurantRange ||secondDeliveryDistance < otherRestaurantRange
    }
    
    • Your first structure

    struct Location {
            let x: Int
            let y: Int 
    }
    
    • Your second structure

    struct DeliveryArea {
             var range: Double
             let center: Location
    }
    
    • 完整示例:

    struct Location {
        let x: Int
        let y: Int
    }
    struct DeliveryArea {
        var range: Double
        let center: Location
    }
    func distance(from source: (x: Int, y: Int), to target: (x: Int, y: Int))
        -> Double {
            let distanceX = Double(source.x - target.x)
            let distanceY = Double(source.y - target.y)
            return sqrt(distanceX * distanceX + distanceY * distanceY)
    }
    let areas = [
              DeliveryArea(range: 2.5, center: Location(x: 2, y: 4)),
              DeliveryArea(range: 4.5, center: Location(x: 9, y: 7))
    ]
    func isInDeliveryRange(_ location: Location) -> Bool {
              for area in areas {
                  let distanceToStore =
                  distance(from: (area.center.x, area.center.y),
                     to: (location.x, location.y))
                  if distanceToStore < area.range {
                     return true
                  }
             }
             return false
    }
    let customerLocation1 = Location(x: 8, y: 1)
    let customerLocation2 = Location(x: 5, y: 5)
    print(isInDeliveryRange(customerLocation1)) // false
    print(isInDeliveryRange(customerLocation2)) // true
    

    • 七、第七部分:Properties

    • 1.stored properties(存储属性)

    struct Contact {
            var fullName: String
            var emailAddress: String
    }
     var person = Contact(fullName: "Grace Murray",
                     emailAddress: "grace@navy.mil")
     let name = person.fullName // Grace Murray
    let email = person.emailAddress // grace@navy.mil
    
    • Default values

    struct Contact {
            var fullName: String
            var emailAddress: String
            var type = "Friend"
    }
    
    • 2.Computed properties(计算属性)

    • Getter,举个栗子

    struct TV {
          var height: Double  // 存储属性
          var width: Double   // 存储属性
          // 1
          var diagonal: Int {  // 计算属性
                // 2
                let result = sqrt(height * height + width * width)
                // 3
                let roundedResult = result.rounded()
                // 4
                return Int(roundedResult)
            }
    }
     var tv = TV(height: 53.93, width: 95.87)
    let size = tv.diagonal // 110
     tv.width = tv.height // 改变width,diagonal通过计算发生变化
    let diagonal = tv.diagonal // 76
    
    • Getter and setter

    var diagonal: Int {
          // 1
          get { // 2
            let result = sqrt(height * height + width * width)
            let roundedResult = result.rounded(.toNearestOrAwayFromZero)
            return Int(roundedResult)
        } set {
            // 3
            let ratioWidth = 16.0
            let ratioHeight = 9.0
            // 4
            height = Double(newValue) * ratioHeight /
          sqrt(ratioWidth * ratioWidth + ratioHeight * ratioHeight)
            width = height * ratioWidth / ratioHeight
        }
    }
    tv.diagonal = 70 // 通过设置tv.diagonal,自动获得tv.height和tv.width
    let height = tv.height // 34.32...
    let width = tv.width // 61.01...
          - ###说明:
    1。因为你想要包括一个setter,你现在必须明确哪些计算组成的getter和setter,所以你周围每个代码块和花括号之前得到或设置。这不是只读属性,计算所需的单一代码块隐式getter。
    2。您可以使用与前面相同的代码来获得计算值。
    3。对于setter,你通常需要做出这样的假设。在这种情况下,您为屏幕比提供了一个合理的默认值。
    4。考虑到一个高和宽,给定一个对角和一个比,面积有点深。你可以用一点时间来解决它们,但我已经为你做了一些脏活,并在这里提供了它们。关注的重点是:
            - newValue常量允许您使用在赋值期间传递的任何值。
            - 记住,对角线是一个整数,所以在计算中使用它时,你必须先把它转换成双精度。
            - 一旦你做了计算,你就会分配电视结构的高度和宽度。
    
    • Type properties(类型属性)

    struct Level {
            static var highestLevel = 1 // 类型属性
            let id: Int
            var boss: String
            var unlocked: Bool
    }
    let level1 = Level(id: 1, boss: "Chameleon", unlocked: true)
    let level2 = Level(id: 2, boss: "Squid", unlocked: false)
    let level3 = Level(id: 3, boss: "Chupacabra", unlocked: false)
    let level4 = Level(id: 4, boss: "Yeti", unlocked: false)
    
    • Property observers(属性观察器)

    struct Level {
            static var highestLevel = 1 // 类型属性
            let id: Int
            var boss: String
            var unlocked: Bool {
                didSet {
                    if unlocked && id > Level.highestLevel {
                        Level.highestLevel = id
                    }
                }
            }
    }
    现在,当玩家解锁一个新级别时,如果级别是新的高度,它将更新highestLevel类型属性。这里有几件事需要注意:
    您可以从didSet观察器中访问未锁定的值。请记住,在设置了值之后,didSet就会被调用。
    即使您是在类型的一个实例中,您仍然需要访问类型属性,它们的全名都是级别的。高水平的,而不是仅仅是高水平的。
    另外,请记住,在初始化期间设置属性时,不会调用willSet和didSet观察器;只有当您为完全初始化的实例分配一个新值时,才会调用它们。这意味着属性观察器只对可变属性有用,因为常量属性只在初始化期间设置。
    
    • Limiting a variable(限制一个变量)

    struct LightBulb {
          static let maxCurrent = 40
          var current = 0 {
              didSet {
                  if current > LightBulb.maxCurrent {
                    print("Current too high, falling back to previous setting.")
                    current = oldValue
                  }
              }
           }
    }
     - ###测试:
    var light = LightBulb()
    light.current = 50
    var current = light.current // 0
    light.current = 40
    current = light.current // 40
    // 你试着把灯泡设置为50安培,但是灯泡拒绝了输入。很酷!
    
    • Lazy properties(懒加载属性

    struct Circle {
          // 这里,您不相信从标准库中可以获得的pi值;您需要自己计算它
          lazy var pi = {
              return ((4.0 * atan(1.0 / 5.0)) - atan(1.0 / 239.0)) * 4.0
          }()
          var radius = 0.0
          var circumference: Double {
              mutating get {
                  return pi * radius * 2
              }
          }
          init (radius: Double) {
              self.radius = radius
          }
    }
    //  您可以使用它的初始化器创建一个新的圆,而pi计算将不会运行:
    var circle = Circle(radius: 5) // got a circle, pi has not been run
    let circumference = circle.circumference // 31.42 // also, pi now has a value
    

    在前一章中,我们学习了属性,它们是常量和变量,它们是结构的一部分。方法,正如您已经看到的,仅仅是驻留在结构中的函数。
    在本章中,您将更深入地了解方法和初始化器。与属性一样,您将开始设计更复杂的结构。在本章中学习的内容将适用于所有命名类型的方法,包括类和枚举,您将在后面的章节中看到。

    • 八、第八部分:Methods

    通过计算属性,您可以在最后一章看到,您可以从一个结构中运行代码。这听起来很像一种方法。有什么区别呢?这确实取决于风格,但有一些有用的想法可以帮助你做出决定。属性保存您可以得到和设置的值,而方法执行工作。有时,当方法的唯一目的是返回一个值时,这种区别就会变得模糊。
    问问自己,你是否想要能够设定一个价值,并获得价值。计算属性可以在内部设置一个setter组件来编写值。另一个需要考虑的问题是,计算是否需要进行大量的计算或从数据库中读取数据。即使是一个简单的值,一个方法也可以帮助您向未来的开发人员指出,这个调用在时间和计算资源方面是昂贵的。如果调用很便宜,就使用计算属性。


    • Turning a function into a method(将一个函数转换为一个方法)

    let months = ["January", "February", "March",
                  "April", "May", "June",
                  "July", "August", "September",
                  "October", "November", "December"]
    struct SimpleDate {
            var month: String
    }
    func monthsUntilWinterBreak(from date: SimpleDate) -> Int {
            return months.index(of: "December")! - months.index(of: date.month)!
    }
    print(monthsUntilWinterBreak(from:SimpleDate(month: "May"))) // 7
    

    如果把方法定义在Struct中会不会更容易理解呢

    struct SimpleDate {
          var month: String
          func monthsUntilWinterBreak1(from date: SimpleDate) -> Int {
                return months.index(of: "December")! - months.index(of: date.month)!
          }
          // 推荐写法
           func monthsUntilWinterBreak() -> Int {
                return months.index(of: "December")! - months.index(of: self.month)!
            }
    }
    let date = SimpleDate(month: "October")
    let monthsLeft = date.monthsUntilWinterBreak(from: date) // 2
    
    • mutating methods()

    结构中的方法不能改变实例的值,而不被标记为“ mutating”。变异关键字标记了一个改变结构值的方法。由于一个结构是一个值类型,每次它在一个应用程序中传递时,系统就会复制它。如果一个方法改变了其中一个属性的值,那么原来的实例和复制的实例就不再是等价的了
    通过将一个方法标记为mutating,您告诉快速编译器这个方法不应该在常量上调用。这就是Swift知道在编译时允许哪些方法和拒绝哪些方法。如果您在一个常量结构上调用一个mutating方法,编译器会将其标记为一个错误,在您运行程序之前必须纠正这个错误。

    struct SimpleDate {
            var month: String
            var day: Int
            init(month: String, day: Int) {
                self.month = month
                self.day = day
            }
            mutating func advance() {
                day += 1 // 没有加mutating修饰func的话,会编译错误,不能在结构体提直接修改day的值
            }
    }
    var current = SimpleDate(month: "December", day: 30)
    current.advance()
    let currentMonth = current.month // December; should be January!
    let currentDay = current.day // 31;
    
    没有加mutating修饰func的话,会编译错误.png
    • Type methods(类方法)

    与类型属性一样,您可以使用类型方法来访问所有实例中的数据。您在类型本身上调用类型方法,而不是在实例上调用。要定义类型方法,您需要使用静态修饰符来对其进行前缀。
    类型方法对于一般情况下的类型是有用的,而不是特定的实例。

    struct Math {
            // 1 类方法,关键字static修饰
            static func factorial(of number: Int) -> Int {
                // 2
                return (1...number).reduce(1, *)
            }
    }
    // 3
    let factorial = Math.factorial(of: 6) // 720
    
    • extensions(扩展)

    struct SimpleDate {
            var month: String
            var day: Int
     }
    extension SimpleDate {
            init() {
                month = "March"
                day = 1
            }
    }
    let defaultDay = SimpleDate()
    let childrensDay = SimpleDate(month: "May", day: 5)
    

    您学习了结构体,它是一个命名类型,它允许您定义自己的类型。在本章中,您将熟悉,它们与结构非常相似,它们被命名为类型,具有属性,并且可以定义方法。
    但是,您将学习的类是引用类型,而不是值类型,它们的功能和优点与它们的结构相比具有很大的不同。虽然您经常在应用程序中使用结构来表示值,但通常使用类来表示对象。

    • 九、第九部分:Classes

      • 结构体和类的区别

      • Reference types(引用类型)class
    class Person {
          let name: String
          init(name: String) {
              self.name = name
          }
    }
    var var1 = Person(name: "John")
    
    内存.png
    如果您要创建一个新的变量var2并将其赋值为var1的值:
    var var2 = var1
    内存.png
    • value types(值类型)struct

    struct Person {
          let name: String
    }
    var1 = Person(name: "John")
    
    内存.png
    如果您要创建一个新的变量var2并将其赋值为var1的值,然后,var1的值将被复制到var2:
    var var2 = var1
    内存.png
    • help(帮助理解)

    当您创建诸如类之类的引用类型时,系统将实际的实例存储在称为堆的内存区域中。一个值类型的实例,例如一个结构体,驻留在一个名为堆栈的内存区域中,除非该值是类实例的一部分,在这种情况下,该值被存储在类实例的其余部分中。
    堆和堆栈都在执行任何程序时都具有重要的作用。对它们是什么以及它们的工作原理有一个大致的了解,可以帮助你理解类和结构之间的功能差异:
    该系统使用堆栈来存储执行的即时线程上的任何内容;它受到CPU的严格管理和优化。当函数创建一个变量时,堆栈会存储该变量,然后在函数退出时销毁它。因为这个堆栈组织得很好,所以它非常高效,而且非常快。


    help.png

    当您创建一个类的实例时,您的代码请求堆上的一个内存块来存储实例本身;这是图表右侧的实例的第一个名称和最后一个名称。它将该内存的地址存储在堆栈的命名变量中;这是存储在图左侧的引用。
    当您创建一个struct时,值本身就存储在堆栈中,而堆永远不会涉及到。

    • 示例代码

    值类型的工作

    struct Location {
              var x: CGFloat
              var y: CGFloat
    }
    struct DeliveryArea {
              var range: Double
              let center: Location
    }
    var area1 = DeliveryArea(range: 2.5, center: Location(x: 2, y: 4))
    var area2 = area1
    print(area1.range) // 2.5
    print(area2.range) // 2.5
    area1.range = 4  
    print(area1.range) // 4.0
    print(area2.range) // 2.5 不会变为4.0
    

    引用类型

    class DeliveryArea {
            var range: Double
            let center: Location
    }
    var area1 = DeliveryArea(range: 2.5, center: Location(x: 2, y: 4))
    var area2 = area1
    print(area1.range) // 2.5
    print(area2.range) // 2.5
    area1.range = 4  
    print(area1.range) // 4.0
    print(area2.range) // 4.0 不会再是2.5 
    
    • Object identity(OC中的isEqual:)

    在Swift中,===操作符让您检查一个对象的标识是否等于另一个对象的标识:



    .png
    • Preventing inheritance防止继承(final关键字)

    防止类继承

    class Person {
        //...
    }
    final class Student: Person {
        //...
    }
    // Build error!
    class StudentAthlete: Student {
        //...
    }
    

    防止方法重写

    class Student: Person {
      final func recordGrade(_ grade: Grade) {
    //...
    } }
    class StudentAthlete: Student {
            // Build error!
            override func recordGrade(_ grade: Grade) {
              //...
            } 
    }
    
    • Required and convenience initializers

      • Required(必须实现)

    class Student {
              let firstName: String
              let lastName: String
              required init(firstName: String, lastName: String) {
                  self.firstName = firstName
                  self.lastName = lastName
              }
        //... 创建Student对象必须实现 required init(firstName: String, lastName: String),否则编译错误
    }
    Student(firstName: "留", lastName: "明")
    
    不实现报错.png
    • convenience(便利构造)

    class Student {
              convenience init(transfer: Student) {
                  self.init(firstName: transfer.firstName, lastName: transfer.lastName)
              }
    }
    

    十、第十部分:Enumerations

    e.g:举个例子

    enum Month {
      case january
      case february
      case march
      case april
      case may
      case june
      case july
      case august
      case september
      case october
      case november
      case december
    }
    func semester(for month: Month) -> String {
      switch month {
          case Month.august, Month.september, Month.october,
           Month.november, Month.december:
              return "Autumn"
          case Month.january, Month.february, Month.march, Month.april,
           Month.may:
              return "Spring"
        default:
              return "Not in the school year"
      }
    }
    
    • Raw values

    enum Month: Int {
              case january = 1, february = 2, march = 3, april = 4, may = 5,
      june = 6, july = 7, august = 8, september = 9,
      october = 10, november = 11, december = 12
    }
    // 第一个赋值即可,后面的赋值可以省略,自动+1
    enum Month: Int {
              case january = 1, february, march, april, may, june, july,
      august, september, october, november, december
    }
    func monthsUntilWinterBreak(from month: Month) -> Int {
             return Month.december.rawValue - month.rawValue
    }
    monthsUntilWinterBreak(from: .april) // 8
    
    • Initializing with the raw value

     let fifthMonth = Month(rawValue: 5)
    monthsUntilWinterBreak(from: fifthMonth) // Error: value not unwrapped,可选值,必须明确类型解包
    monthsUntilWinterBreak(from: fifthMonth!) // Error: value not 
     let fifthMonth = Month(rawValue: 5)!
    monthsUntilWinterBreak(from: fifthMonth)  // 7
    
    • String raw values

    // 1
    enum Icon: String {
            case music
            case sports
            case weather
            var filename: String {
                // 2
                return "\(rawValue.capitalized).png"
            }
    }
    let icon = Icon.weather
    icon.filename // Weather.png
    icon.rawValue // Weather
    icon.hashValue // 2
    
    • Enumeration as state machine

    交通灯

    enum TrafficLight {
            case red, yellow, green
    }
    let trafficLight = TrafficLight.red
    


    • 轻轻点击,关注我简书

    轻轻点击,关注我简书

    轻轻点击,关注我微博

    浏览我的GitHub


    • 扫一扫,关注我

    扫一扫,关注我.jpg

    相关文章

      网友评论

        本文标题:Swift_Apprentice_v2.0语法中

        本文链接:https://www.haomeiwen.com/subject/gpezcxtx.html