类

Swift2.0语言的类与对象

Swift2.0语言中类的组成 8.1  类的构成

• q  属性：它将值和特定的类关联。
• q  下标脚本：访问对象、集合等的快捷方式。
• q  方法：实现某一特定的功能，类似于函数。

Swift2.0语言中创建类

Swift中类的创建要比在Objective-C中简单的多。在Objecttive-C中，需要使用需要@interface@end对类中的内容进行声明，还需要使用@implementation@end对类声明的内容进行实现。在Xcode 6.3之前，它们需要放置在不同的文件中。虽然在Xcode 6.4中，它们可以放置在一个文件中，但是也相当的麻烦。Swift语言推出了自己创建类的方式，只使用一个class关键字，其一般的创建形式如下：

• class 类名{
•   //具体内容
• }

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

• class 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 常量存储属性名:数据类型=初始值

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

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

• class NewClass1 {
•     let value1=20
•     var value2:Int=10
• }

• class NewClass1 {
•     let value1=20
•     var value2:Int
• }

• 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)

• '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)")

• annot assign to 'let' property 'firstValue'

3.延迟存储属性

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

【示例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)

• [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  调试

1）定义一个延迟存储属性时除了lazy外，还需要使用var关键字，但是不能使用let关键字，否则程序就会出现错误，如以下代码：

• class DataImporter {
•     var fileName = 123456
• }
• class DataManager {
•     lazy let importer = DataImporter()
•     var data = [String]()
• }

• 'lazy' cannot be used on a let

2）初始内容是不可以省去的，否则程序就会出现错误，如以下的代码，定义了一个没有初始值的延迟属性。代码如下:

• class DataManager {
•     lazy var value:Int
• }

• lazy properties must have an initializer

计算属性

• get{
•   …
•   return 某一属性值
• }
• setter使用set关键字进行定义，其一般语法形式如下：
• set(参数名称){
•   …
•   属性值=某一个值
•   …
• }

• 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.定义计算属性的关键字

• class WalletClass{
•     var money=0.0
•     let cal:Double{
•         get{
•             var RMB=money*6.1
•             return RMB
•         }
•         set(RMB){
•             money=RMB/6.1
•         }
•     }
• }

• 'let' declarations cannot be a computed property

2.数据类型

• 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后面的参数类型

• 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
•         }
•     }
• }

• Expected ')' after setter value name
• Expected '{' to start setter definition

4.没有定义参数名称

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

• import Foundation
• class DegreeClass{
•     var degree=0.0
•     var cal :Double{
•         get{
•         }
•         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{
•         }
•         set(aaa){                                                                                                           //定义参数名称后，使用默认参数
•             degree=1.8*newValue+32
•         }
•     }
• }

• Use of unresolved identifier 'newValue'

5.settergetter的省略

【示例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)")

• 没有名字时NULL
• 有名字时Tom

• class PersonName{
•     var name:String=""
•     var setName :String{
•         set{
•             …
•         }
• }

• Variable with a setter must also have a getter

Swift2.0语言的类型属性

• class var 类型属性名:数据类型{
•    …
•    返回一个值
• }

• 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

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

• import Foundation
• class NewClass {
•     class let newvalue:Int{
•         return 20
•     }
• }
• print(NewClass.newvalue)

• 'let' declarations cannot be computed properties

2.存储属性

• import Foundation
• class NewClass {
•     var count:Int=20
•     class var newvalue:Int{
•         return count
•     }
• }
• print(NewClass.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)

• '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语言中的属性监视器

• var 属性名:数据类型=初始值{
•          willSet(参数名){
•                  …
• }
•          didSet(参数名){
•                  …
•     }
• }

【示例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 个值

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 个值

• 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.默认参数不可以交换使用

• import Foundation
• class StepCounter {
• var totalSteps: Int = 0 {
•     //完整的属性监视器
•         willSet {
•             print("新的值为 \(newValue)")
•         }
•         didSet {
• if newValue > oldValue  {
•     print("与原来相比增减了 \(newValue - oldValue) 个值")   //输出新值和旧值之间的差值
•             }
•         }
•     }
• }
• let stepCounter = StepCounter()

• 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

• 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

• 新的值为 0
• 新的值为 200
• 新的值为 600
• 新的值为 1200

• 博文量
915
• 访问量
742908
{"ft_lang_label":"__label__zh","ft_lang_prob":0.98709714,"math_prob":0.9002498,"size":5758,"snap":"2019-43-2019-47","text_gpt3_token_len":4219,"char_repetition_ratio":0.120264165,"word_repetition_ratio":0.0,"special_character_ratio":0.14866273,"punctuation_ratio":0.0745234,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9714428,"pos_list":[0,1,2,3,4,5,6,7,8],"im_url_duplicate_count":[null,1,null,1,null,1,null,1,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2019-10-18T13:33:29Z\",\"WARC-Record-ID\":\"<urn:uuid:31122359-4dbf-44bb-a9b7-eccdeb57adeb>\",\"Content-Length\":\"142559\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:c6160660-e568-4008-90be-615905c6a581>\",\"WARC-Concurrent-To\":\"<urn:uuid:eff7a0d4-3a08-4d38-8242-8b60f17e9907>\",\"WARC-IP-Address\":\"122.226.187.14\",\"WARC-Target-URI\":\"http://blog.itpub.net/29597077/viewspace-1742857/\",\"WARC-Payload-Digest\":\"sha1:DDLG2VZ7N4EO2SJYUPDK2LSPKRGVJSIP\",\"WARC-Block-Digest\":\"sha1:IFAP434CXDFOJ5LZLIZ3NHXMPJWRQ2PV\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2019/CC-MAIN-2019-43/CC-MAIN-2019-43_segments_1570986682998.59_warc_CC-MAIN-20191018131050-20191018154550-00359.warc.gz\"}"}