存储属性和计算属性
今天讨论实例存储属性与实例变量,结构体常量与实例属性,定义计算属性,setter方法,属性观察者
存储属性:存储在类和结构体里的变量和常量。分为实例存储属性和类型存储属性,实例存储属性是指单个的实例,用来保存实例的状态和数据。类型存储属性:属于类型本身。类,结构体,枚举都可以定义成类型存储属性。枚举不可以定义成实例存储属性,
所有的存储属性都必须显示的指定初始值,可以在定义时或者构造器中指定。
可选类型的存储属性是可以不指定初始值的
1.程序为所有的实例存储属性指定了初始值,且没有构造器。则系统会提供2个构造器:一个无参数的构造器和一个初始化所有实例存储属性的构造器
2.属性没有初始值也没有构造器,系统提供一个初始化所有属性的构造器
3.有构造器,则要早构造器中为所有的属性提供初始值
通过构造器函数完成对存储属性的初始化:
//存储属性
struct lengthrange{
var start: Int
//定义常量存储属性,可以不指定初始值
let length: Int
}
var len = lengthrange(start: 9, length: 3)
print(len.start,len.length)
//定义一个结构体常量与她的实例属性
struct lengthrange2{
var start: Int
var length: Int
}
let len2 = lengthrange(start: 1, length: 2)//不可以改变实例属性
延迟存储属性:第一次调用的时候才会计算初始值的属性,用lazy的修饰符
延迟存储是一种延迟机制,只能声明成变量。
计算属性
计算属性就相当于oc中的getter和setter方法合成的属性,
计算属性的格式:
/*
[修饰符]var 计算属性名:属性类型{
get {
//get方法执行体,该方法一定要有返回值
}
set(形参名){
set方法执行体,该方法一定不能有返回值
}
*/
属性观察者:用来观察属性的变化的,为了让属性在被赋值的时候获得执行代码的机会
1.它可以监听除了延迟属性之外的所有存储属性(包括类型存储属性和实例存储属性)
2.可以通过重载的方式为继承得到的属性添加属性观察者
/*
属性观察者:
[修饰符]var 计算属性名: 属性类型 = 初始值{
will set(newvalue){
//属性即将被赋值之前调用的方法
}
didset(oldvalue){
//属性被赋值完成之后自动调用的方法
}
willset和didset后面的参数都是可以省略的
*/
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.components(separatedBy: "-")
self.first = names[0]
self.last = names[1]
}
}
init (first: String , last: String){
self.first = first
self.last = last
}
}
let s = user(first: "swift", last: "hello")
print(s.fullname)//调用get方法
s.fullname = "hello-swift"//调用setter方法
print(s.first)
//只读属性,不需要set部分,可以省略get和花括号
//属性观察者
class person {
//定义存储属性
var name: String = "" {
willSet{
if newValue.characters.count>6 || newValue.characters.count < 2 {
print("你设置的人名不符合要求,请重新设置")
} 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
p.age = 10//将会调用willset和didset方法
swift面相对象中的方法
在方法中,谈论的是方法的所属性,方法转换为函数,方法的外部形参名,值类型的可变方法,属性和方法的统一
1.定义方法需要在枚举,结构体,类中定义,不能够独立的定义
2.方法可以使类型本身,也可以是属于实例
3.不能独立使用方法,需用类型或者实例充当调用者
4.枚举和结构体中的方法用static修饰,类中用class修饰,都属于类方法。否则属于实例方法
//将方法转换成函数
class someclass {
func test() {
print("==test 方法 ==")
}
class func bar(msg: String){
print("== bar 类型方法==,传入的参数:\(msg)")
}
}
//创建实例
var sc = someclass()
//将sc的test方法分离成函数
var f1 : ()->() = sc.test//不能有(),()标示调用方法,没有()标示赋值给f1,从而把方法转变成了函数
//将sc的bar方法分离成函数
var f2:(String) -> Void = someclass.bar
//直接调用函数就等于调用了方法
f1() //等价于sc.text()
f2("swift")
方法的外部形参名
//方法的外部形参名
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(food: "烤鸭", drink: "啤酒", cigarette: "雪茄")//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(x: 100, y: 90)
print("rect举行的左上角的x坐标为:\(rect.x),y\(rect.y)")
//注意:常量类型的结构体,枚举是不可变的
属性和方法的统一
1.使用函数类型定义属性,并将函数或者闭包作为该属性的初始值,这个属性就成了方法。
//属性和方法的统一
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()
//使用闭包对sc对象发的info赋值,相当于重新定义sc的info方法
sc.info = {
print("另外一个闭包")
}
sc.info()
var n = 6
//调用的fact方法,执行的是阶乘
print("\(n)的阶乘是:\(somestruct.fact(6))")
//使用闭包对somestruct的fact赋值,相当于重新定义somestruct的fact方法
somestruct.fact = {
var result = 1
for i in 1...$0{
result += i
}
return result
}
//再次调用fact方法,执行的是累加
print("\(n)的累加的和")
下标
需要了解下标的用法和下标的重载
1.所有的swift类型(枚举,类,结构体)都支持下标
2.同一个类型可以定义多个下标值
3.通过下标的形参列表或者返回值的类型来区分不同的下标
4.同一个类型中定义多个不同的下标,被称为下标重载。
//下标的基本用法
/*
Subscripe(形参列表) -> 下标返回值类型 {
get {
//get方法执行体,该方法一定有返回值
}
set (形参名){
//setter方法执行体,该方法可以没有返回值
}
}
形参列表:与函数的形参列表的用法基本相同,但是不支持指定外部参数和默认值
下标返回值类型:可以是任何有效的类型
*/
//下标
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[0])y坐标为 \(rect2[1])")
//省略下标中的set部分即是只读下标