Swift -5 面向对象基础(中)

存储属性与计算属性

1.实例存储属性与实例变量
2.结构体常量与实例属性
3.定义计算属性
4.setter方法
5.属性观察者

存储属性:存储在类.结构体里的变量或者常量
分为:实例存储属性.类型存储属性
所有的存储属性必须显示的指定初始值,在定义时或者构造器当中指定
可选类型的存储属性可以不指定初始值

结构体中实例存储属性的规则
1.程序为所有的实例存储属性指定了初始值,且没有构造器,则系统会提供两个构造器:一个无参数的构造器和一个初始化所有实例存储属性的构造器
2.没有初始值和构造器,系统会提供一个初始化所有实例存储属性的构造器
3.有构造器,则程序必须为结构体中的所有存储属性提供初始值

存储属性

struct LengthRange{
    var start: Int
    // 定义常量存储属性,可以不指定初始值
    let length: Int
}
var len = LengthRange(start: 9, length: 3)
// 通过构造器参数完成实例存储属性的初始化
print("len的起点为\(len.start), 长度为\(len.length)")

// 结构体常量与实例属性
struct LengthRange2{
    var start: Int
    var length: Int
}
let len2 = LengthRange2(start: 1, length: 5)

// 延迟存储属性:第一次被调用时候才会被计算初始值的属性,用lazy修饰符

计算属性

/*
    [修饰符]var 计算属性名: 属性类型{
        get{
    // get方法执行体,该方法一定要有返回值
    }
        set(形参名){
    // setter方法执行体,该方法一定不能有返回值
    }
}
*/
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: "Devin", last: "hello")
print(s.fullName)
s.fullName = "Devin-Hello"
print(s.first)
print(s.last)

// 只读属性,则无需set部分,可以省略get和花括号

属性观察者

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

/*
    [修饰符]var 计算属性名: 属性类型 = 初始值{
    willSet(newValue){
            // 属性即将被赋值之前自动调用的方法
    }
    didSet(oldValue){
            // 属性被赋值完成之后自动调用的方法
    }
}
注意:willSet和didSet后的参数都可以省略
*/
/*
    willSet(newValue): 被观察的属性即将被赋值之前自动调用的方法
    didSet(oldValue): 被观察的属性被赋值完成之后自动调用的方法
*/
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 // 不成功设置
// 成功设置age属性后
p.age = 10
print("成功设置age属性后, age为\(p.age)")

方法

方法的所属性

1.定义方法需要在类型(枚举.结构体.类)里定义,不能独立定义
2.方法要么属于该类型本身,要么是该类型的一个实例
3.不能独立执行方法,执行方法必须使用类型或实例作为调用者
注意:枚举.结构体中方法使用static修饰,类中用class修饰,都属于类型方法,否则的话属于实例方法

将方法转换为函数

class SomeClass {
    func test() {
        print("===test 方法===")
    }
    class func bar(msg msg: String) {
        print("==bar类型方法==, 传入的参数为:\(msg)")
    }
}
// 创建实例
var sc = SomeClass()
// 将sc的test方法分离成函数
var f1: () -> () = sc.test
// 将sc的bar方法分离成函数
var f2:(String) -> Void = SomeClass.bar
f1() // 等价于sc.test()
sc.test()
f2("Devin") // 等价于SomeClass.bar(msg:"Devin")
SomeClass.bar(msg: "Devin")

方法的外部形参名

class Person1 {
    var name: String
    //
    init(name: String) {
        self.name = name
    }
    //
    func eat(food: String, _ drink: String, _ cigarette: String) {
        print("\(self.name)吃着\(food), 喝着\(drink), 抽着\(cigarette)")
    }
}
var p1 = Person1(name: "Devin")
p1.eat("烤鸭", "啤酒", "雪茄")
// Swift默认为除第一个参数外都添加了外部参数名,与局部参数名一样,如果不需要的话,则用 _ 下划线的方式去掉

值类型的可变方法

将mutating关键字放在func之前,即将该方法声明为可变方法

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)
// 调用mutating方法,该方法可以改变rect实例的存储属性
rect.moveByX(100, y: 90)
print("rect矩形的左上角的x坐标为:\(rect.x), y坐标为:\(rect.y)")
// 注意:常量类型的结构体.枚举是不可变的

属性和方法的统一

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

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 sc1 = SomeStruct()
// 调用info方法
//sc1.info()

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

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

// 使用闭包对SomeStruct的fact赋值,相当于重新定义SomeStruct的方法
SomeStruct.fact = {
    var result = 1
    for i in 1...$0 {
        result += i
    }
    return result
}
// 再次调用fact方法,执行的是累加
print("\(n)的累加的和是:\(SomeStruct.fact(6))")

下标

1.下标的基本用法
2.下标重载

1.所有的Swift类型(枚举.类和结构体)都支持下标定义
2.同一个类型可以定义多个下标
3.通过下标的形参列表或者返回值类型来区分不同的下标
4.同一类型中定义多个不同的下标被称为下标重载

/*
    Subscript(形参列表) -> 下标返回值类型 {
        get {
            // getter方法执行体,该方法必须有返回值
        }
        set(形参名) {
            // setter方法执行体,该方法不能有返回值
        }
    }
*/

// 1.形参列表:与函数的形参列表的用法基本相同,但是不支持指定外部参数和默认值
// 2.下标的返回值类型:可以是任何有效的类型


struct JKRect2 {
    var x: Int
    var y: Int
    var width: Int
    var height: Int

    // 定义下标,指定下标只接受一个Int类型的参数,下标的返回类型为Int
    subscript(index: Int) -> Int {
        // get部分
        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部分
        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.x), y坐标为:\(rect2.y)")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值