From: AceVest Date: Tue, 14 Mar 2017 15:54:10 +0000 (+0800) Subject: swift-Inheritance-Initialization X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/man.named-checkzone.html?a=commitdiff_plain;h=88958a0f71d36b4f4fab6b3717d946204de876eb;p=acecode.git swift-Inheritance-Initialization --- diff --git a/learn/AcePlay/AcePlay.playground/Pages/Inheritance.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/Inheritance.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..dc1cf1d --- /dev/null +++ b/learn/AcePlay/AcePlay.playground/Pages/Inheritance.xcplaygroundpage/Contents.swift @@ -0,0 +1,96 @@ +//: [Previous](@previous) + +import Foundation + +var str = "Hello, Inheritance" + +//: [Next](@next) + +class Vehicle { + var currentSpeed = 0.0 + var description: String { + return "traveling at \(currentSpeed) miles per hour" + } + + func makeNoise() { + // to do nothing + } +} + +let someVehicle = Vehicle() +print("Vehicle: \(someVehicle.description)") + +class Bicycle: Vehicle { + var hasBasket = false +} +let someBicycle = Bicycle() +someBicycle.hasBasket = true +someBicycle.currentSpeed = 13.5 +print("Bicycle: \(someBicycle.description)") + + +class Tandem: Bicycle { + var currentNumberOfPassengers = 0 +} + +let someTandem = Tandem() +someTandem.hasBasket = true +someTandem.currentSpeed = 19.9 +someTandem.currentNumberOfPassengers = 2 +print("Tandem: \(someTandem.description)") + +// 重写 +// 子类可以为继承来的实例方法,类方法,实例属性,或下标提供自己定制的实现。我们把这种行为叫重写 +// 如果要重写某个特性,你需要在重写定义的前面加上override关键字 +class Train: Vehicle { + override func makeNoise() { + print("Choo Choo") + } +} + +let someTrain = Train() +someTrain.makeNoise() + + +// 重写属性 +// 可以重写继承来的实例属性或类型属性,提供自己定制的 getter 和 setter,或添加属性观察器使重写的属性可以观察属性值什么时候发生改变 +// 可以将一个继承来的只读属性重写为一个读写属性 +// 不可以将一个继承来的读写属性重写为一个只读属性 + +// 如果在重写属性中提供了setter,那么你也一定要提供getter +// 如果不想在重写版本中的getter 里修改继承来的属性值 +// 可以直接通过super.someProperty来返回继承来的值,其中someProperty是要重写的属性的名字 + +class Car: Vehicle { + var gear = 1 + + override var description: String { + return super.description + " in gear \(gear)" + } +} + +let someCar = Car() +someCar.currentSpeed = 72.7 +someCar.gear = 3 +print("Car: \(someCar.description)") + +// 重写属性观察器 +// 可以通过重写属性为一个继承来的属性添加属性观察器 +class AutomaticCar: Car { + override var currentSpeed: Double { + didSet { + gear = Int(currentSpeed/20.0) + 1 + } + } +} +let someAutomaticCar = AutomaticCar() +someAutomaticCar.currentSpeed = 67.3 +print("AutomaticCar: \(someAutomaticCar.description)") + +// 防止重写 +// 以通过把方法,属性或下标标记为final来防止它们被重写,只需要在声明关键字前加上final修饰符即可 +// 例如:final var,final func,final class func,以及final subscript +// 在类扩展中的方法,属性或下标也可以在扩展的定义里标记为final的 +// 可以通过在关键字class前添加final修饰符来将整个类标记为不可被继承的,试图继承这样的类会导致编译报错 + + diff --git a/learn/AcePlay/AcePlay.playground/Pages/Initialization.xcplaygroundpage/Contents.swift b/learn/AcePlay/AcePlay.playground/Pages/Initialization.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..a7ddf9f --- /dev/null +++ b/learn/AcePlay/AcePlay.playground/Pages/Initialization.xcplaygroundpage/Contents.swift @@ -0,0 +1,176 @@ +//: [Previous](@previous) + +import Foundation + +var str = "Hello, Initialization" + +//: [Next](@next) + +// 构造过程 + +// 可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值 +// 为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察者 + +struct Fahrenheit { + var temperature: Double + init() { + temperature = 32.0 + } +} + +// 与下述定义方式等价 +// struct Fahrenheit { +// var temperature = 32.0 +// } + +var f = Fahrenheit() +print("The default temperature is \(f.temperature)° Fahrenheit") + + +// 构造参数 +struct Celsius { + var temperatureInCelsius: Double + init(fromFahrenheit fahrenheit: Double) { + temperatureInCelsius = (fahrenheit - 32.0) / 1.8 + } + + init(fromKelvin kelvin: Double) { + temperatureInCelsius = kelvin - 273.15 + } + + init(_ celsius: Double) { + temperatureInCelsius = celsius + } +} + +let bollingPointOfWather = Celsius(fromFahrenheit: 212.0) +let freezingPointOfWather = Celsius(fromKelvin: 273.15) + + +// 构造器并不像函数和方法那样在括号前有一个可辨别的名字 +// 因此在调用构造器时,主要通过构造器中的参数名和类型来确定应该被调用的构造器 +// 正因为参数如此重要,如果你在定义构造器时没有提供参数的外部名字,Swift会为构造器的每个参数自动生成一个跟内部名字相同的外部名 + +struct Color { + var red, green, blue: Double + + init(red: Double, green: Double, blue: Double) { + self.red = red + self.green = green + self.blue = blue + } + + init(white: Double) { + red = white + green = white + blue = white + } +} + +let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) +let halfGray = Color(white: 0.5) + + +// 如果不通过外部参数名字传值,你是没法调用这个构造器的 +// 只要构造器定义了某个外部参数名,你就必须使用它,忽略它将导致编译错误 +// let green = Color(0.0, 1.0, 0.0) 这段代码会报编译时错误,需要外部名称 +let bodyTemperature = Celsius(37.2) + +// 常量属性的修改&可选属性类型 +class SureyQuestion { + let text: String + var response: String? + + init(text: String) { + // 可以在构造过程中的任意时间点给常量属性指定一个值 + // 一旦常量属性被赋值,它将永远不可更改 + // 对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改 + self.text = text + } + + func ask() { + print(text) + } +} + + +let beetsQuestion = SureyQuestion(text: "How about beets?") +beetsQuestion.ask() +beetsQuestion.response = "I also like beets. (But not with cheese.)" + + +// 默认构造器 +// 如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器(default initializers) +class ShoppingListItem { + // name 默认为 nil + var name: String? + + // quantity 默认为 1 + var quantity = 1 + + // purchased 默认为 false + var purchased = false +} + +var someShoppingListItem = ShoppingListItem() + + +// 结构体的逐一成员构造器 +// 除了上面提到的默认构造器,如果结构体没有提供自定义的构造器,它们将自动获得一个逐一成员构造器,即使结构体的存储型属性没有默认值 +struct Size { + var width = 0.0 + var height = 0.0 +} + +let size0 = Size() // 默认构造器 +let size1 = Size(width: 2.3, height: 3.7) // 逐一构造器 + + +// 构造器代理 +// 构造器代理的实现规则和形式在值类型和类类型中有所不同 + +// 值类型(结构体和枚举类型)的构造器代理不支持继承,所以构造器代理的过程相对简单 +// 对于值类型,可以使用self.init在自定义的构造器中引用相同类型中的其它构造器。并且只能在构造器内部调用self.init +// 如果为某个值类型定义了一个自定义的构造器,将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器) +// 如果希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例 +// 可以将自定义的构造器写到扩展(extension)中,而不是写在值类型的原始定义中 + +struct Point { + var x = 0.0, y = 0.0 +} + +struct Rect { + var origin = Point() + var size = Size() + + init() { } + + init(origin: Point, size: Size) { + self.origin = origin + self.size = size + } + + init(center: Point, size: Size) { + let originX = center.x - size.width / 2 + let originY = center.y - size.height / 2 + + self.init(origin: Point(x: originX, y: originY), size: size) + } + + var description: String { + return "LeftBottom(\(origin.x), \(origin.y)) RightTop(\(origin.x+size.width), \(origin.y+size.height))" + } +} + +let basicRect = Rect() +let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 100, height: 200)) +let centerRect = Rect(center: Point(x: 50, y: 50), size: Size(width: 50, height: 50)) + +print("BasicRect: \(basicRect.description)") +print("OriginRect: \(originRect.description)") +print("CenterRect: \(centerRect.description)") + + +// 类的继承和构造过程 + + diff --git a/learn/AcePlay/AcePlay.playground/contents.xcplayground b/learn/AcePlay/AcePlay.playground/contents.xcplayground index 7a38434..17e0832 100644 --- a/learn/AcePlay/AcePlay.playground/contents.xcplayground +++ b/learn/AcePlay/AcePlay.playground/contents.xcplayground @@ -11,5 +11,7 @@ + + \ No newline at end of file diff --git a/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate b/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate index e07186e..ed698a8 100644 Binary files a/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate and b/learn/AcePlay/AcePlay.playground/playground.xcworkspace/xcuserdata/Ace.xcuserdatad/UserInterfaceState.xcuserstate differ