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. 便利构造方法必须调用同一个类中的其他指定构造方法(可以是指定构造方法或者便利构造方法),不能直接调用父类构造方法。
  • 相关阅读:
    pytest-html报告自定义字段
    Python SMTP发送邮件
    IE浏览器兼容测试工具 IETester
    全局ID生成--雪花算法改进版
    全局ID生成--雪花算法
    spring-cloud-sleuth/zipkin
    14.跑批到某个点突然所有批都断批
    13.分布式锁在不同环境引发的坑
    spring-cloud-gateway
    spring-cloud-netflix-config
  • 原文地址:https://www.cnblogs.com/ming1025/p/6072689.html
Copyright © 2011-2022 走看看