详解Swift中属性的声明与作用

一、引言

属性将值与类,结构体,枚举进行关联。Swift中的属性分为存储属性和计算属性两种,存储属性用于存储一个值,其只能用于类与结构体,计算属性用于计算一个值,其可以用于类,结构体和枚举。

二、存储属性

存储属性使用变量或者常量来存储一个值,在声明存储属性时,可以为其设置一个默认值,也可以在构造示例是进行值的设置,属性可以通过点语法来访问,结构体的存储属性示例代码如下:

struct MyStruct {
  var property1 = 1
  var property2:Int
}
var obj = MyStruct(property1: 1, property2: 2)
//通过点语法进行属性的访问
print(obj.property1,obj.property2)

如上结构体,如果有属性被声明成let常量,则此属性不能够被修改。还有一点需要注意,如果在创建结构体的实例时,使用的是let进行创建,则即便结构体中的属性是变量也不可进行修改。这和类有很大区别。

还有一类存储属性叫做延时存储属性,可以设想一下这样的情形,类的某些属性可能并不是在每次类实例后都会用到,并且有些属性的构造可能会消耗大量的时间,这时一个比较聪明的设计便是在类进行实例化时,这类属性并不被构造,当次类的实例使用到这个属性时,这个属性才被构造出来,这样的属性被称为延时存储属性,使用lazy关键字来声明,示例如下:

//第一个类
class MyClass1 {
  init(){
    print("MyClass1类被构造")
  }
}
class MyClass2 {
  //声明为延时存储属性
  lazy var body = MyClass1()
}
//在构造MyClass2时 并不会进行body属性的构造 不会有打印信息
var obj2 = MyClass2()
//执行下面代码后 会有打印信息 使用body属性使得body被构造
obj2.body

注意,如果在多个线程中对延时构造属性进行使用,不能保证其只被构造一次。

三、计算属性

简单的理解,计算属性并不是独立的用于存储值的属性,开发者甚至可以将其理解为一个计算方法,其主要用于通过计算来获取或者设置其他存储属性的值。示例如下:

struct Circle {
  //圆心
  var center:(Double,Double)
  //半径
  var r:Double
  //周长 将其作为计算属性
  var l:Double{
    get{
      //计算圆的周长
      return 2.0*r*M_PI
    }
    set{
      //通过周长重新计算半径 默认传入的参数名为newValue
      r = newValue/(M_PI*2)
    }
  }
}
var circle = Circle(center: (0,0), r: 2)
print(circle.l)
circle.l=24
print(circle.r)

通过上面的演示代码可以了解,l属性并非是一个新的属性,只是通过r属性来计算出l,或者通过l来反推出r,其中有一点需要注意,计算属性中可以创建两个代码块set和get,set代码块是可选的,其中会默认生成一个newValue参数来传递外界传进来的数据,get代码块是必须要实现的,当然也可以只实现get代码块,这时这个属性将是只读的计算属性,只可以获取,不能够设置。还有一点需要注意,开发者也可以在set代码块后面自定义一个参数名来接收外界传入的参数,示例如下:

struct Circle {
  //圆心
  var center:(Double,Double)
  //半径
  var r:Double
  //周长 将其作为计算属性
  var l:Double{
    get{
      //计算圆的周长
      return 2.0*r*M_PI
    }
    set(newL){
      //通过周长重新计算半径 默认传入的参数名为newValue
      r = newL/(M_PI*2)
    }
  }
}

只读的计算属性可以进行进一步的简写,因为没有了set代码块,所以关键字get和括号也可以给省略掉,不会产生歧义,示例如下:

struct Point {
  var x:Double
  var y:Double
  var center:(Double,Double){
    return (x/2,y/2)
  }
}

四、属性监听器

Swift中的计算属性中的get和set方法和Objective-C中的get和set方法其实并非是一回事,Objective-C提供set和get方法可以让开发者在属性将要获取或者设置的时候来进行一些自定义的操作,这部分的开发需求在Swift中通过属性监听器来实现。

属性监听器有willSet和didSet两种,willSet在属性值将要变化时执行,didSet在属性值已经变化时执行,并且其中会传入变化前后的值。示例如下:

struct Point {
  var x:Double
  var y:Double{
    willSet{
      print("将要进行值的更新设置,新的值是:",newValue)
    }
    didSet{
      print("已经进行值得更新设置,旧的值是:",oldValue)
    }
  }
  var center:(Double,Double){
    return (x/2,y/2)
  }
}
var point = Point(x: 3, y: 3)
//将打印
/*
 将要进行值的更新设置,新的值是: 4.0
 已经进行值得更新设置,旧的值是: 3.0
 */
point.y=4

willSet中默认会生成一个命名为newValue的参数,didSet中会默认生成一个命名为oldValue的参数,也可以自定义这些参数的命名,示例如下:

struct Point {
  var x:Double
  var y:Double{
    willSet(new){
      print("将要进行值的更新设置,新的值是:",new)
    }
    didSet(old){
      print("已经进行值得更新设置,旧的值是:",old)
    }
  }
  var center:(Double,Double){
    return (x/2,y/2)
  }
}

五、实例属性与类型属性

实例属性是针对与一个类型的实例,类型属性则是直接针对与类型。  每对类型进行一次实例化,其实例都有一套独立的实例属性,而类型属性则是类的所有实例所共用的,在Objective-C中,通常使用全局的属性来实现这样的效果,在Swift中,使用static关键字来声明类型属性,示例如下:

struct Point {
  //类型存储属性
  static var name:String = "Point"
  //类型计算属性
  static var subName:String{
    return "sub"+name
  }
  var x:Double
  var y:Double{
    willSet(new){
      print("将要进行值的更新设置,新的值是:",new)
    }
    didSet(old){
      print("已经进行值得更新设置,旧的值是:",old)
    }
  }
  var center:(Double,Double){
    return (x/2,y/2)
  }
}
//类型属性 通过类型点语法来获取
print(Point.name,Point.subName)

注意,有一种特殊的情况是针对于类的类型计算属性,如果其需要子类进行继承重写,需要将static关键字,换成class关键字,示例如下:

class SomeClass {
  static var storedTypeProperty = "Some value."
  static var computedTypeProperty: Int {
    return 27
  }
  //支持子类进行重写的计算属性
  class var overrideableComputedTypeProperty: Int {
    return 107
  }
}
(0)

相关推荐

  • 详解Swift中的函数及函数闭包使用

    一.引言 函数是有特定功能的代码段,函数会有一个特定的名称调用时来使用.Swift提供了十分灵活的方式来创建与调用函数.事实上在Swift,每个函数都是一种类型,这种类型由参数和返回值来决定.Swift和Objective-C的一大区别就在于Swift中的函数可以进行嵌套. 而Swift中的闭包是有一定功能的代码块,这十分类似于Objective-C中的block语法.Swift中的闭包语法风格十分简洁,其作用和函数的作用相似. 二.函数的创建与调用 函数通过函数名,参数和返回值来定义,参数和返

  • Swift中的条件判断、循环、跳转语句基础学习笔记

    一.引言 一种编程语言的强大与否,很大程度上取决于其提供的程序流程控制方案,就如使用汇编语言实现复杂的程序流程是一件痛苦的事情.Swift中提供了许多强大的流程控制语句,例如快速遍历for-in,while循环,repeat-while循环,switch选择等,需要注意的是,在Swift2.2中,for(a;b;c)循环已经被弃用掉,并且Swift中的Switch语句也更加强大,可以处理任意数据类型. 二.for-in循环 配合范围运算符,for-in循环可以用来执行确定次数的循环,示例如下:

  • Swift中的类class与结构体struct体学习笔记

    一.引言 Swift中的类与结构体十分相似,和Objective-C不同的事,Swift中的结构体不仅可以定义属性,也可以像类一样为其定义方法. Swift中的类与结构体有如下相似点: 1.定义属性来存储值. 2.定义函数来提供功能. 3.通过定义下标语法使用下标的方式取值. 4.定义构造方法来对其进行初始化. 5.通过扩展来在原始基础上添加功能. 6.通过协议来定义实现标准. 当然类和结构体也有许多不同点,下面这些功能是类独有的,结构体没有: 1.通过继承来创建类的子类. 2.在运行时允许对类

  • 详解Swift中enum枚举类型的用法

    一.引言 在Objective-C语言中,没有实际上是整型数据,Swift中的枚举则更加灵活,开发者可以不为其分配值类型把枚举作为独立的类型来使用,也可以为其分配值,可以是字符,字符串,整型或者浮点型数据. 二.枚举语法 Swift中enum关键字来进行枚举的创建,使用case来创建每一个枚举值,示例如下: //创建姓氏枚举,和Objective-C不同,Swift枚举不会默认分配值 enum Surname { case 张 case 王 case 李 case 赵 } //创建一个枚举类型的

  • Swift代码实现冒泡排序算法的简单实例

    冒泡排序原理 1.对需要排序的数据,俩俩进行比较,小的放前面,大的放后面 2.依次对每一对相邻的数据作步骤1的工作,当排序到最后一个元素的时候,我们能保证这个数据是最大. 3.针对所有的元素重复以上的步骤,除了最后一个(这里为什么需要针对除了最后一个元素的全部元素做一次呢,因为最后一个元素已经是最大的不需要排序了,同时,由于元素的交换,交换上来的元素的大小不一定比前面的元素的大,所以需要再做一次). 4持续对越来越少的元素重复3的步骤,直到没有任何一对元素需要比较. 时间复杂度 我们一般谈最坏时

  • 深入解析Swift编程中的构造方法

    一.引言 构造方法是一个类创建对象最先也是必须调用的方法,在Objective-C中,开发者更习惯称这类方法为初始化方法.在Objective-C中的初始化方法与普通函数相比除了要以init抬头外并无太严格的分界,而在Swift语言体系中,构造方法与普通的方法分界十分严格,从格式写法上就有不同,普通方法函数要以func声明,构造方法统一为init命名,不需要func关键字声明,不同的构造方法采用方法重载的方式创建. 二.构造方法的复写与重载 在Objective-C中,不同的初始化方法就是不同的

  • 详解Swift面向对象编程中的方法(method)

    struct Point { var x:Double var y:Double mutating func move(x:Double,y:Double) { self = Point(x: self.x+x,y: self.y+y) } static func name(){ print("Point") } } Point.name() 一.引言 方法只是一个术语,其实就是将函数与特定的类型结合,类.结构体.枚举都可以定义方法,方法又分为实例方法和类型方法,类型方法类似于Obje

  • 详解Swift中属性的声明与作用

    一.引言 属性将值与类,结构体,枚举进行关联.Swift中的属性分为存储属性和计算属性两种,存储属性用于存储一个值,其只能用于类与结构体,计算属性用于计算一个值,其可以用于类,结构体和枚举. 二.存储属性 存储属性使用变量或者常量来存储一个值,在声明存储属性时,可以为其设置一个默认值,也可以在构造示例是进行值的设置,属性可以通过点语法来访问,结构体的存储属性示例代码如下: struct MyStruct { var property1 = 1 var property2:Int } var ob

  • 详解Swift中对C语言接口缓存的使用以及数组与字符串转为指针类型的方法

    详解Swift中对C语言接口缓存的使用以及数组与字符串转为指针类型的方法 由于Swift编程语言属于上层编程语言,而Swift中由于为了低层的高性能计算接口,所以往往需要C语言中的指针类型,由此,在Swift编程语言刚诞生的时候就有了UnsafePointer与UnsafeMutablePointer类型,分别对应为const Type*类型与Type *类型. 而在Swift编程语言中,由于一般数组(Array)对象都无法直接用于C语言中含有指针类型的函数参数(比如:void*),所以往往需要

  • 详解JSP 中Spring工作原理及其作用

    详解JSP 中Spring工作原理及其作用 1.springmvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作. 2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller. 3.DispatcherServlet请请求提交到目标Controller 4.Controller进行业务逻辑处理后,会返回一个ModelAndView 5.Dispathcher查询一个或多个

  • 详解 objective-c中interface与protocol的作用

    详解 objective-c中interface与protocol的作用 以前对Objective-C中的interface,即头文件的作用一直不太清楚.最近看了一些文章,再加上自己的试验,对头文件的作用稍有了解. 在我看来,头文件的作用是,定义对外的接口. 然而,它的作用也只有这个而已.头文件无法保证对外接口一定会被实现. 根据.h文件是否定义方法..m文件是否实现方法,可以分为三类: 第一类是.h文件定义方法,.m文件也实现了方法,这是最common的做法,也是最没有问题的做法. 第二类是.

  • 详解mysql中的静态变量的作用

    详解mysql中的静态变量的作用 使用静态变量 static variable 示例代码: function Test() { $a = 0; echo $a; $a++; } 本函数没什么用处,因为每次调用时都会将 $a 的值设为 0 并输出 "0".将变量加一的 $a++ 没有作用,因为一旦退出本函数则变量 $a 就不存在了 示例代码: function Test(){ static $a = 0; echo $a; $a++; } 每次调用 Test() 函数都会输出 $a 的值

  • 详解 Mysql中的delimiter定义及作用

    初学mysql时,可能不太明白delimiter的真正用途,delimiter在mysql很多地方出现,比如存储过程.触发器.函数等. 学过oracle的人,再来学mysql就会感到很奇怪,百思不得其解. 其实就是告诉mysql解释器,该段命令是否已经结束了,mysql是否可以执行了. 默认情况下,delimiter是分号(;) . 在命令行客户端中,如果有一行命令以分号结束,那么回车后,mysql将会执行该命令.如输入下面的语句 mysql> select * from test_table;

  • 详解Swift中的下标访问用法

    Swift中的Array,Dictionary类型可以通过下标或者键值的方式来进行数据的访问,实际上在Swift的语法中,下标可以定义在类.结构体.枚举中.开发者可以通过下标的方式来对属性进行访问而不用使用专门的存取方法.并且定义的下标不限于一维,开发者可以定义多维的下标来满足需求. 下标的语法结构 下标使用subscript来定义,其有些类似于方法,参数和返回值本别作为下标入参和通过下标所取的值.但是在subscript实现部分,又十分类似于计算属性,其需要实现一个get块和可选实现一个set

  • 详解Swift中的Characters字符类型与String字符串类型

    一.引言 Swift中提供了String类型与Characters类型来处理字符串和字符数据,Swift中的String类型除了提供了许多方便开发者使用的方法外,还可以与Foundation框架的NSString类进行转换,使用起来十分方便. 二.String基础 在Swift中,使用双引号来定义字符串,开发者可以通过如下代码来创建一个字符串常量: let str = "Hello, playground" 可以通过下面两种方式来创建空字符串: let str1 = "&qu

随机推荐