PART_A 属性简介

  • 存储属性:存储常量(let)或变量(var),作为实例的一部分. 只能作用于类和结构体

  • 计算属性:计算一个值. 可用于类、结构体、枚举. 必须用 var 声明

  • 类型属性:上述两属性通常与特定类型的实例关联. 该属性可直接作用于类型本身

PART_B 存储属性

  1. 案例

    struct Range {
        var startIndex: Int // 变量存储属性
        let width: Int // 常量存储属性(创建实例时被初始化)
    }
    
    var range = Range(startIndex: 0,width: 5)
    // 区间为 0...5
    range.startIndex = 3
    // 区间为 3...8
  2. 常量结构体的存储属性

    • 当值类型的实例被声明为常量时,其所有属性也成常量

    • 当引用类型的实例被声明为常量后,仍可修改该实例的变量属性

      let rangeFix = Range(startIndex: 3,width: 8)
      rangeFix.startIndex = 1
      // 报错. 因结构体是值类型,而值类型的实例被声明为常量,其属性均成常量
  3. 延迟存储属性:lazy var声明. 第一次被调用时才计算其属性的初始化值

    • 使用场景

      • 当属性的值依赖于在实例的构造过程结束后才会知道具体值的外部因素时

      • 当获得属性的初始值需要复杂或大量计算时

    • 当被 lazy 标记的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次

      class DataProvider {
          // 导入文件(耗时操作)
          var fileName = "data.txt"
      }
      
      class DataManager {
          lazy var provider = DataProvider()
      
          // 数据管理
          var data = [String]()
      }
      
      let manager = DataManager()
      manager.data.append("Some data")
      manager.data.append("Some more data")
      // DataProvider 实例还没有被创建
      
      
      print(manager.importer.fileName)
      // DataProvider 实例被创建(此时第一次被调用)
  4. 存储属性和实例变量

    • Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问

PART_C 计算属性(-案例值得琢磨-)

  1. 不直接存储值,提供 gettersetter 来间接获取和设置值

    // 定义中心坐标
    struct Point {
        var x = 0.0,y = 0.0
    }
    
    // 定义宽高
    struct Size {
        var width = 0.0,height = 0.0
    }
    
    // 定义矩形
    struct Rect {
    
        var origin = Point()
        var size = Size()
    
        var center: Point {
            // getter:返回 Point 实例(中心)
            get {
                let centerX = origin.x + (size.width / 2)
                let centerY = origin.y + (size.height / 2)
                return Point(x: centerX,y: centerY)
            }
    
            // setter:设置 Point 中心坐标
            set(newCenter) {
                origin.x = newCenter.x - (size.width / 2)
                origin.y = newCenter.y - (size.height / 2)
            }
        }
    }
    
    var square = Rect(origin: Point(x: 0.0,y: 0.0),size: Size(width: 10.0,height: 10.0))
    
    let squareCenter = square.center
    // 中心坐标 (5,5)
    
    square.center = Point(x: 15.0,y: 15.0)
    
    print("square.origin is Now at (\(square.origin.x),\(square.origin.y))")
    // 输出 "square.origin is Now at (10.0,10.0)”
  2. 便捷 setter 声明

    • 若计算属性的 setter 没有定义新值的参数名,则可使用默认名称 newValue

      // 上述代码的 setter 可简写
      set {
          origin.x = newCenter.x - (size.width / 2)
          origin.y = newCenter.y - (size.height / 2)
      }
  3. 只读计算属性:只有 getter 没有 setter 的计算属性,总是返回一个值

    struct Cuboid {
        var width = 0.0,height = 0.0,depth = 0.0
    
        // 只读计算属性
        var volume: Double {
            return width * height * depth
        }
    }
    
    let rect1 = Cuboid(width: 4.0,height: 5.0,depth: 2.0)
    print("the volume of rect1 is \(rect1.volume)")

PART_D 属性观察器

  • 可为除延迟存储属性外的其他存储属性添加

  • 可通过重写属性的方式为继承的属性(存储属性、计算属性)添加

  • 父类的属性在子类构造器中被赋值时,其在父类的观察器会被调用

  • 可为属性添加如下一个或全部观察器

    • willSet:新值被设置前调用

    • didSet:新值被设置后调用

      class StepCounter {
          var totalSetps: Int = 0 {
              // newTotalSteps:新值(默认 newValue)
              willSet(newTotalSteps) {
                  print(newTotalSteps)
              } didSet {
                  // oldValue:旧值 
                  if totalSetps > oldValue {
                      print(totalSetps - oldValue)
                  }
              }
          }
      }
      
      let stepCounter = StepCounter()
      stepCounter.totalSetps = 50
      // 50
      // 50
      
      stepCounter.totalSetps = 90
      // 90
      // 40
      
      stepCounter.totalSetps = 80
      // 80
  • 若一个属性的 didSet 观察器里赋值,该值会替代之前设置的值

PATR_E 全局变量和局部变量

  1. 定义

    • 全局变量:在函数、方法、闭包或任何类型之外定义的变量

    • 局部变量:在函数、方法或闭包内部定义的变量

  2. 注意

    • 全局的常量或变量都是延迟计算的(省略 lazy 修饰符)

    • 局部的常量或变量从不延迟计算

  3. 计算属性和属性观察器所描述的功能可用于全局变量和局部变量

PART_F 类型属性(static):定义某个类型所有实例共享的数据

  • 实例属性属特定类型的实例,每创建一个实例,实例都拥有属于自己的一套属性值,实例间的属性相互独立

  • 必须给存储型类型属性指定默认值(无构造器,无法初始化时赋值)

  • 存储型类型属性是延迟初始化的(省略 lazy). 即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化

  1. 语法

    struct SomeStructure {
        // 存储型类型属性
        static var storedTypeProperty = "Some value."
        // 计算型类型属性(本例所用是只读的)
        static var computedTypeProperty: Int {
            return 5
        }
    }
    enum SomeEnumeration {
        static var storedTypeProperty = "Some value."
        static var computedTypeProperty: Int {
            return 6
        }
    }
    class SomeClass {
        static var storedTypeProperty = "Some value."
        static var computedTypeProperty: Int {
            return 7
        }
    
        // 为类定义计算型类型属性时,改用 class 支持子类对父类的实现进行重写
        class var overrideableComputedTypeProperty: Int {
            return 8
        }
    }
  2. 获取和设置类型属性的值

    • 和实例属性一样通过 .,但类型属性是通过类型本身来访问(是不是很像JAVA的静态类)

      SomeStructure.storedTypeProperty = "Another value."

  3. 案例:两个喇叭的音量

    struct AudioChannel {
    
        // 常量存储类型属性:音量上限
        static let thresholdLevel = 10
    
        // 变量存储类型属性:输入音量
        static var maxInputLevelForAllChannels = 0
    
        // 存储型实例属性:当前声道音量
        var currentLevel: Int = 0 {
            // 属性观察器
            didSet {
                if currentLevel > AudioChannel.thresholdLevel {
                    // 将当前音量限制在音量上限内
                    currentLevel = AudioChannel.thresholdLevel
                }
                if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                    // 存储音量上限
                    AudioChannel.maxInputLevelForAllChannels = currentLevel
                }
            }
        }
    }
    
    var leftChannel = AudioChannel()
    var rightChannel = AudioChannel()
    
    leftChannel.currentLevel = 7 // 左声道音量为 7
    rightChannel.currentLevel = 11 // 右声道音量为 10(控制在音量上限内)

以上。如有错误和疑问,欢迎指正提出。 catface.wyh@gmail.com

Swift开篇008->属性的更多相关文章

  1. three.js模拟实现太阳系行星体系功能

    这篇文章主要介绍了three.js模拟实现太阳系行星体系功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

  2. HTML5 3D书本翻页动画的实现示例

    这是一款十分炫酷的HTML5 3D书本翻页动画,效果相对比较简单,拖拽鼠标模拟用手翻页,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5页面无缝闪开的问题及解决方案

    这篇文章主要介绍了HTML5页面无缝闪开方案,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. 使用postMessage让 iframe自适应高度的方法示例

    这篇文章主要介绍了使用postMessage让 iframe自适应高度的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. ios – UIPopoverController出现在错误的位置

    所以我花了一些时间寻找答案,但到目前为止还没有找到任何答案.我正在尝试从UIInputAccessoryView上的按钮呈现弹出窗口.UIBarButtonItem我想显示popover来自定制视图,所以我可以使用图像.我创建这样的按钮:当需要显示popover时,我这样做:但我得到的是:弹出窗口看起来很好,但它应该出现在第一个按钮上时出现在第二个按钮上.然后我发现了这个问题:UIBarButto

  6. ios – 如何从变量访问属性或方法?

    是否可以使用变量作为Swift中方法或属性的名称来访问方法或属性?在PHP中,您可以使用$object->{$variable}.例如编辑:这是我正在使用的实际代码:解决方法你可以做到,但不能使用“纯粹的”Swift.Swift的重点是防止这种危险的动态属性访问.你必须使用Cocoa的Key-ValueCoding功能:非常方便,它完全穿过你要穿过的字符串到属性名称的桥,但要注意:这里是龙.

  7. ios – Swift中的UIView动画不起作用,错误的参数错误

    我正在尝试制作动画并使用下面的代码.我得到“无法使用类型’的参数列表调用’animateWithDuration'(FloatLiteralConvertible,延迟:FloatLiteralConvertible,选项:UIViewAnimationoptions,动画:()–>()–>$T4,完成:(Bool)–>(Bool)–>$T5)’“错误.这意味着我使用了错误的参数.我错了.请

  8. iOS >>块>>更改块外部的变量值

    我不是在处理一个Object并改变它,就像我的mString一样.我希望’center’属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针.我希望’backgroundColor’的行为类似于我的imstring,因为它是一个指向一个新对象的对象的指针,不是吗?

  9. ios – Xcode Bot:如何在post触发器脚本上获得.ipa路径?

    我正在使用机器人来存档iOS应用程序,我需要获取.ipa产品路径才能将其发布到我们的分发系统中.机器人设置:并使用脚本打印所有env变量,其中不包含ipa文件的路径.此外,一些变量指向不存在的目录,即:XCS_OUTPUT_DIR这里的env变量输出:除此之外,我还能够确认.ipa文件是在另一个文件夹中创建的(/IntegrationAssets//

  10. ios – 使用附加字符串本地化Info.plist变量

    我正在尝试本地化应用程序的名称,同时仍然能够根据构建配置追加字符串.所以目前它被设置为:该设置定义为:通过这种方式,我们可以为应用程序添加后缀以用于不同的beta版本.问题是,当我们尝试本地化本地化的InfoPlist.strings中的应用程序显示名称时,就像这样我们覆盖存储在Info.plist中的值,并丢失后缀字符.这有什么好办法吗?

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部