Swift2.0语言教程之类的属性

Swift2.0语言教程之类的属性

虽然函数能够简化代码,可是当一个程序中出现成百上千的函数和变量时,代码仍是会显得很混乱。为此,人们又引入了新的类型——类。它是人们构建代码所用的一种通用、灵活的构造方式。本章将主要详细讲解类的使用。swift

Swift2.0语言的类与对象

类是一种新的数据类型,相似于生活中犬类、猫类等等。而对象则是将这个抽象的类进行了具体化。例如,在犬类中,有哈士奇,金毛等等,这些就是犬类的具体化,即对象。本节将讲解类的建立以及如何将类进行具体化(即实例化)为对象。ide

Swift2.0语言中类的组成

在一个类中一般能够包含如图8.1所示的内容。函数

8.1  类的构成工具

其中,这些内容的功能以下:spa

  • q  属性:它将值和特定的类关联。.net

  • q  下标脚本:访问对象、集合等的快捷方式。调试

  • q  方法:实现某一特定的功能,相似于函数。code

Swift2.0语言中建立类

Swift中类的建立要比在Objective-C中简单的多。在Objecttive-C中,须要使用须要@interface @end 对类中的内容进行声明,还须要使用@implementation@end 对类声明的内容进行实现。在Xcode 6.3以前,它们须要放置在不一样的文件中。虽然在Xcode 6.4中,它们能够放置在一个文件中,可是也至关的麻烦。Swift语言推出了本身建立类的方式,只使用一个class关键字,其通常的建立形式以下:orm

  • class 类名{server

  •   //具体内容

  • }

注意:在类中能够定义属性和方法,这些内容会在后面作详细的介绍。类名可使用“大骆驼拼写法”方式来命名(如SomeClass),以便符合标准Swift 类型的大写命名风格(如StringIntBool)。对于后面所讲的对象、属性以及方法等可使用“小骆驼拼写法”来命名。

【示例8-1】如下建立一个名为NewClass的类。代码以下:

  • class NewClass{

  •  

  • }

该类名称为NewClass。因为其中没有属性和方法,因此它只是一个空类。

Swift2.0语言实例化对象

实例化对象也能够称为类的实例,其语法形式以下:

  • var/let 对象名=类名()

【示例8-2】如下会建立一个类名为NewClass的类,而后再进行实例化。代码以下:

  • import Foundation

  • class NewClass{

  •    

  • }

  • let newClass=NewClass ()

注意:在进行实例化时,类名后必定要加上()。不然程序就会错误,如如下的代码:

  • var newClass = NewClass

因为在实例化时缺乏了(),致使程序出现如下的错误信息:

  • Expected member name or constructor call after type name

以上所讲的这些只是简单的实例化对象。它使用了最简单的构造器来生成一个对象。在后面的章节中咱们会为开发者讲解构造器的具体用法。

属性

Objective-C中,属性是使用关键字@property关键字进行声明的内容。在Swift中,属性能够将值跟特定的类、结构或枚举关联。属性通常分为存储属性、计算属性和类型属性。本节将讲解对这些属性作详细的讲解。

Swift2.0语言存储属性

存储属性就是存储特定类中的一个常量或者变量。根据数据是否可变,分为常量存储属性和变量存储属性。

1.定义存储属性

常量存储属性使用let关键字定义(声明定义在一块儿进行,为了方便称为定义),其语法形式以下:

  • let 常量存储属性名:数据类型=初始值

变量存储属性可使用var关键字定义,其语法形式以下:

  • var 变量存储属性名:数据类型=初始值

【示例8-3】如下代码定义类NewClass1,其中包含两个属性value1value2,代码以下:

  • class NewClass1 {

  •     let value1=20

  •     var value2:Int=10

  • }

其中,value1使用let定义为常量存储属性,value2使用var定义为变量存储属性。在定义存储属性时,初始值是必不可少的,不然,就会出现错误。例如,如下的代码:

  • class NewClass1 {

  •     let value1=20

  •     var value2:Int

  • }

在此代码中,因为value2后面未加初始值,致使程序出现如下的错误信息:

  • Class 'NewClass1' has no initializers

2.访问存储属性

对于这些存储属性的访问,须要使用“.”点运算符。其语法形式以下:

  • 对象名.常量存储属性名/变量存储属性名

【示例8-4】如下定义了3个存储属性firstValuesecondValuethirdValue,而后进行访问。代码以下:

  • import Foundation

  • class NewClass{

  •     let firstValue:Int = 0

  •     let secondValue=200

  •     var thirdValue:String="Hello"

  • }

  • let newclass=NewClass()

  • //存储属性的访问

  • print("firstValue=\(newclass.firstValue)")

  • print("secondValue=\(newclass.secondValue)")

  • print("thirdValue=\(newclass.thirdValue)")

运行结果以下所示:

  • firstValue=0

  • secondValue=200

  • thirdValue=Hello

注意:对存储属性进行访问时,只能够对在本身类中定义的存储属性进行访问,不然就会出现错误,代码以下:

  • import Foundation

  • class NewClass1 {

  •    var class1Value=10

  • }

  • class NewClass2 {

  •     var class2Value=10

  • }

  • let newclass1=NewClass1()

  • print(newclass1.class1Value)

  • print(newclass1.class2Value)

在此代码中,因为class2Value存储属性是在NewClass2类中定义的,而不是NewClass1中定义的,因此程序就会出现如下的错误信息:

  • 'NewClass1' does not have a member named 'class2Value'

存储属性除了可使用“.”点运算符进行读取外,还能够对其进行修改。修存储改属性的通常语法形式以下:

  • 对象名.存储属性=修改的内容

【示例8-5】如下代码就将secondValue的属性值"Hello"修改成了"Swift",代码以下:

  • import Foundation

  • class NewClass{

  •     var secondValue:String="Hello"

  • }

  • let newclass=NewClass()

  • print("修改前:secondValue=\(newclass.secondValue)")

  • newclass.secondValue="Swift"                                                                       //修改存储实现

  • print("修改后:secondValue=\(newclass.secondValue)")

运行结果以下所示:

  • 修改前:secondValue=Hello

  • 修改后:secondValue=Swift

注意:只有变量存储属性才能够进行属性修改,常量存储属性不能够进行属性修改。如如下的代码:

  • import Foundation

  • class NewClass{

  •     let firstValue:Int = 0

  • }

  • let newclass=NewClass()

  • print("修改前:firstValue=\(newclass.firstValue)")

  • newclass.firstValue=100                                                                 //试图对属性firstValue的值进行修改

  • print("修改后:\(newclass.firstValue)")

因为在类中使用了let对存储属性进行了定义,其值是不能够进行修改的,因此出现了如下的错误信息:

  • annot assign to 'let' property 'firstValue'

3.延迟存储属性

若是开发者只有在第一次调用存储属性时才能肯定初始值,这时须要使用延迟存储属性实现。它的定义通常须要使用关键字lazy实现的,其语法形式以下:

  • lazy var 属性名:数据类型=初始内容

注意:在延迟存储属性中初始内容是不能够省去的。数据类型也是能够省去的,由于swift会根据初始内容自行判断数据类型。

【示例8-6】如下将使用lazy来定义一个延迟存储属性importer,代码以下:

  • import Foundation

  • class DataImporter {

  •     var fileName = 123456

  • }

  • class DataManager {

  •     lazy var importer = DataImporter()

  •     var data = [String]()

  • }

  • let manager = DataManager()

  • manager.data += ["Some more data"]

  • print(manager.data)

  • print(manager.importer.fileName)

在没有调用manager.importer.fileName时,实例的 importer属性尚未被建立。运行结果以下所示:

  • [Some more data]

  • 123456

咱们可使用断点调试的方法对此代码进行调试,来查看它的运行结果。具体步骤以下:

1)为几行关键代码添加断点,并再添加一行代码,来查看添加importer的值,如图8.2所示。

8.2  添加断点

2)单击运行按钮,此时会在第一个断点处出现一个蓝色的箭头,表示此行代码在运行。而后选择Debug|Continue命令,按下调试窗口工具栏中的Continue program execution按钮,查看程序的执行,其中,可使用查看器来观察属性值的变化。属性查看器位于调试信息窗口左半部分,如图8.3所示。程序的执行,如图8.4所示。其中,看到的selfdataimporter.storage(由于importer是延迟属性,为了和其余属性区分,因此在查看器上看到是importer.storage)等都是属性。它们会随程序的执行为改变。

8.3  查看器位置

8.4  调试

在此图中程序执行到第3步,也就是第三个图时,类DataManager的属性data初始化,但没有给importer.storage属性进行初始化,一直为nil,直到执行到第7步,即第7个图时,才为importer.storage属性的属性初始化。

在定义一个延迟存储属性时须要注意如下2点,

1)定义一个延迟存储属性时除了lazy外,还须要使用var关键字,可是不能使用let关键字,不然程序就会出现错误,如如下代码:

  • class DataImporter {

  •     var fileName = 123456

  • }

  • class DataManager {

  •     lazy let importer = DataImporter()

  •     var data = [String]()

  • }

因为在定义延迟属性时使用了let关键字,因此致使程序出现了如下的错误:

  • 'lazy' cannot be used on a let

2)初始内容是不能够省去的,不然程序就会出现错误,如如下的代码,定义了一个没有初始值的延迟属性。代码以下:

  • class DataManager {

  •     lazy var value:Int

  • }

因为在此代码中没有为value指定初始值,致使程序出现了如下的错误:

  • lazy properties must have an initializer

计算属性

除了存储属性外,类中还能够定义计算属性。计算属性不存储值,而是提供了一个gettersetter来分别进行获取值和设置其余属性的值。getter使用get关键字进行定义,其通常形式以下:

  • get{

  •   

  •   return 某一属性值

  • }

  • setter使用set关键字进行定义,其通常语法形式以下:

  • set(参数名称){

  •   

  •   属性值=某一个值

  •   

  • }

固然,它也能够没有参数名称。这种状况会后面的内容中讲解。在计算属性中同时包含了gettersetter,其通常定义形式以下:

  • var 属性名:数据类型{

  •          get{

  •                  

  •                  return 某一属性值

  • }

  •          set(参数名称){

  •                  

  •                  属性值=某一个值

  •                  

  •     }

  • }

【示例8-7】如下代码定义了一个类WalletClass,用来保存钱包中的金额,其默认单位为美圆。为了方便用户以人民币为单位进行访问值和设置值,因此使用了计算属性cal。代码以下:

  • import Foundation

  • class WalletClass{

  •     var money=0.0

  •     var cal:Double{                                                                                        //定义计算属性cal

  •         get{                                                                                            //定义getter

  •             let RMB=money*6.1

  •             return RMB                                                                  //返回以人民币为单位的金额

  •         }

  •         set(RMB){                                                                                 //定义setter

  •             money=RMB/6.1                                                         //返回以美圆为单位的金额

  •         }

  •     }

  • }

  • var mywallet=WalletClass()

  • mywallet.cal=(20)

  • //输出

  • print(mywallet.cal)

  • print(mywallet.money)

运行结果以下所示:

  • 20.0

  • 3.27868852459016

注意:在使用计算属性时须要注意如下三点:

1.定义计算属性的关键字

在定义一个计算属性时,必须且只能使用var关键字,不然就会出现错误。如下的代码,将示例8-7的代码作了一些修改,代码以下:

  • class WalletClass{

  •     var money=0.0

  •     let cal:Double{

  •         get{

  •             var RMB=money*6.1

  •             return RMB

  •         }

  •         set(RMB){

  •             money=RMB/6.1

  •         }

  •     }

  • }

在此代码中定义一个计算属性,可是使用了let关键字,致使程序出现了如下的错误:

  • 'let' declarations cannot be a computed property

2.数据类型

在定义计算属性时,必定要为属性指定一个明确的数据类型,不然就会出现错误提示。例如如下的代码,是将示例8-7中的代码作了一些修改。代码以下:

  • class WalletClass{

  •     var money=0.0

  •     var cal{                                                                                                   //没有设置cal的数据类型

  •         get{

  •             var RMB=money*6.1

  •             return RMB

  •         }

  •         set(RMB){

  •             money=RMB/6.1

  •         }

  •     }

  • }

在此代码中因为没有为计算属性指定一个明确的数据类型,致使程序出现了如下的错误信息:

  • Computed property must have an explicit type

  • Type annotation missing in pattern

3.set后面的参数类型

在使用计算属性时,set后面的参数类型要和返回值的类型相同,不须要再指定类型。不然,程序就会出现错误。如如下的代码,此代码是将示例8-7中的代码作了一下修改,代码以下:

  • class WalletClass{

  •     var money=0.0

  •     var cal:Double{                                                                                               //没有设置cal的数据类型

  •         get{

  •             var RMB=money*6.1

  •             return RMB

  •         }

  •         set(RMB:String){                                                                         //为参数定义了数据类型

  •             money=RMB/6.1

  •         }

  •     }

  • }

在此代码中,对set后面的参数RMB指定了数据类型,致使程序出现了如下的错误:

  • Expected ')' after setter value name

  • Expected '{' to start setter definition

4.没有定义参数名称

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

【示例8-8】如下代码就使用了newValue来实现了华氏温度和摄氏温度的转换。代码以下:

  • import Foundation

  • class DegreeClass{

  •     var degree=0.0

  •     var cal :Double{

  •         get{

  •             let centigradedegree=(degree-32)/1.8

  •             return centigradedegree

  •         }

  •         set{

  •             degree=1.8*newValue+32                                                 //没有定义参数名称,可使用默认的

  •         }

  •     }

  • }

  • var degreeClass=DegreeClass()

  • degreeClass.cal=(10.0)

  • print(degreeClass.cal)

  • print(degreeClass.degree)

运行结果以下所示:

  • 10.0

  • 50.0

4.定义参数名后不能使用默认参数名

set后面若是定义了参数名称,就不能再使用Swift默认的参数名称newValue。不然,就会致使程序出现错误。如如下的代码,将示例8-8作了一些修改,代码以下:

  • import Foundation

  • class DegreeClass{

  •     var degree=0.0

  •     var cal :Double{

  •         get{

  •             let centigradedegree=(degree-32)/1.8

  •             return centigradedegree

  •         }

  •         set(aaa){                                                                                                           //定义参数名称后,使用默认参数

  •             degree=1.8*newValue+32

  •         }

  •     }

  • }

在此代码中,set后面定义了参数名称,可是又使用了默认的参数名称,致使程序出现了如下的错误:

  • Use of unresolved identifier 'newValue'

5.settergetter的省略

在计算属性中,若是只有一个getter,则称为只读计算属性。只读计算属性能够返回一个值,但不能设置新的值。

【示例8-9】如下将经过getter来获取名称的字符串。代码以下:

  • import Foundation

  • class PersonName{

  •     var name:String=""

  •     var returnName :String{

  •         if (name.isEmpty) {

  •             return "NULL"

  •         }else{

  •             return name

  •         }

  •     }

  • }

  • var personClass=PersonName()

  • print("没有名字时\(personClass.returnName)")

  • personClass.name=("Tom")

  • print("有名字时\(personClass.returnName)")

在此代码中,当刚建立实例PersonName后,就去访问returnName。因为name默认为空,因此会返回字符串"NULL"。再对name赋值后,再一次访问returnName。因为name不为空,因此会返回name的内容。运行结果以下所示:

  • 没有名字时NULL

  • 有名字时Tom

注意:1.在只读计算属性中,能够将get关键字和花括号去掉。2.C#等其余语言中能够将属性分为只读属性(只有getter)、只写属性(只有setter)和可读可写属性。可是在Swift中就不一样了,只有只读计算属性和可读可写计算属性两个。没有只写计算属性,不然程序就会出现错误,如如下的代码:

  • class PersonName{

  •     var name:String=""

  •     var setName :String{

  •         set{

  •             

  •         }

  • }

在此代码中定义了一个只写计算属性,致使程序出现了如下的错误:

  • Variable with a setter must also have a getter

Swift2.0语言的类型属性

类型属性就是不须要对类进行实例化就可使用的属性。它须要使用关键字class进行定义,其定义形式以下:

  • class var 类型属性名:数据类型{

  •    

  •    返回一个值

  • }

例以下面代码定义了一个类型属性count,代码以下:

  • class var count:Int{

  • return 20

  • }

类型属性也是能够被访问的,其访问类型属性的通常形式以下:

  • 类名.类型属性

【示例8-10】如下代码定义了一个类型属性newvalue,而后进行遍历访问该属性的每个字符,并输出。代码以下:

  • import Foundation

  • class NewClass {

  •     class var newvalue:String{                                                                  //定义类型属性newvalue

  •         return "Hello"

  •     }

  • }

  • print(NewClass.newvalue)

  • print("遍历NewClass.newvalue")

  • //遍历类型属性newvalue的值

  • for index in NewClass.newvalue.characters {

  •     print(index)

  • }

  • 运行结果以下所示:

  • Hello

  • 遍历NewClass.newvalue

  • H

  • e

  • l

  • l

  • o

在使用类型属性时须要注意如下2点:

1.let关键字不能声明类型属性

定义类型属性时除了有关键字class外,还须要使用var关键字,但不能使用let关键字,不然程序提示错误,如如下代码,此代码定义了一个类型属性newvalue。代码以下:

  • import Foundation

  • class NewClass {

  •     class let newvalue:Int{

  •         return 20

  •     }

  • }

  • print(NewClass.newvalue)

在此代码中使用了关键字let进行了类型属性的声明,致使程序出现了如下的错误:

  • 'let' declarations cannot be computed properties

2.存储属性

在类型方法中不能使用存储属性,不然程序就会出现错误,如如下的代码,此代码实现的是输出字符串"Hello"

  • import Foundation

  • class NewClass {

  •     var count:Int=20

  •     class var newvalue:Int{

  •         return count

  •     }

  • }

  • print(NewClass.newvalue)

其中,count是存储属性,newvalue是类型属性。在代码中,将str用在newvalue中,致使程序出现了如下的错误:

  • 'NewClass.Type' does not have a member named 'count'

3.对象不能访问类型属性

类型属性只可使用类去访问,而不可使用对象进行访问。不然,就会出现错误,如如下的代码:

  • import Foundation

  • class NewClass {

  •     class var newvalue:Int{

  •         return 20

  •     }

  • }

  • var newClass=NewClass()

  • print(newClass.newvalue)

在此代码中,定义了一个类型属性newvalue,但在访问它时使用了对象,致使程序出现了如下错误:

  • 'NewClass' does not have a member named 'newvalue'

类型属性和存储属性同样,除了能够进行访问外,还能够进行修改,其语法形式以下:

  • 类名.类型属性=修改的内容

【示例8-11】如下程序将类型属性0变为200,并输出。代码以下所示:

  • import Foundation

  • var value:Int=0

  • class NewClass{

  •     class var count :Int{

  •         get{

  •             let newvalue=value

  •             return newvalue

  •         }

  •         set{

  •             value=newValue

  •         }

  •     }

  • }

  • print("修改前:\(NewClass.count)")

  • NewClass.count=200

  • print("修改后:\(NewClass.count)")

运行结果以下所示:

  • 修改前:0

  • 修改后:200

Swift2.0语言中的属性监视器

属性监视器用来监控和响应属性值的变化。每次属性被设置值的时候,都会调用属性监视器,哪怕是新的值和原先的值相同。一个属性监视器由willSetdidSet组成,其定义形式以下:

  • var 属性名:数据类型=初始值{

  •          willSet(参数名){

  •                  

  • }

  •          didSet(参数名){

  •                  

  •     }

  • }

其中,willSet在设置新的值以前被调用,它会将新的属性值做为固定参数传入。didSet在新的值被设置以后被调用,会将旧的属性值做为参数传入,能够为该参数命名或者使用默认参数名oldValue

【示例8-12】如下将使用属性监视器监视totalSteps属性值的变化。代码以下:

  • import Foundation

  • class StepCounter {

  • var totalSteps: Int = 0 {

  •     //完整的属性监视器

  •         willSet(newTotalSteps) {

  •             print("新的值为 \(newTotalSteps)")

  •         }

  •         didSet(old) {

  • if totalSteps > old {                                                                           

  •       print("与原来相比增减了 \(totalSteps - old) 个值")

  •             }

  •         }

  •     }

  • }

  • let stepCounter = StepCounter()

  • stepCounter.totalSteps = 0

  • stepCounter.totalSteps = 200

  • stepCounter.totalSteps = 400

  • stepCounter.totalSteps = 800

运行结果以下所示:

  • 新的值为 0

  • 新的值为 200

  • 与原来相比增减了 200 个值

  • 新的值为 400

  • 与原来相比增减了 200 个值

  • 新的值为 800

  • 与原来相比增减了 400 个值

注意:在使用属性监视器时,须要使用注意如下4点:

1.不指定参数名

willSet后面是能够不指定参数的,这时Swift会使用默认newValue表示新值。例如如下的代码在没有指定willSet参数的状况下,直接使用newValue来输出新的值。代码以下:

  • import Foundation

  • class StepCounter {

  •     var totalSteps: Int=0  {

  •         willSet {

  •             print("新的值为 \(newValue)")

  •         }

  •         didSet (old){

  •             if totalSteps > old  {

  •                 print("与原来相比增减了 \(totalSteps - old) 个值")

  •             }

  •         }

  •     }

  • }

  • let stepCounter = StepCounter()

  • stepCounter.totalSteps = 0

  • stepCounter.totalSteps = 200

运行结果以下所示:

  • 新的值为 0

  • 新的值为 200

  • 与原来相比增减了 200 个值

一样在didSet后面也能够不指定参数名,此时Swift会使用默认参数名oldValue。如如下的代码,此是示例8-12的代码作了一个修改,代码以下:

  • import Foundation

  • class StepCounter {

  • var totalSteps: Int = 0 {

  •     //完整的属性监视器

  •         willSet(newTotalSteps) {

  •             print("新的值为 \(newTotalSteps)")

  •         }

  •         didSet {

  •             if totalSteps > oldValue  {

  •                 print("与原来相比增减了 \(totalSteps - oldValue) 个值")

  •             }

  •         }

  •     }

  • }

  • let stepCounter = StepCounter()

  • stepCounter.totalSteps = 0

2.默认参数不能够交换使用

在使用willSetdidSet时,它们默认的参数能够是不能够交换使用的。例如在willSet中使用的newValue不可使用在didSet中,在didSet中使用的oldValue不可使用在willSet中,不然程序就会出现错误。例如如下的代码,将示例8-12作了一些修改,代码以下:

  • import Foundation

  • class StepCounter {

  • var totalSteps: Int = 0 {

  •     //完整的属性监视器

  •         willSet {

  •             print("新的值为 \(newValue)")

  •         }

  •         didSet {

  • if newValue > oldValue  {                                                                          

  •     print("与原来相比增减了 \(newValue - oldValue) 个值")   //输出新值和旧值之间的差值

  •             }

  •         }

  •     }

  • }

  • let stepCounter = StepCounter()

在此代码中,因为在didSet中使用了willSet中的默认参数,致使程序出现了如下的错误:

  • Use of unresolved identifier 'newValue'

3.延迟属性不能使用属性监视器

在延迟属性中不可使用属性监视器,不然程序会出现错误。如如下的代码:

  • class StepCounter {

  •    lazy var totalSteps: Int=0  {

  •         willSet {

  •             print("新的值为 \(newValue)")

  •         }

  •         didSet {

  •             if totalSteps > oldValue  {

  •                 print("与原来相比增减了 \(totalSteps - oldValue) 个值")

  •             }

  •         }

  •     }

  • }

此代码中延迟属性中添加了属性监视器,致使程序出现了以下的错误:

  • lazy properties may not have observers

4.分开使用willSetdidSet

一个完整的属性监视器由willSetdidSet组成,可是willSetdidSet也能够单独使用。例如如下的代码就只使用了willSet输出了新值的信息。代码以下:

  • import Foundation

  • class StepCounter {

  •    var totalSteps: Int=0  {

  •         willSet {

  •             print("新的值为 \(newValue)")

  •         }

  •     }

  • }

  • let stepCounter = StepCounter()

  • stepCounter.totalSteps = 0

  • stepCounter.totalSteps = 200

  • stepCounter.totalSteps = 600

  • stepCounter.totalSteps = 1200

这里属性监视器total只使用了willset,而没有使用didset。运做结果以下所示:

  • 新的值为 0

  • 新的值为 200

  • 新的值为 600

  • 新的值为 1200

本文选自:Swift2.0语言快速入门v3.0 大学霸内部资料,转载请注明出处,尊重技术尊重IT人!

相关文章
相关标签/搜索