swift 属性和方法
属性和常量
如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性:
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) rangeOfFourItems.firstValue = 6
- 当值类型的实例被声明为常量的时候,它的所有属性也就成了常量
- 当引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。
延迟属性
- 属性声明前使用@lazy来标示一个延迟存储属性。
- 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性
- 必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
- 什么时候使用延迟属性?
- 当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时
- 当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它
class DataManager { @lazy var importer = DataImporter() var data = String[]() // 这是提供数据管理功能 }
计算属性:getter和setter
如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称newValue。
必须使用var关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。
struct Rect{ var _center:String; var center: String { get { return _center; } set (newCenter){ _center = newCenter } } } //使用newValue struct Rect2{ var _center:String; var center: String { get { return _center; } set{ _center = newValue } } }
属性观察器
- 属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。
- 可以为除了延迟存储属性之外的其他存储属性添加属性观察器,
- 不需要为无法重载的计算属性添加属性观察器,因为可以通过 setter 直接监控和响应值的变化。
- 可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器
属性观察器:
willSet
在设置新的值之前调用,willSet观察器会将新的属性值作为固定参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。didSet
在新的值被设置之后立即调用,didSet观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。- willSet和didSet观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。
struct Test{ var test:Int = 0{ willSet { println(newValue) } didSet{ println(oldValue) } } } var a = Test(); a.test = 5;
全局变量,局部变量和延迟属性,计算属性,属性观察器
全局或局部变量都属于存储型变量,跟存储属性类似,它提供特定类型的存储空间,并允许读取和写入。
- 在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
- 全局的常量或变量都是延迟计算的,跟延迟存储属性相似,不同的地方在于,全局的常量或变量不需要标记@lazy特性。 局部范围的常量或变量不会延迟计算。
var test:Int = 0{ willSet { println(newValue) } didSet{ println(oldValue) } } test = 5 ; var str:String{ get{ return String(test); } set { test = newValue.toInt()!+5 } } println(str); str = "4"; println(str)
类型属性---静态属性
使用关键字static来定义值类型的类型属性,关键字class来为类(class)定义类型属性:
struct SomeStructure { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { // 这里返回一个 Int 值 } } enum SomeEnumeration { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { // 这里返回一个 Int 值 } } class SomeClass { class var computedTypeProperty: Int { // 这里返回一个 Int 值 } }
类型属性是通过类型本身来获取和设置,而不是通过实例。
println(SomeClass.computedTypeProperty) // 输出 "42" println(SomeStructure.storedTypeProperty) // 输出 "Some value." SomeStructure.storedTypeProperty = "Another value." println(SomeStructure.storedTypeProperty) // 输出 "Another value.”
self 和 parent
- 类型的每一个实例都有一个隐含属性叫做self,self完全等同于该实例本身
- 你不必在你的代码里面经常写self。不论何时,只要在一个方法中使用一个已知的属性或者方法名称,如果你没有明确的写self,Swift 假定你是指当前实例的属性或者方法
- 使用这条规则的主要场景是实例方法的某个参数名称与实例的某个属性名称相同的时候。在这种情况下,参数名称享有优先权,并且在引用属性时必须使用一种更严格的方式。这时你可以使用self属性来区分参数名称和属性名称。
- 变异方法能够赋给隐含属性self一个全新的实例。
- 在类型方法的方法体(body)中,self指向这个类型本身,而不是类型的某个实例。对于结构体和枚举来说,这意味着你可以用self来消除静态属性和静态方法参数之间的歧义
struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { self = Point(x: x + deltaX, y: y + deltaY) } } enum TriStateSwitch { case Off, Low, High mutating func next() { switch self { case Off: self = Low case Low: self = High case High: self = Off } } } var ovenLight = TriStateSwitch.Low ovenLight.next() // ovenLight 现在等于 .High ovenLight.next() // ovenLight 现在等于 .Off
变异 mutating
- 结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。
- 要使用变异方法, 将关键字mutating 放到方法的func关键字之前
- 不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变,即使想改变的是常量的变量属性也不行
struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { x += deltaX y += deltaY } } var somePoint = Point(x: 1.0, y: 1.0) somePoint.moveByX(2.0, y: 3.0)
实例方法
- 实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。
- 实例方法只能被它所属的类的某个特定实例调用。
- 实例方法不能脱离于现存的实例而被调用。
Swift 中方法的名称通常用一个介词指向方法的第一个参数,比如:with,for,by等等。
关于方法的外部参数:
- Swift 默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称局部参数名称和外部参数名称。
- 可以自己添加一个显式的外部名称或者用一个井号(#)作为第一个参数的前缀来把这个局部名称当作外部名称使用。
- 如果你不想为方法的第二个及后续的参数提供一个外部名称,可以通过使用下划线(_)作为该参数的显式外部名称,这样做将覆盖默认行为。
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes } } let counter = Counter() counter.incrementBy(5, numberOfTimes: 3)
类型方法--静态方法
声明类的类型方法,在方法的func关键字之前加上关键字class;声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。
struct LevelTracker { static var highestUnlockedLevel = 1 static func unlockLevel(level: Int) { if level > highestUnlockedLevel { highestUnlockedLevel = level } } static func levelIsUnlocked(level: Int) -> Bool { return level <= highestUnlockedLevel } var currentLevel = 1 mutating func advanceToLevel(level: Int) -> Bool { if LevelTracker.levelIsUnlocked(level) { currentLevel = level return true } else { return false } } }