//
// PropertyMethod.swift
// SwiftCode
//
// Created by Alisa on 2022/4/6.
// Copyright © 2022 Alisa. All rights reserved.
//
import Foundation
import UIKit
/*
**属性
属性:定义在类、结构体或者枚举中的量值
属性的分类:存储属性、计算属性
存储属性:作用---用于存储类的某个特征。
用于---类和结构体
类的存储属性可以被设置为延时存储属性,在实例构造的时候,延时存储属性并不进行构造和初始化,只有当开发者调用这个类实例属性时,此属性才
完成构造或初始化操作,延时存储属性可以减少一个复杂的类在初始化的时间
计算属性:作用---通过计算告知外界类的某个特征,描述计算过程并获取计算结果。
用于---类、结构体、枚举
计算属性中可以定义get与set方法,分别用来获取计算属性的值和设置计算属性的值,这与oc中的setter与getter是有区别的,不要混为一谈,
计算属性本身并没有存储值,它只是作为一个接口向外界提供某些经过计算后具有相应意义的数据
当计算属性只设置了get方法,那么它是个只读的计算属性
属性监听器:属性监听器用于监听存储属性赋值的过程,并且开发者可以在其中编写代码,添加额外的逻辑。
在属性的构造或初始化时,无论是通过构造方法进行属性构造或初始化,还是为属性设置默认值,都不会调用属性监听器的方法,初始化后从第二次为属性赋值开始,属性监听器才会被调用
实例属性:实例属性由类的实例调用,实例属性是与具体实例相关联的,一般用于描述类的实例的一些特性
类属性:类属性则直接由类来调用,类属性是与此类型相关联,用来描述整个类型的某些特性
类属性使用static或者class关键字来声明,使用static关键字声明的属性也被称为静态属性
如果允许子类对其计算方法进行覆写,则需要用class关键字来声明
注意:在使用时,子类修改了继承于父类的类属性值,那么整个父类的这个属性值都跟着改变了
属性包装器:属性包装器时swift5.1版本引入的新特性,使用属性包装器可以实现计算属性计算过程的复用
属性在使用时需要注意:
在一个类进行实例化时,被构造完成时,必须保证类中所有属性都构造或者初始化完成。
一般情况下我们会在创建的类中提供一个构造方法,用于设置其中的属性,但并不是所有情况都需要这么做,我们也可以为类中的属性在声明时就提供一个初始值。
**方法
方法:方法用来定义事物的行为,其实质是具有特殊意义的函数
方法可用于,类、结构体、枚举
方法的分类:实例方法、类方法。以及特殊的构造方法、析构方法
实例方法:作用---描述类型实例的行为
类方法:作用---描述整体类型的行为
实例方法:实例方法是由类的实例进行调用
开发者可以通过self来调用类的属性和其它实例方法,self其实也可以省略,我们可以直接通过方法名调用自身的实例方法,只是有时候属性名字可能会和
方法中的参数名称相同,使用self的方式调用实例方法可以避免歧义
注意:在实例方法中对引用类型的实例属性进行修改是没问题的,但是对于值类型的实例属性,读者需要额外的注意,使用mutating关键字修饰实例方法才能对其进行修改
类方法:类方法是由类型名直接调用,类方法是关联整个类型的,被整个类型所共享
类方法通过static和class关键字来声明,static关键字声明的类方法又被称为静态方法,其不能被子类覆写
而class关键字声明的类方法可以被类的子类覆写
下标方法:swift语言中的元组,如集合和数组等数据结构,它们可以通过下标的方式来获得其中的元素,我们使用下标方法可以使我们自定义的类型具有这样功能
**知识扩展
类的每个实例都默认隐藏着一个名为self的属性,可以简单理解为self就是实例本身
*/
//类的属性的使用,以及延时属性的使用
class Student{
var name:String
var age:Int
let sex:String
var schoolName:String
//创建一个延时属性
lazy var job:String = "teacher"
init(name:String, age:Int, sex:String, schoolName:String){
self.name = name
self.age = age
self.sex = sex
self.schoolName = schoolName
}
}
//计算属性的get、set方法的使用
class ShapeTime{
var r:Int
var l:Int{
get{
return r * r
}
set{
r = newValue / r //newValue为外界所设置的值
}
}
var s:Int{
get{
return 88
}
}
let name:String
init(r:Int, name:String) {
self.r = r
self.name = "std"
}
}
//属性监听器的使用
class Teacher{
var name:String{
//此属性将要赋值时会调用的方法
willSet{
//其中会默认生成一个newValue来接收外界传递进来的新值
print("将要设置值为:\(newValue)")
}
//此属性已经被赋值后会调用的方法
didSet{
//其中会默认生成一个oldValue来保存此属性的原始值
print("旧的值为:\(oldValue)")
}
}
var subject:String{
//这里可以设置传入的值的名字为自己喜欢的new
willSet(new){
print("将要设置值为new = \(new)")
}
//这里可以设置传入的值的名字为自己喜欢的old
didSet(old){
print("将要设置值为old = \(old)")
}
}
var age:Int
init(name:String, subject:String, age:Int){
self.age = age
self.name = name
self.subject = subject
}
}
//属性包装器的使用
@propertyWrapper
struct MoreThanZero{
private var number:Int
init(){
self.number = 0
}
var wrappedValue:Int{
get{
return number
}
set{
if newValue < 0{
self.number = 1
}
else{
self.number = newValue
}
}
}
}
@propertyWrapper
struct NotEmptyString{
private var value:String
init(){
self.value = "dafault"
}
var wrappedValue:String{
get{
return value
}
set{
if newValue.count > 0{
self.value = newValue
}
else{
self.value = "default value"
}
}
}
}
class Member:CustomStringConvertible{
private var name:String
private var age:Int
init() {
self.name = "default"
self.age = 0
}
//使用属性包装器来定义计算属性
@NotEmptyString var memberName:String
@MoreThanZero var memberAge:Int
var description:String{
return "\(self.memberName):\(self.memberAge)"
}
}
//实例属性与类属性的使用
class SomeClass{
//静态存储属性
static var className = "SomeClass"
//静态计算属性
static var subName:String{
return "sub" + className
}
class var classSubName:String{
return "class" + subName
}
}
class SubClass:SomeClass{
//对计算类属性的计算方法进行覆写,覆写需要使用override关键字
override class var classSubName: String{
return "newNme"
}
}
//实例方法与类方法的使用
class Math{
static var x_value:Double = 10
static var y_value:Double = 10
//提供一个加法的实例方法
func add(param1:Double, param2:Double)->Double{
return param1 + param2
}
//提供一个求和的平方的实例方法
func sqr(param1:Double, param2:Double)->Double{
//调用自身的其它实例方法
return self.add(param1: param1, param2: param2) * self.add(param1: param1, param2: param2)
}
//类方法
class func movePoint(x:Double, y:Double){
//静态属性,也可以使用self调用
self.x_value += x
self.y_value += y
print("current super x_value = \(self.x_value), y_value = \(self.y_value)")
}
}
class MathPoint:Math{
override class func movePoint(x:Double, y:Double){
super.movePoint(x: x, y: y)
self.x_value += 5
self.y_value += 5
print("current subclass x_value = \(self.x_value), y_value = \(self.y_value)")
}
}
//结构体中的实例方法,使用值类型的实例属性时,使用mutating
struct Point{
var x:Double
var y:Double
//将点进行移动,因为修改了属性的值,需要用mutating修饰方法
mutating func move(x:Double, y:Double){
self.x += x
self.y += y
print("current x:\(self.x), current y: \(self.y)")
}
}
//下标方法的使用
class MyArray{
var array:Array<Int>
init(param:Int...) {
array = param
}
//subscript是swift语言中用于定义下标功能的方法
subscript(index:Int)->Int{
set{
//默认外界设置的值会以newValue为名称传入,开发者也可以自定义
array[index] = newValue
}
get{
return array[index]
}
}
}
class PropertyMethod{
//类的属性的使用
func useClassProperty(){
//声明一个变量var类型的类的实例
var stu = Student(name: "jone", age: 12, sex: "man", schoolName: "AEC")
print("student age is:\(stu.age)")
//变量类型的属性值可以修改
stu.age = 14
//常量类型的属性的值是不可以修改的
//stu.sex = "woman" //Cannot assign to property: 'sex' is a 'let' constant
print("student age is:\(stu.age)")
//声明一个常量let类型的类的实例
let stuTwo = Student(name: "Pony", age: 22, sex: "man", schoolName: "EC")
print("student Two age is:\(stuTwo.age)")
//变量类型的属性值可以修改
stuTwo.age = 16
//常量类型的属性的值是不可以修改的
//stuTwo.sex = "woman" //Cannot assign to property: 'sex' is a 'let' constant
print("student Two age is:\(stuTwo.age)")
//创建一个引用变量
let stuThree = stu
print("student Three age is:\(stuThree.age)")
//变量类型的属性值可以修改
stuThree.age = 18
//常量类型的属性的值是不可以修改的
//stuThree.sex = "woman" //Cannot assign to property: 'sex' is a 'let' constant
print("student Three age is:\(stuThree.age)") //student Three age is:18
//源变量的值也会跟着改变
print("student age is:\(stu.age)") //student age is:18
//使用延时存储属性
print("student three job is:\(stuThree.job)") //student three job is:teacher
}
//计算属性与get、set方法的使用
func calculationgAndGetSet(){
let shapeT = ShapeTime(r:2, name: "lancom")
print("shapeT s = \(shapeT.s), l = \(shapeT.l)")
//当一个计算属性,只设置了get属性时,那么它是只读的
//shapeT.s = 22 //Cannot assign to property: 's' is a get-only property
shapeT.l = 10
print("shapeT l = \(shapeT.l)")
}
//属性监听器的使用
func attributeListener(){
let teacher = Teacher(name: "Denny", subject: "语文", age: 30)
teacher.name = "Pun"
teacher.subject = "数学"
}
//属性包装器的使用
func attributeWrapper(){
let member = Member()
member.memberAge = -1
member.memberName = ""
print("member age:\(member.memberAge), name = \(member.memberName)") //member age:1, name = default value
}
//实例属性与类属性的使用
func classProperty(){
//类属性不需要创建实例对象,直接使用类名来调用
let nameOne = SomeClass.className
let subName = SomeClass.subName
let nameTwo = SomeClass.classSubName
print("nameOne = \(nameOne), subName = \(subName), nameTwo\(nameTwo)")
//使用子类覆写父类的计算属性
let subClassName = SubClass.classSubName
print("subName = \(subClassName)")
}
//结构体中的实例方法,使用值类型的实例属性时,使用mutating
func changePropertyValue(){
var point = Point(x: 10, y: 10)
point.move(x: 10, y: 10)
}
//类方法的使用,子类覆写父类的类方法,类方法里修改静态属性的值
func classMethod(){
Math.x_value = 100
Math.y_value = 100
Math.movePoint(x: 10, y: 10)
print("Math x_value = \(Math.x_value), y_value = \(Math.y_value)")
//Math x_value = 110.0, y_value = 110.0
MathPoint.x_value = 20
MathPoint.y_value = 20
print("Math x_value = \(Math.x_value), y_value = \(Math.y_value)")
//Math x_value = 20.0, y_value = 20.0
MathPoint.movePoint(x: 5, y: 5)
print("Math x_value = \(Math.x_value), y_value = \(Math.y_value)")
//Math x_value = 30.0, y_value = 30.0
print("MathPoint x_value = \(Math.x_value), y_value = \(Math.y_value)")
//MathPoint x_value = 30.0, y_value = 30.0
//注意:在使用时,子类修改了继承于父类的类属性值,那么整个父类的这个属性值都跟着改变了。可以看到上边的值的变化
}
//下标方法的使用
func subscriptAccess(){
let myArray = MyArray(param: 1, 2, 3, 4, 5)
//通过下标进行访问
myArray[4] = 6
print("myArray[2] = \(myArray[2]), myArray[4] = \(myArray[4])")
}
}