swift学习(二)

属性

计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。
存储属性分为常量存储属性(let) 变量存储属性(var

如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使有属性被声明为变量也不行:

 struct FixedLengthRange {
     var firstValue: Int
     let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) // 该区间表示整数0,1,2
rangeOfThreeItems.firstValue = 6
// 该区间现在表示整数6,7,8

延迟存储属性(lazy)是第一次用的时候再去分配和初始化,因此必须声明为变量(var)。

计算属性

必须使用关键字定义计算属性,包括只读计算属性,因为它们的值不是固定的。 关键字只用来声明 常量属性,表示初始化后再也无法修改的值。

 struct AlternativeRect {
     var origin = Point()
     var size = Size()
     var center: Point {
         get {
             let centerX = origin.x + (size.width / 2)
             let centerY = origin.y + (size.height / 2)
             return Point(x: centerX, y: centerY)
}
set {
             origin.x = newValue.x - (size.width / 2)
             origin.y = newValue.y - (size.height / 2)
         }
} }
属性观察器 willSet didSet

观察器会将新的属性值作为常量参数传入,在 willset 的实现代码中可以为这个参数指定一个名 称,如果不指定则参数仍然可用,这时使用默认名称newValue 表示。同样,观察器会将旧的属性值作为参数传入,didSet可以为该参数命名或者使用默认参数名oldValue 。如果 在didSet 方法中再次对该属性赋值,那么新值会覆盖旧的值。
父类的属性在子类的构造器中被赋值时,它在父类中的 willSetdidSet 观察器会被调用,随后才会调用子类的观察器。在父类初始化方法调用之前,子类给属性赋值时,观察器不会被调用。

class StepCounter {
    var totalSteps:Int = 0 {
        willSet (newValue) {
            print("newValue:\(newValue)")
        }
        didSet (oldValue){
            if totalSteps > oldValue {
                self.totalSteps = 100
            }
            print("oldValue:\(oldValue)")
        }
    }
}
let stepCounts = StepCounter()
stepCounts.totalSteps = 120
print(stepCounts.totalSteps)//结果100
下标

下标允许你通过在实例名称后面的方括号中传入一个或者多个索引值来对实例进行存取。语法类似于实例方法语 法和计算型属性语法的混合。与定义实例方法类似,定义下标使用 subscript 关键字,指定一个或多个输入参数 和返回类型

struct TimesTable {
var multiplier:Int
subscript(index:Int)->Int {
    get {
        return multiplier*index
    }
    set {
        return multiplier = newValue
    }
}

}
var threeTimesTable = TimesTable.init(multiplier: 3)
threeTimesTable[4] = 4
继承 override

调用父类的属性和方法用关键字super你可以将一个继承来的只读属性重写为一个读写属性,只需要在重写版本的属性里提供 getter 和 setter 即 可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。

class Vehicle {
var currentSpeed = 0.0
var description:String {
    return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {

    }
}
class Byicle: Vehicle {
    var hasBasket = false

}
let someVehicle = Vehicle()
someVehicle.description
let someByicle = Byicle.init()
someVehicle.currentSpeed = 30.0
someVehicle.description

注意
如果你在重写属性中提供了 setter,那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改 继承来的属性值,你可以直接通过 super.someProperty 来返回继承来的值,其中 someProperty 是你要重写的属 性的名字

防止重写 (final)
你可以通过把方法,属性或下标标记为 来防止它们被重写,只需要在声明关键字前加上 修饰符即 可(例如: , , ,以及 )。
如果你重写了带有 标记的方法,属性或下标,在编译时会报错。在类扩展中的方法,属性或下标也可以在 扩展的定义里标记为 final 的。
你可以通过在关键字 前添加 修饰符( )来将整个类标记为 final 的。这样的类是不可 被继承的,试图继承这样的类会导致编译报错。

构造……

循环引用
注意弱引用weak和无主引用unowned的用法不同.

  • 弱引用适用于生命周期短的情况。例如下面的例子,公寓可能没有人住。
  • 无主引用必须时刻有一个实例,因此无主引用是非可选类型的。例如下面信用卡的例子,信用卡一定时刻关联着一个客户。
  • 第三种情况就是Country和city,一个国家必有一个首都,一个城市必属于一个国家,这是一个用unowned和隐式解析可选类型(属性后面加!,这样属性就可以像其他的可选类型一样可以为nil
class Student {
    let name:String?
    var apartment: Apartment?
    init(name:String) {
        self.name = name
        print("class init")
    }
    deinit { print("\(String(describing: name)) is being deinitialized") }
}
class Apartment {
    let unit:String?
    weak var stu:Student?
    init(unit:String) {
        self.unit = unit
    }
    deinit {
        print("Apartment class deinit\(String(describing: self.stu))")
    }


}
var stu1:Student?,stu2:Student?,stu3:Student?
var apart1:Apartment?

stu1 = Student(name:"jack")
apart1 = Apartment(unit:"unit1")
stu1!.apartment = apart1
apart1!.stu = stu1
stu1 = nil
apart1 = nil

客户和信用卡的无主引用

class Customer {
    let name:String?
    var card:CreditCard?
    init(name:String) {
        self.name = name
    }
    deinit {
        print("class customer deinit")
    }


}
class CreditCard {
    let number:Int
    unowned let customer:Customer
    init(number:Int,customer:Customer) {
        self.number = number
        self.customer = customer
    }
    deinit {
        print("class creditcard deinit")
    }
}
var customer1:Customer?,card1:CreditCard?
customer1 = Customer(name:"jakc")
card1 = CreditCard(number:102020,customer:customer1!)
customer1!.card = card1
customer1 = nil
card1 = nil

在这种场景中,两个属性都必须有值,并且初始化完成后永远不会为 nil 。在这种场 景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。

 class Country {
     let name: String
     var capitalCity: City!
     init(name: String, capitalName: String) {
         self.name = name
         self.capitalCity = City(name: capitalName, country: self)
     }
}
 class City {
     let name: String
     unowned let country: Country
     init(name: String, country: Country) {
         self.name = name
         self.country = country
     }
}
var country = Country(name: "Canada", capitalName: "Ottawa") print("\(country.name)'s capital city is called \(country.capitalCity.name)") // 打印 “Canada's capital city is called Ottawa”

为了建立两个类的依赖关系, City 的构造函数接受一个 Country 实例作为参数,并且将实例保存到 country 属 性。Country 的构造函数调用了 City 的构造函数。然而,只有 Country 的实例完全初始化后, Country 的构造函数 才能把 self 传给 City 的构造函数.为了满足这种需求,通过在类型结尾处加上感叹号( City! )的方式,将 Country capitalCity 属性声明为隐式解析可选类型的属性。这意味着像其他可选类型一,capitalCity 属性的默认值为 nil ,但是不需要展开它 的值就能访问它。由于 capitalCity 默认值为 nil ,一旦 Country 的实例在构造函数中给 name 属性赋值后,整个初始化过程就完 成了。这意味着一旦 name 属性被赋值后, Country 的构造函数就能引用并传递隐式的 self 。 Country 的构造函 数在赋值 capitalCity 时,就能将 self 作为参数传递给 City 的构造函数。以上的意义在于你可以通过一条语句同时创建 Country 和 City 的实例,而不产生循环强引用,并且 的属性能被直接访问,而不需要通过感叹号来展开它的可选值.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值