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


Posted in Python onJune 30, 2016

一、引言

属性将值与类,结构体,枚举进行关联。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
  }
}
Python 相关文章推荐
理解Python中的With语句
Feb 02 Python
简单介绍Python的Tornado框架中的协程异步实现原理
Apr 23 Python
详解Python3 中hasattr()、getattr()、setattr()、delattr()函数及示例代码数
Apr 18 Python
利用Python yagmail三行代码实现发送邮件
May 11 Python
Django配置celery(非djcelery)执行异步任务和定时任务
Jul 16 Python
python实现windows倒计时锁屏功能
Jul 30 Python
解决pytorch GPU 计算过程中出现内存耗尽的问题
Aug 19 Python
Python 文件操作之读取文件(read),文件指针与写入文件(write),文件打开方式示例
Sep 29 Python
Python 格式化打印json数据方法(展开状态)
Feb 27 Python
完美解决ARIMA模型中plot_acf画不出图的问题
Jun 04 Python
matplotlib实现数据实时刷新的示例代码
Jan 05 Python
用python删除文件夹中的重复图片(图片去重)
May 12 Python
为Python的Tornado框架配置使用Jinja2模板引擎的方法
Jun 30 #Python
Python的Flask框架中的Jinja2模板引擎学习教程
Jun 30 #Python
Python的Tornado框架实现异步非阻塞访问数据库的示例
Jun 30 #Python
Python的Tornado框架实现图片上传及图片大小修改功能
Jun 30 #Python
举例讲解Python中metaclass元类的创建与使用
Jun 30 #Python
在Python中定义和使用抽象类的方法
Jun 30 #Python
Python中functools模块的常用函数解析
Jun 30 #Python
You might like
PHP下一个非常全面获取图象信息的函数
2008/11/20 PHP
PHP 无限分类三种方式 非函数的递归调用!
2011/08/26 PHP
php中的strpos使用示例
2014/02/27 PHP
php cookie名使用点号(句号)会被转换
2014/10/23 PHP
YII2框架使用控制台命令的方法分析
2020/03/18 PHP
浅谈Jquery为元素绑定事件
2015/04/27 Javascript
基于JavaScript实现智能右键菜单
2016/03/02 Javascript
获取input标签的所有属性的方法
2016/06/28 Javascript
vuex实现简易计数器
2016/10/27 Javascript
AngularJS深入探讨scope,继承结构,事件系统和生命周期
2016/11/02 Javascript
Ajax与服务器(JSON)通信实例代码
2016/11/05 Javascript
Dropzone.js实现文件拖拽上传功能(附源码下载)
2016/11/22 Javascript
JavaScript全屏和退出全屏事件总结(附代码)
2017/08/17 Javascript
AngularJS实现的select二级联动下拉菜单功能示例
2017/10/25 Javascript
JS运动特效之链式运动分析
2018/01/24 Javascript
vue.js自定义组件directives的实例代码
2018/11/09 Javascript
Vue中img的src是动态渲染时不显示的解决
2019/11/14 Javascript
Angular如何由模板生成DOM树的方法
2019/12/23 Javascript
vuex页面刷新导致数据丢失的解决方案
2020/12/10 Vue.js
python 获取当天每个准点时间戳的实例
2018/05/22 Python
Python给定一个句子倒序输出单词以及字母的方法
2018/12/20 Python
python 去除二维数组/二维列表中的重复行方法
2019/01/23 Python
python 列表转为字典的两个小方法(小结)
2019/06/28 Python
Python 日志logging模块用法简单示例
2019/10/18 Python
Python内置数据类型list各方法的性能测试过程解析
2020/01/07 Python
Python sqlalchemy时间戳及密码管理实现代码详解
2020/08/01 Python
python装饰器三种装饰模式的简单分析
2020/09/04 Python
印尼旅游网站:via
2017/11/12 全球购物
怎样建立和理解非常复杂的声明?例如定义一个包含N 个指向返回 指向字符的指针的函数的指针的数组?
2013/03/19 面试题
事业单位个人应聘自荐信
2013/09/21 职场文书
房地产销售员的自我评价分享
2013/12/04 职场文书
工地宣传标语
2014/06/18 职场文书
教师党员个人整改措施
2014/10/27 职场文书
晚会开场白和结束语
2015/05/29 职场文书
Nginx下配置Https证书详细过程
2021/04/01 Servers
win10此电脑打不开怎么办 win10双击此电脑无响应的解决办法
2022/07/23 数码科技