SwiftNote-9
2016年05月09日 Swift

方法

同其他面向对象语言的成员方法,细节略有不同

  • 实例方法

    属于某个类实例,与类型方法相对应,实例化某个类实例出来之后,才可以使用类实例进行调用。(结构体与枚举也可以定义方法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class Person
    {
    var name:String = "Jack"
    var age:Int = 15
    var education:String = "MiddleSchool"
    // instance method
    func introduceSelf()
    {
    print("Hello, Everyone! My name is \(self.name), I am \(age) years old.")
    }
    func growUp(age:Int, _ education:String)
    {
    self.age = age
    self.education = education
    }
    }

    let p = Person()
    p.introduceSelf()
    // 第一个参数不需要外部参数名,第二个及之后的需要外部参数名
    p.growUp(18, "College")

    introduceSelf方法就是针对第个生成出来的Person的具体实例的,因为不同的person的属性是不同的。self与C++中的this意义相同,就指代当前的对象。

    方法参数,Swift默认给除了第一个参数之外的参数一个外部参数名,不指定外部参数名的情况下与局部参数相同,这里Swift的默认行为,如果不想有外部参数名,可以使用_(下划线)显式忽略掉对应的外部参数名,这样就会覆盖掉Swift的默认行为。如上例中的growUp方法,显式忽略第二个参数的外部参数名。

    值类型的实例方法不能修改实例属性, 结构体,枚举值类型的实例方法不能修改实例内部的属性,如果需要修改,需在方法前加可变的关键字mutating,否则会报错

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    struct Rect
    {
    var wid = 0, hgt = 0
    mutating func modifyWid(wid:Int)
    {
    self.wid = wid
    }
    func modifyHgtTedt(hgt:Int)
    {
    // self.hgt = hgt 这里会报错
    }
    mutating func modifySelf(wid:Int, hgt:Int)
    {
    self = Rect(wid: wid, hgt: hgt)
    }
    }

    var r = Rect(wid: 100, hgt: 100)
    r.modifyWid(10)
    print(r.wid) // 输出10
    // 修改self的值
    r.modifySelf(120, hgt: 30)
    print(r.hgt) // 输出30

    可变方法中可以直接修改self的值,也就是自身实例的值可以在可变方法中直接修改。上例中的modifySelf方法,可直接给self赋值

  • 类型方法

    区别于实例方法,不需要生成实例即可调用,属性类级别的,直接使用ClassName.StaticMethod()的形式调用即可。方法定义使用static在func关键字前面。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class StaticTest
    {
    static var staticInt:String = "Static Variable"
    static func ClassTypeMethod()
    {
    print(self.staticInt)
    }
    }
    // 直接使用类名调用
    StaticTest.ClassTypeMethod()

    同类型差不多,如果需要子类重写对应的类型方法,不使用static而使用class关键字

下标

Swift中可以自定义类的中括号的实现,类似字典和数组那样的形式,使用subscript关键字,参数没有限制(包括个数与类型都没有限制),内部实现就像getter与setter。

  • 下标语法

    就像多了一层大括号的setter与getter实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class Test
    {
    subscript(row:Int, col:Int, ex:String) -> String
    {
    set{
    print(newValue) // newValue的值类型必须与返回值类型相同,这里是String
    }
    get{
    if row < 5 && col < 5
    {
    return "1 2 3 4"
    }
    else
    {
    return "More than 5"
    }
    }
    }
    }

    let t = Test()
    print(t[5, 3, "3"])
    t[3, 3, "4"] = "Test"
  • 下标使用事项

    下标参数可以是变量或者变参,但是不是是inout类型的,数量类型不限,也不可以设置参数默认值。可以有多个下标实现,Swift会根据不同的入参类型进行判定调用哪一个。

继承

这个特性只有类有,结构体与枚举不存在继承这一说。Swift的类继承在定义类时,类名后使用:(冒号)后面是基类名。

1
2
3
4
class SubClass:BaseClass
{
// some code
}
  • 基类

    一个没有继承其他任何类的类就是基类,它可能不被继承,也可能被继承,上边例子里面的Person就是一个基类。

  • 子类

    通过上述语法继承一个基类,这个类就是子类,子类拥有基类的的所有特性,并且还可以继续添加子类自己的特性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class Person
    {
    var name:String = "Jack"
    var age:Int = 15
    var education:String = "MiddleSchool"
    func introduceSelf()
    {
    print("Hello, Everyone! My name is \(self.name), I am \(age) years old.")
    }
    func growUp(age:Int, education:String)
    {
    self.age = age
    self.education = education
    }
    }
    class Programmer:Person
    {
    var codingSkill = "code"
    func codingWith(lang:String)
    {
    print("DO NOT TOUCH ME, I am coding with \(lang) language!")
    }
    }

    let p = Programmer()
    p.introduceSelf() // 继承了Person的属性和方法,正常调用
    p.codingWith("Swift") // 自己添加的新行为,coding
  • 重写

    子类可以把继承过来的计算属性/属性观察器(不能同时重写setter和属性观察器,setter里就可以观察到属性变化了),方法,下标,都按子类的规则重新实现,叫做重写。就是覆盖了基类的实现,再次调用的时候就是子类自己的实现。使用override关键字,访问基类使用super关键字,比如在重写的过程中,需要先调用一下基类的实现,可以直接使用super.implement()这种形式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    class Person
    {
    var name:String = "Jack"
    var age:Int = 15
    var education:String = "MiddleSchool"
    var address:String
    {
    get{
    return ""
    }
    }
    func introduceSelf()
    {
    print("Hello, Everyone! My name is \(self.name), I am \(age) years old.")
    }
    func growUp(age:Int, education:String)
    {
    self.age = age
    self.education = education
    }
    }
    class Programmer:Person
    {
    // 重写了基类的address计算属性的get
    override var address:String
    {
    get{
    return "Computer"
    }
    }
    var codingSkill = "code"
    func codingWith(lang:String)
    {
    print("DO NOT TOUCH ME, I am coding with \(lang) language!")
    }
    override func introduceSelf()
    {
    super.introduceSelf() // 使用super来访问基类
    print("... And I am a PROGRAMMER, I am changing the world!")
    }
    }

    let person = Person()
    person.introduceSelf()
    print(person.address)

    let p = Programmer()
    p.introduceSelf() // 程序员的自我介绍与Person不同了
    p.codingWith("Swift")
    print(p.address)// 重写了计算属性的getter
  • 禁止重写

    基类中使用final关键字,防止子类重写此特性。同样适用于计算属性,属性观察器,方法,下标,如果一个类不想被继承,直接在class关键字前使用final,类即不可以被继承。试图重写被final标记的属性,方法,下标,继续被final标记的类,都会直接报错。