Swift - 类、属性、方法

作者: Albert_Li99 | 来源:发表于2017-12-04 17:42 被阅读1071次

    一、类

    Swift类是构建代码所用的一种通用且灵活的构造体。
    我们可以为类定义属性(常量、变量)和方法。
    与其他编程语言所不同的是,Swift并不要求你为自定义类去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类,系统会自动生成面向其他代码的外部接口。

    类和结构体对比

    Swift中类和结构体有很多共同点。共同处在于:
    1.定义属性用于存储值。
    2.定义方法用于提供功能。
    3.定义附属脚本用于访问值。
    4.定义构造器用于生成初始化值。
    5.通过扩展以增加默认实现的功能。
    6.符合协议以对某类提供能标准功能。

    与结构体相比,类还有如下的附加功能:

    1.继承允许一个类继承另一个类的特征。
    2.类型转换允许在运行时检查和解释一个类实例的类型。
    3.解构器允许一个类实例释放任何其所被分配的资源。
    4.引用计数器允许对一个类的多次引用。

    语法:

    class className {
        Definition 1
        Definition 2
        ......
        Definition N
    }
    

    类定义

    class student {
        var studentName : String
        var mark1 : Int
        var mark2 : Int
    }
    

    实例化类:

    let studentRecord = student()
    

    实例:

    class MarksStruct {
         var mark : Int
         init(mark : Int) {
             self.mark = mark
        }
    }
    
    class studentMarks {
          var mark = 300
    }
    let marks = studentMarks()
    print("成绩为\(marks.mark)")
    

    以上程序的执行结果为:

    成绩为 300
    

    作为引用类型访问类属性

    类属性可以通过,来访问。格式为:实例化类名.属性名:

    class MarksStruct {
        var mark : Int
        init(mark : Int) {
            self.mark = mark
        }
    }
    
    class studentMarks {
        var mark1 = 300
        var mark2 = 400
        var mark3 = 900
    }
    let marks = studentMarks()
    print("Mark is \(marks.mark1)")  
    print("Mark is \(marks.mark2)")
    print("Mark is \(marks.mark3)")
    

    以上程序执行输出结果:

    Mark1 is 300
    Mark2 is 400
    Mark3 is 900
    

    恒等运算符

    因为类是引用类型,有可能有多个常量和变量在后台同时引用某一个实例。
    为了能够判断两个常量或者变量是否引用同一个类实例,Swift内建了两个恒等运算符。


    实例

    class SampleClass : EquaTable {
        let myProperty : String
        init(s : Sting) {
            myProperty = s  
        }
    }
    
    func == (lhs: SampleClass, rhs: SampleClass) -> Bool {
        return lhs.myProperty == rhs.myProperty
    }
    
    let spClass1 = SampleClass(s : "Hello") 
    let spClass2 = SampleClass(s : "Hello")
    
    if spClass1 === spClass2 {
        print("引用相同的类实例\(spClass1)")
    }
    
    if spClass1 !== spClass2 {
        print("引用不相同的类实例\(spClass2)")
    }
    

    以上程序执行输出结果为:

    引用不相同的类实例:SampleClass
    

    二、属性

    Swift属性将值与特定的类、结构或枚举关联。
    属性可分为存储属性和计算属性:



    存储属性和计算属性通常用于特定类型的实例。
    属性也可以直接用于类型本身,这种属性称为类型属性。
    另外,还可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。

    存储属性

    简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。
    存储属性可以是变量存储属性(用关键字var定义),也可以是常量存储属性(用关键字let定义)。
    1.可以在定义存储属性的时候指定默认值。
    2.也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值。

    struct Number {
        var digits : Int
        let pi = 3.1415
    }
    
    var n = Number(digits: 12345)
    n.digits = 67
    print("\(n.digits)")
    print("\(n.pi)")
    

    以上程序执行输出结构为:

    67
    3.1415
    

    考虑一下代码:

    let pi = 3.1415
    

    代码中pi定义存储属性的时候指定默认值(pi = 3.1415),所以不管你什么时候实例化结构体,它都不会改变。如果你定义的是一个常量存储属性,如果尝试修改它就会报错,如下所示:

    struct Number {
        var digits : Int
        let numbers = 3.1415
    }
    
    var n = Number(digits: 12345)
    n.digits = 67
    print("\(n.digits)")
    print("\(n.numbers)")
    n.numbers = 8.7
    

    以上程序执行将会报错,错误如下所示:

    error: cannot assign to property: 'numbers' is a 'let' constant
    n.numbers = 8.7
    

    意思为‘numbers’是一个常量,你不能修改它。

    延迟存储属性

    延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。
    在属性声明前使用lazy来标示一个延迟存储属性。
    注意:
    必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
    延迟存储属性一般用于:
    1.延迟对象的创建。
    2.当属性的值依赖于其他未知类

    class sample {
        lazy var no = number()
    }
    
    class number {
        var name = "Apple"
    }
    
    var firstSample = sample()
    print(firstSample.no.name)
    

    以上程序执行输出结果为:

    Apple
    

    实例化变量

    如果您有过OC经验,应该知道OC为类实例存储值和引用提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。
    Swift编程语言中把这些理论统一用属性来实现。Swift中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。
    一个类型中属性的全部信息一一包括命名、类型和内存管理特征--都在唯一一个地方(类型定义中)定义。

    计算属性

    除存储属性外,类、结构体和枚举可以定义计算属性,计算属性不直接存储值,而是提供一个getter来获取值,一个可选的setter来间接设置其他属性或变量。

    class sample {
        var nol = 0.0, no2 = 0.0
        var length = 300.0, breadth = 150.0
        var middle: (Double, Double) {
            get {
                return (length / 2, breadth / 2)
            }
            set(axis) {
                no1 = axis.0 - (length / 2)
                no2 = axis.1 - (length / 2)
            }
        }
    }
    
    var result = sample()
    print(result.middle)
    result.middle = (0.0, 10.0)
    print(result.no1)
    print(result.no2)
    

    以上程序执行输出结果为:

    (150.0,75.0)
    -150.0
    -65.0
    

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

    只读计算属性

    只有getter没有setter的计算属性就是只读计算属性。
    只读计算属性总是返回一个值,可以通过点(.)运算符访问,单但不能设置新的值。

    class film {
        var head = ""
        var duration = 0.0
        var metaInfo: [String : String] {
            return [
                "head" : self.head,
                "duration" : "\(self,duration)"
            ]
        }
    }
    var movie = film()
    movie.head = "Swift属性"
    movie.duration = 3.09
    print(movie.metaInfo["head"]!)
    print(movie.metaInfo["duration"]!)
    

    以上程序执行输出结果为:

    Swift属性
    3.09
    

    注意:
    必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。

    属性观察器

    属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。
    可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。
    注意:
    不需要为无法重载的计算属性添加属性观察器,因为可以通过setter直接监控和响应值的变化。
    可以为属性添加如下的一个或全部观察器:
    1.willSet在设置新的值之前调用。
    2.didSet在新的值被设置之后立即调用。
    3.willSet和didSet观察器在属性初始化过程中不会被调用。

    class Samplepgm {
        var counter : Int = 0 {
            willSet(newTotal) {
                print("计数器:\(newTotal)")
            }
            didSet {
                if counter > oldValue {
                    print("新增数\(counter - oldValue)")
                }
            }
        }
    }
    let NewCounter = Samplepgm()
    NewCounter.counter = 100
    NewCounter.counter = 800
    

    以上程序执行输出结果为:

    计数器:100
    新增数:100
    计数器:800
    新增数:700
    

    全局变量和局部变量

    计算属性和属性观察器所描述的模式也可以用于全局变量和局部变量。


    类型属性

    类型属性是作为类型定义的一部分写在类型最外层的花括号({})内。
    使用关键字static来定义值类型的类型属性,关键字class来为类定义类型属性。

      struct StructName {
          static var storedTypeProperty = " "
          static var computedTypeProperty: Int {
              //返回一个Int值
          }
      }
    
      enum Enumname {
          static var storedTypeProperty = ""
          static var computedTypeProperty: Int {
              //返回一个Int值
          }
      }
    
     class Classname {
         class var computedTypeProperty: Int {
             //返回一个Int值
         }
     }
    

    注意:
    例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。

    获取和设置类型属性的值

    类似于实例的属性,类型属性的访问也是通过点运算符(.)来进行。但是,类型属性是通过类型本身来获取和设置,而不是通过实例。实例如下:

    struct StudentMarks {
        static let markCount = 97
        static var totalCount = 0
        var InternalMarks: Int = 0 {
            didSet {
                if InternalMarks > StudentMarks.markCount {
                    InternalMarks = StudentMarks.markCount
                }
    
                if InternalMarks > StudentMarks.totalCount {
                    StudentMarks.totalCount = InternalMarks
                }
            }
        }
    }
    var studentMark1 = StudentMarks()
    var studentMark2 = StudentMarks()
    
    student1Mark1.InternalMarks = 98
    print(studentMark1 > InternalMarks)
    
    student1Mark2.InternalMarks = 87
    print(studentMark2 > InternalMarks)
    

    以上程序执行输出结果为:

    97
    87
    

    三、方法

    Swift方法是与某些特定类型相关联的函数。
    在OC中,类唯一能定义方法的类型。但在Swift中,你不仅能选择是否要定义一个类、结构体、枚举,还能灵活的在你穿件的类型(类、结构体、枚举)上定义方法。

    实例方法

    在Swift语言中,实例方法是属于某个特定类、结构体或者枚举类型实例的方法。
    实例方法提供以下方法:
    1.可以访问和修改实例属性。
    2.提供与实例目的相关的功能。

    实例方法

    在Swift语言中,实例方法是属于缪戈特定类、结构体或者枚举类型实例的方法。
    实例方法提供以下方法:
    1.可以访问和修改实例属性。
    2.提供与实例目的相关的功能。
    实例方法要写在它所属的类型的前后大括号({})之间。
    实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。
    实例方法只能被它所属的类的某个特定实例调用。
    实例方法不能脱离于现存的实例而被调用。

    语法:

    func funcName(Parameters) -> returnType {
        Statement1
        Statement2
        ......
        StatementN
        return parameters
    }
    

    实例:

    class Counter {
        var count = 0
        func increment() {
            count += 1
        }
        func incrementBy(amount: Int) {
            count += amount
        }
        func reset() {
            count = 0
        }
    }
    //初始计数值是0
    let counter = Counter()
    //计数值现在是1
    counter.increment()
    //计数值现在是6
    counter.incrementBy(amount : 5)
    print(counter.count)
    //计数值现在是0
    counter.reset()
    print(counter.count)
    

    以上程序的执行结果为:

     6
     0
    

    Counter类定义了三个实例方法:
    1.increment让计数器按1递增。
    2.incrementBy(amount : Int)让计数器按一个指定的整数值递增。
    3.reset将计数器重置为0。
    Counter这个类还声明了一个可变属性count,用它来保持对当前计数器值的追踪。

    方法的局部参数名称和外部参数名称

    Swift函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用Swift中的方法和OC中的方法极其相似。像在OC中一样,Swift中方法的名称通常用一个介词指向方法的第一个参数,比如:with、for、by等等)。
    Swift默认仅给方法的第一个参数名称一个局部参数名称,默认同时给第二个和后续参数名称全局参数名称。
    以下实例中‘no1’在Swift中声明为局部参数名称。‘no2’用于全局的声明并通过外部程序访问。

    class division {
        var count: Int = 0
        func incrementBy(no1: Int, no2: Int) {
            count = no1 / no2
            print(count)
        }
    }
    
    let counter = division()
    counter.incrementBy(no1: 1800, no2: 3)
    counter.incrementBy(no1: 1900, no2: 2)
    counter.incrementBy(no1: 11100, no2: 2)
    

    以上程序执行的输出结果为:

    600
    950
    5550
    

    是否提供外部名称设置

    我们强制在第一个参数添加外部名称把这个局部名称当做外部名称使用(Swift2.0前是使用#号)。
    相反,我们呢也可以使用下划线(_)设置第二个及后续的参数不提供一个外部名称。

    class multiplication {
        var count: Int = 0
        func incrementBy(first no1: Int, no2: Int) {
            count = no1 * no2
            print(count)
        }
    }
    let counter = multipication()
    counter.incrementBy(first: 800, no2: 3)
    counter.incrementBy(first: 100, no2: 5)
    counter.incrementBy(first: 15000, no2: 3)
    

    以上程序执行输出结果为:

    2400
    500
    45000
    

    Self属性

    类型的每一个实例都有一个隐含属性叫做self,self完全等同于该实例本身。
    你可以在一个实例的实例方法中使用这个隐含的self属性来引用当前实例。

    class calculations {
        let a : Int
        let b : Int
        let res : Int 
    
        init(a: Int, b: Int) {
            self.a = a
            self.b = b
            res = a+b
            print("Self 内:\(res)")
        }
    
        func tot(c : Int) -> Int {
            return res - c
        }
    
        func result() {
            print("结果为:\(tot(c : 20))")
            print("结果为:\(tot(c : 50))")
        }
    }
    let pri = calculations(a: 600, b: 300)
    let sum = calculations(a: 1200, b: 300)
    pri.result()
    sum.result()
    

    以上程序执行输出结果为:

    Self内:900
    Self内:1500
    结果为:880
    结果为:850
    结果为:1480
    结果为:1450
    

    在实例方法中修改值类型

    Swift语言中结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。
    但是,如果你确实需要在某个具体的方法中修改结构体或者枚举的属性,你可以选择变异(mutating)这个方法,然后方法就可以从方法内部改变它的属性;并且它做的任何改变在方法结束时还会保留在原始结构中。
    方法还可以给它隐含得到self属性赋值一个全新的实例,这个新实例在方法结束后将替换原来的实例。

    struct area {
        var length = 1
        var breadth = 1
        func area() -> Int {
            return length * breadth
        }
        mutating func scaleBy(res: Int) {
            length *= res
            breadth *= res
            print(length)
            print(breadth)
        }
    }
    var val = area(length: 3, breadth: 5)
    var.scaleBy(res: 3)
    var.scaleBy(res: 30)
    var.scaleBy(res: 300)
    

    以上程序执行输出结果为:

    9
    15
    270
    450
    81000
    135000
    

    在可变方法中给self赋值

    可变方法能够赋给隐含属性self一个全新的实例。

    struct area {
        var length = 1
        var breadth = 1
        func area() -> Int {
            return length * breadth
        }
        mutating func scaleBy(res: Int) {
              self.length *= res
              self.breadth *= res
              print(length)
              print(breadth)
        }  
    }
    var val = area(length: 3, breadth: 5)
    var.scaleBy(res: 13)
    

    以上程序执行输出结果为:

    39
    65
    

    类型方法

    实例方法是被类型的某个实例调用的方法,你也可以定义类型本身调用的方法,这种方法就叫做类型方法。
    声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。类可能会用关键字class来允许子类重写父类的实现方法。
    类型方法和实例方法一样用点号(.)语法调用。

    class Math {
        class func abs(number: Int) -> Int {
            if number < 0 {
                return (-number)
            } else {
                return number
            }
        }
    }
    
    struct absno {
        static func abs(number : Int) -> Int {
            if number< 0 {
                return (-number)
            } else {
                return number
            }
        }
    }
    
    let no = Math.abs(number: -35)
    let num = absno.abs(number: -5)
    print(no)
    print(num)
    

    以上程序执行输出结果为:

    35
    5
    

    下一篇:“Swift - 继承” http://www.jianshu.com/p/39b5348f1f1b

    相关文章

      网友评论

        本文标题:Swift - 类、属性、方法

        本文链接:https://www.haomeiwen.com/subject/cblxixtx.html