zoukankan      html  css  js  c++  java
  • iOS学习笔记43-Swift(三)类

    一、Swift的类class

    作为一门面向对象语言,类也是Swift的非常重要的类型,我们先来看下一个简单的类

    //Swift中一个类可以不继承于任何其他基类,那么此类本身就是一个基类
    class Person {
        //定义属性
        var name:String
        var height = 0.0
        //构造器方法,注意如果不编写构造方法默认会自动创建一个无参构造方法
        init(name:String){
            self.name = name
        }
        //析构器方法,在对象被释放时调用,类似于ObjC的dealloc,注意这里没有括号和参数,无法直接调用
        deinit{
            println("deinit...")
        }
        //定义对象方法
        func showMessage(){
            println("name=(name),height=(height)")
        }    
    }
    //创建类的对象
    var p = Person(name: "Liuting")
    p.height = 170.0
    p.showMessage() //结果:name=Liuting,height=170.0
     
    //类是引用类型
    var p2 = p
    p2.name = "XiaoMing"
    println(p.name) //结果:XiaoMing
    //“===”表示等价于,这里不能使用等于“==”,等于用于比较值相等,p和p2是不同的值,但是指向的对象相同
    if p === p2 { 
        println("p===p2") //p等价于p2,表示二者指向同一个对象
    }

    二、属性

    Swift中淡化了成员属性的概念,把属性分为两种:

    1. 存储属性
      无论从概念上还是定义方式上来看,存储属性更像其他语言中的成员变量,但是不同的是:
    • 可以控制读写操作(var表示可读可写,let表示只读)
    • 通过属性监视器来属性的变化(willSetdidSet
    • 快速实现懒加载功能(lazy修饰)
    1. 计算属性
      计算属性并不直接存储一个值,而是提供getter来获取一个值,或者利用setter来间接设置其他属性。
    下面是对象属性使用实例:
    class Account {
        //定义存储属性,设置默认值,添加属性监听器
        var balance:Double = 0.0{
            //即将赋值时调用
            willSet{
                //注意此时修改balance的值没有用
                self.balance = 2.0
                //newValue表示即将赋值的新值,并且在属性监视器内部调用属性不会引起监视器循环调用
                println("Account.balance willSet,newValue=(newValue),value=(self.balance)")
            }
            //赋值完成后调用
            didSet{
                //注意此时修改balance的值将作为最终结果
                self.balance = 3.0
                //oldValue表示已经赋值的旧值,并且在属性监视器内部调用属性不会引起监视器循环调用
                println("Account.balance didSet,oldValue=(oldValue),value=(self.balance)")
            }
        }
    }
    class Person {
        //firstName、lastName、age是存储属性
        var firstName:String //var定义表示该存储属性可读可写
        var lastName:String
        let age:Int //let定义表示该存储属性只读
        
        //属性的懒加载,第一次访问才会初始化
        lazy var account = Account()//在Swift中懒加载的属性不一定就是对象类型,也可以是基本类型
         
        //fullName是一个计算属性,在get、set方法中不能直接访问计算属性,否则会引起循环调用
        var fullName:String{
            //获取该计算属性时调用
            get{
                return firstName + "." + lastName
            }
            //设置该计算属性时调用
            set{
                //set方法中的newValue表示即将赋值的新值,这里是分割字符串
                let array = split(newValue, maxSplit: Int.max, 
                                    allowEmptySlices: false, 
                                         isSeparator: {$0=="."})
                if array.count == 2 {
                    firstName = array[0]
                    lastName = array[1]
                }
            }
        }
        //构造器方法,注意如果不编写构造方法默认会自动创建一个无参构造方法
        init(firstName:String, lastName:String, age:Int){
            self.firstName = firstName
            self.lastName = lastName
            self.age = age
        }
        //定义方法
        func showMessage(){
            println("name=(self.fullName),age=(self.age)")
        }
    }
    //创建对象
    var p = Person(firstName: "Liu", lastName: "Ting", age:22)
    p.showMessage() //结果:name=Liu.Ting,age=22
    p.fullName = "Liu.HAHA" //设置计算属性
    p.showMessage() //结果:name=Liu.HAHA,age=22
    
    p.account.balance = 10
    /* 下面是存储属性监听器方法打印:
    Account.balance willSet,newValue=10,value=0.0
    Account.balance didSet,oldValue=10,value=3.0
    */
    println("p.account.balance=(p.account.balance)") //结果:p.account.balance=3.0
    1. 计算属性并不直接存储一个值,而是提供getter来获取一个值,或者利用setter来间接设置其他属性;
    2. lazy属性必须有初始值,必须是变量不能是常量,因为常量在构造完成之前就已经确定了值;
    3. 在构造对象方法之前存储属性必须有值(可选类型除外),无论是变量属性还是常量属性,这个值既可以在属性创建时指定,也可以在构造方法内指定;
    4. 存储属性的默认值设置不会引起属性监视器的调用(另外在构造方法中赋值也不会引起属性监视器调用),只有在外部设置存储属性才会引起属性监视器调用;
    除了上面的对象属性外,我们还可以定义类的属性:
    class Student {
        //定义类的属性只需要在前面加static关键字即可,也是分为存储属性和计算属性,这里是计算属性
        static var skin:Array<String>{
            //只定义了getter,表示该计算属性是只读的
            get{
                return ["yellow", "white", "black"]
            }
        }
    }
    //读取类的属性
    for color in Student.skin {
        println(color)
    }

    三、方法

    Swift的类中的方法可分为以下几个类别:
    1. 构造器方法
    • 默认构造器方法(当存在有参数的指定构造器方法,被覆盖)
    • 指定构造器方法
    • 便利构造器方法
    1. 析构器方法
    2. 对象方法
    3. 类方法
    以下是方法使用实例:
    class Person {
        //定义属性
        var name:String
        var height:Double
        var age = 0
        //1.2.指定构造器方法,注意如果不编写构造方法,默认会自动创建一个无参构造方法
        init(name:String, height:Double, age:Int){
            self.name = name
            self.height = height
            self.age = age
        }
        //1.3.便利构造方法,通过调用指定构造方法、提供默认值来简化构造方法实现
        convenience init(name:String){
            self.init(name:name, height:0.0, age:0)
        }
        //2.析构方法,在对象被释放时调用,注意此方法没有括号,没有参数,无法直接调用
        deinit{
            println("deinit...")
        }
        //3.对象方法
        func modifyInfoWithAge(age:Int, height:Double){
            self.age = age
            self.height = height
        }
        //4.类方法,使用class修饰的方法即是类方法
        class func showClassName(){
            println("Class name is Person")
        }      
    }
    //通过便利构造方法创建对象
    var p = Person(name: "liuting")
    //调用对象方法
    p.modifyInfoWithAge(22,height: 170)
    //调用类方法
    Person.showClassName()
    1. 除构造方法、析构方法外,其他方法的参数默认除了第一个参数是局部参数,从第二个参数开始既是局部参数又是外部参数。但是,对于函数,默认情况下只有默认参数既是局部参数又是外部参数,其他参数都是局部参数。
    2. 构造方法的所有参数默认情况下既是外部参数又是局部参数
    3. 只有便利构造器方法才能调用当前类的指定构造方法
    4. 有参数的指定构造器方法会覆盖调用默认的无参构造器方法
    5. 一个对象被释放前,先自动调用自己的析构方法,然后一层一层往上调用父类的析构方法

    四、下标脚本

    下标脚本是一种访问集合的快捷方式,如果我们自定义的类具有集合类型的功能,我们可以定义下标脚本来快捷访问该类属性,定义下标脚本是通过关键字subscript进行的。

    class Record {
        //定义属性,store是Record内部的存储结构,这里是字典
        var store:[String:String]
        //指定构造方法
        init(data:[String:String]){
            self.store = data
        }
        //下标脚本,下标索引为整形(注意也可以实现只有getter的只读下标脚本)
        subscript(index:Int) -> String{
            get{
                //字典的key进行排序后根据Index整形索引获取字典的值
                var key = sorted(Array(self.store.keys))[index]
                return self.store[key]!
            }
            set{
                //字典的key进行排序后根据Index整形索引设置字典的值
                var key = sorted(Array(self.store.keys))[index]
                self.store[key] = newValue //newValue和属性一样使用
            }
        }
        //下标脚本,下标索引为字符串
        subscript(key:String) -> String{
            get{
                return store[key]!
            }
            set{
                store[key] = newValue
            }
        }
    }
    //创建对象
    var record = Record(data:["name":"liuting","sex":"male"])
    println("r[0]=(record[0])") //结果:r[0]=liuting
    record["sex"] = "female"
    println(record["sex"]) //结果:female

    五、继承

    和ObjC一样,Swift也是单继承的(可以实现多个协议,此时协议放在后面),子类可以调用父类的属性、方法,重写父类的方法,添加属性监视器,甚至可以将只读属性重写成读写属性。

    //定义一个父类
    class Person {
        var firstName:String
        var lastName:String
        var age:Int = 0
        var fullName:String{
            get{
                return firstName + " " + lastName
            }
        }
        //指定构造方法
        init(firstName:String,lastName:String){
            self.firstName = firstName
            self.lastName = lastName
        }
        //对象方法
        func showMessage(){
            println("name=(self.fullName),age=(self.age)")
        }
        //通过final声明,子类无法重写
        final func sayHello(){
            println("hello world.")
        }
    }
    //定义子类
    class Student: Person {
        //重写属性,为属性添加监视器,重写都需要加override关键字
        override var firstName:String{
            willSet{
                println("firstName willSet")
            }
            didSet{
                println("firstName didSet")
            }
        }
        //添加子类属性
        var score:Double
         
        //子类指定构造方法一定要调用父类构造方法
        //并且必须在子类存储属性初始化之后调用父类构造方法
        init(firstName:String, lastName:String, score:Double){
            self.score = score
            super.init(firstName: firstName, lastName: lastName)
        }
        //便利构造方法
        convenience init(){
            self.init(firstName:"", lastName:"", score:0)
        }
        //将只读属性重写成了可写属性
        override var fullName:String{
            get{
                return super.fullName;
            }
            set{
                let array = split(newValue, maxSplit: Int.max, 
                                    allowEmptySlices: false, 
                                         isSeparator: { $0 == "." })
                if array.count == 2 {
                    firstName = array[0]
                    lastName = array[1]
                }
            }
        }
        //重写对象方法
        override func showMessage() {
            println("name=(self.fullName),age=(self.age),score=(self.score)")
        }
         
    }
    //创建子类对象
    var p = Student()
    p.firstName = "liu"
    p.showMessage() //结果:name=liu,age=0,score=0
    p.fullName = "Liu.Ting"
    p.showMessage() //结果:name=Liu.Ting,age=0,score=0
    p.sayHello()
    1. 只有指定构造方法才能调用父类的构造方法。
    2. 如果父类中存在有参数的指定构造方法,子类的指定构造方法不会自动调用父类无参的指定构造方法。
    3. 如果父类仅有一个无参构造方法(不管是否包含便利构造方法),子类的构造方法默认就会自动调用父类的无参构造方法(这种情况下可以不用手动调用)。
    4. 常量属性只能在定义它的类的构造方法中初始化,不能在子类中初始化
    5. 一个对象被释放前,先自动调用自己的析构方法,然后一层一层往上调用父类的析构方法。
    6. 便利构造方法必须调用同一个类中的其他指定构造方法(可以是指定构造方法或者便利构造方法),不能直接调用父类构造方法。
  • 相关阅读:
    Notes of Daily Scrum Meeting(12.18)
    Notes of Daily Scrum Meeting(12.17)
    Notes of Daily Scrum Meeting(12.16)
    Notes of Daily Scrum Meeting(12.8)
    Notes of Daily Scrum Meeting(12.5)
    Notes of Daily Scrum Meeting(12.3)
    Notes of Daily Scrum Meeting(11.12)
    Linux中profile、bashrc、bash_profile之间的区别和联系
    Linux GCC编译
    mysql 5.7.16 远程连接
  • 原文地址:https://www.cnblogs.com/ming1025/p/6072689.html
Copyright © 2011-2022 走看看