Cowboy Tech

Swift面向对象基础(中)

存储属性

特点

  1. 存储在类,结构体里的变量或者常量,有两种:实例存储属性和类型存储属性
  2. 初始值要么在构造器中,要么在就直接赋予,可选类型的存储属性可以不指定初始值
  3. 系统会提供两个构造器:一个无参数的构造器和一个初始化所有实例存储属性的构造器。

结构体实例存储属性

struct LengthRange {
var start: Int
//定义常量存储属性,可以不指定初始值
let length:Int
}

var len = LengthRange(start:9, length:3)
//通过构造器参数完成实例存储属性的初始化
print("len的起点为\(len.start),长度为\(len.length)")

len.start = 2
//len.length = 4 //这个会报错,因为是常量,常量是不能修改的

计算属性

语法

[修饰符]var计算属性名:属性类型{
get{
//get方法执行体,该方法一定要有返回值
}

set(形参名){
setter方法执行体,该方法一定不能有返回值
}

}

例子1

class User{
var first:String = ""
var last:String = ""

//定义计算属性
var fullName:String{

    //定义计算属性的getter方法,该方法的返回值由first,last两个存储属性决定
    get{
        return first + "-" + last
    }

    //定义计算属性的setter方法
    //该setter方法将负责改变该实例的first,last两个存储属性
    set(newValue){
        var names = newValue.componentsSeparatedByString("-")
        self.first = names[0]
        self.last = names [1]
    }
}

init(first:String, last:String){
    self.first = first
    self.last = last
}
}

let s = User(first:"极客",last:"Hello")
//print(s.fullName) //结果是:极客-Hello

s.fullName = "极客-学院"
print(s.first)  //outcome is 极客
print(s.last)   //结果是 学院

例子2 只读属性

无需set部分,可以省略get和花括号

class User{
var first:String = ""
var last:String = ""

//定义计算属性
var fullName:String{

//定义计算属性的getter方法,该方法的返回值由first,last两个存储属性决定
   return first + "-" + last

}

init(first:String, last:String){
   self.first = first
   self.last = last
}

}

属性观察者

语法

[修饰符]var 计算属性名:属性类型 = 初始值 {
  willSet (newValue){
  //属性即将被赋值之前自动调用的方法

  }

  didSet(oldValue){
  //属性被赋值完成之后自动调用的方法

  }
}
  1. 除了延迟存储属性之外的所有存储属性(包括实例存储属性和类型存储属性)
  2. 可通过重载方式为继承得到的属性(包括存储属性和计算属性)添加属性观察者。

例子

class Person {
//定义存储属性
var name: String = ""{

    willSet{

        if(newValue.characters.count > 6 || newValue.characters.count < 2){
            print("您设置的人名\(newValue)不符合要求,请重新设置!")
        }else{
            print("人名设置符合要求,设置成功")
        }
    }

    didSet{
        print("人名设置完成,被修改的原名为:\(oldValue)")
    }
}

var age: Int = 0{

    willSet{
        if newValue > 100 || newValue < 0{
            print("您设置的年龄\(newValue)不符合要求,请重新设置!")
        }else{
            print("年龄设置符合要求,设置成功")
        }
    }

    didSet {
        print("年龄设置完成,被修改的年龄为:\(oldValue)")
    }
}
}

var p = Person()
//p.age = 999  //不成功的设置,先调用willSet,再调用didSet
p.age = 10 // 成功的设置
print("成功设置年龄后,年龄为\(p.age)")  

方法

类型方法:枚举,结构体中方法使用static修饰,类中用class修饰,否则的话属于实例方法

将方法转换为函数

class SomeClass {

func test() {
    print("==test 方法==")
}

class func bar(msg:String) {
    print("==bar类型方法==,传入的参数为:\(msg)")
}
}

var sc = SomeClass()     //创建实例
var f1:()->()=sc.test    //将sc的test方法分离成函数

var f2:(String) -> Void = SomeClass.bar    //将sc的bar方法分离成函数,定义一个函数型的变量并赋值
//f1()    //等价于sc.test()
f2("极客")  //等价于SomeClass.bar(msg:"Geek")

方法形参名省略用 “_”

默认除第一个参数外都添加了外部参数名,与局部参数名一样,如果不需要的话,则用_下划线的方式去掉

class Person {

var name:String

init(name:String){
    self.name = name
}

func eat (food:String, _ drink:String, cigarette:String){
    print("\(self.name)吃着\(food),喝着\(drink),抽着\(cigarette)")
}
}

var p = Person(name:"Tom")
p.eat("烤鸭","啤酒",cigarette:"雪茄")

值类型的可变方法可以改变存储属性

struct JKRect {
var x: Int
var y: Int
var width:Int
var height:Int
mutating func moveByX(x:Int,y:Int){
    self.x += x
    self.y += y
}
}

var rect = JKRect(x:20, y:12, width:200, height:300)   //创建实例
rect.moveByX(100, y:90)   //调用mutating方法,该方法可以改变rect实例的存储属性
print("rect矩形的左上角的x坐标为:\(rect.x),y坐标为:\(rect.y)")
  1. 将mutating关键字放在func之前,即将该方法声明为可变方法
  2. 常量类型的结构体,枚举是不可变的,比如上述的var 改成 let就不行了

属性和方法的统一

使用函数类型定义存储属性,并将函数或者闭包作为该属性的初始值,这个属性就成了方法

func factorial(n:Int) -> Int {
var result = 1
for i in 1...n {
    result *= i
}
return result
}

struct SomeStruct {
var info:() -> Void = {
    print("info方法")
}
//将全局函数作为fact存储属性的初始值
static var fact:(Int) -> Int = factorial
}

var sc = SomeStruct()
//调用info方法
//sc.info()  //outcome is info方法

//使用闭包对sc对象的info赋值,相当于重新定义sc的info方法
sc.info = {
print("另外一个闭包")
}

//sc.info()  //outcome is 另外一个闭包

var n = 6

//调用fact方法,执行的是阶乘
//print("\(n)的阶乘是:\(SomeStruct.fact(6))") //Outcome is 720

//使用闭包对SomeStruct的fact赋值,相当于重新定义SomeStruct的fact方法
SomeStruct.fact = {
var result = 1
for i in 1...$0 {
    result += i
}
return result
}

//再次调用fact方法,执行的是累加
print("\(n)的累加的和是:\(SomeStruct.fact(6))") //outcome is 22

下标

  1. 所有的Swift类型(枚举,类,结构体)都支持定义下标
  2. 同一个类型可以定义多个下标,通过下标的形参列表或者返回值类型来区分不同的下标
  3. 同一类型中定义多个不同的下标被称为下标重载
  4. 形参列表:与函数的形参列表的用法基本相同,但是不支持指定外部参数和默认值
  5. 下标的返回值类型:可以是任何有效的类型
1
2
3
4
5
6
7
8
Subscripe(形参列表) ->下标返回值类型 {
get {
//getter方法执行体,该方法必须有返回值
}
set(形参名){
//setter方法执行体,该方法不能有返回值
}
}
struct JKRect2{
var x:Int
var y:Int
var width:Int
var height:Int

//定义下标,指定下标只接受一个Int类型的参数,下标的返回类型为Int

subscript(index:Int) ->Int {

    get{
        switch(index){
        case 0:
            return self.x
        case 1:
            return self.y
        case 2:
            return self.width
        case 3:
            return self.height
        default:
            print("不支持该索引值")
            return 0
        }
    }

    set{
        switch(index){
        case 0:
            self.x = newValue
        case 1:
            self.y = newValue
        case 2:
            self.width = newValue
        case 3:
            self.height = newValue
        default:
            print("不支持该索引值")
        }
    }
}
}

//创建实例
var rect2 = JKRect2(x:20,y:12,width:200,height:300)

//通过下标进行赋值
//rect2[0] = 40
//rect2[1] = 67

//通过下标访问rect的属性
print("rect2矩形的左上角的x坐标为:\(rect2[0]),y坐标为:\(rect2[1])")