Swift-枚举、结构体、类
Swift-枚举、结构体、类学习如下教程的记录
Swift中的type system: 枚举参考:
明确指定后备存储(backing store)类型的枚举被称为RawRepresentable,因为它们自动采用 如下定义一个颜色枚举 enum ColorName: String {
case black
case silver
case gray
case white
case maroon
case red
}
所以 关联值颜色处了有使用名字表示外,还可以使用RGB或者HSL来表示 enum CSSColor {
case named(ColorName)
case rgb(UInt8,UInt8,UInt8)
}
如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法接收一个叫做 枚举中的方法和协议在swift中,枚举与其它named type一样,可以采用协议 extension CSSColor: CustomStringConvertible
{
var description: String {
switch self {
case .named(let colorName):
return colorName.rawValue
case .rgb(let red,let green,let blue):
return String(format: "#%02X%02X%02X",red,green,blue)
}
}
}
枚举的初始化方法 extension CSSColor { init(gray: UInt8) { self = .rgb(gray,gray,gray) } }
枚举类型的可失败构造器如果提供的参数无法匹配任何枚举成员,则构造失败。 enum TemperatureUnit {
case Kelvin,Celsius,Fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
}
带原始值的枚举类型的可失败构造器带原始值的枚举类型会自带一个可失败构造器 enum TemperatureUnit: Character {
case Kelvin = "K",Celsius = "C",Fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit,so initialization succeeded.")
}
// 打印 "This is a defined temperature unit,so initialization succeeded."
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit,so initialization failed.")
}
// 打印 "This is not a defined temperature unit,so initialization failed."
结构体在枚举的extension中不能添加新的case,但结构体和类是可以的
protocol Drawable {
func draw(with context: DrawingContext)
}
protocol DrawingContext {
func draw(circle: Circle)
// more primitives will go here ...
}
如下,定义一个结构体 struct Circle : Drawable {
var strokeWidth = 5
var strokeColor = CSSColor.named(.red)
var fillColor = CSSColor.named(.yellow)
var center = (x: 80.0,y: 160.0)
var radius = 60.0
// 实现Drawable协议
func draw(context: DrawingContext) {
context.draw(self)
}
}
结构体与类类似。结构体与类的区别是,结构体是值类型,类是引用类型 与类不同,结构体的方法不允许修改存储属性,如果要修改的话使用 mutating func shift(x: Double,y: Double) {
center.x += x
center.y += y
}
结构体构造过程默认构造器如果没有存储属性,或者存储属性都有默认值时,可直接使用默认的构造器。同样,如果有可选类型的属性的变量,由于可选类型的存储属性默认初始化为 struct RocketConfiguration {
let name: String = "Athena 9 Heavy"
let numberOfFirstStageCores: Int = 3
let numberOfSecondStageCores: Int = 1
var numberOfStageReuseLandingLegs: Int?
}
let athena9Heavy = RocketConfiguration()
但如果把 let numberOfStageReuseLandingLegs: Int?
这时 结构体的逐一成员构造器处理默认构造器,如果结构体没有提供自定义的构造器,它们将自动获得一个逐一成员构造器,即使结构体的存储型属性没有默认值。 逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。 struct RocketStageConfiguration {
let propellantMass: Double
let liquidOxygenMass: Double
let nominalBurnTime: Int
}
let stageOneConfiguration = RocketStageConfiguration(propellantMass: 119.1,liquidOxygenMass: 276.0,nominalBurnTime: 180)
要注意的是:
但如果任然需要自动生成的逐一构造器方法,该怎么办呢?答案是使用 struct RocketStageConfiguration {
let propellantMass: Double
let liquidOxygenMass: Double
let nominalBurnTime: Int
}
extension RocketStageConfiguration {
init(propellantMass: Double,liquidOxygenMass: Double) {
self.propellantMass = propellantMass
self.liquidOxygenMass = liquidOxygenMass
self.nominalBurnTime = 180
}
}
自定义构造方法一个初始化方法必须给每个不带默认值的存储属性指定值,否则的话报错 struct Weather {
let temperatureCelsius: Double
let windSpeedKilometersPerHour: Double
init(temperatureFahrenheit: Double = 72,windSpeedMilesPerHour: Double = 5) {
self.temperatureCelsius = (temperatureFahrenheit - 32) / 1.8
self.windSpeedKilometersPerHour = windSpeedMilesPerHour * 1.609344
}
}
值类型的构造器代理构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。 要注意的是,构造器代理中不能实例化任何属性,原因是你调用的改造方法,可能会修改你的属性,这样是不安全的,如下会报错 init(zAngularVelocityDegreesPerMinute: Double) {
self.needsCorrection = false//报错
self.init(zAngularVelocityDegreesPerMinute: zAngularVelocityDegreesPerMinute,needsCorrection: self.needsCorrection)
}
Two-Phase Initialization(两段式构造过程)如下: struct CombustionChamberStatus {
var temperatureKelvin: Double
var pressureKiloPascals: Double
init(temperatureKelvin: Double,pressureKiloPascals: Double) {
print("Phase 1 init")
self.temperatureKelvin = temperatureKelvin
self.pressureKiloPascals = pressureKiloPascals
print("CombustionChamberStatus fully initialized")
print("Phase 2 init")
}
init(temperatureCelsius: Double,pressureAtmospheric: Double) {
print("Phase 1 delegating init")
let temperatureKelvin = temperatureCelsius + 273.15
let pressureKiloPascals = pressureAtmospheric * 101.325
self.init(temperatureKelvin: temperatureKelvin,pressureKiloPascals: pressureKiloPascals)
print("Phase 2 delegating init")
}
}
CombustionChamberStatus(temperatureCelsius: 32,pressureAtmospheric: 0.96)
调试区域输出如下: Phase 1 delegating init Phase 1 init CombustionChamberStatus fully initialized Phase 2 init Phase 2 delegating init 可见 可失败构造器你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在
struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}
除了返回 struct Astronaut {
let name: String
let age: Int
init(name: String,age: Int) throws {
if name.isEmpty {
throw InvalidAstronautDataError.EmptyName
}
if age < 18 || age > 70 {
throw InvalidAstronautDataError.InvalidAge
}
self.name = name
self.age = age
}
}
enum InvalidAstronautDataError: Error {
case EmptyName
case InvalidAge
}
在调用可抛出异常的构造器方法时,使用 try、try?、try!的区别?
let johnny = try? Astronaut(name: "Johnny Cosmoseed",age: 17) // nil
类属性计算属性extension Circle {
var diameter: Double {
get {
return radius * 2
}
set {
radius = newValue / 2
}
}
}
更多的时候,需要的是一个getter方法: var area: Double {
return radius * radius * Double.pi
}
属性观察器属性观察器可以用来限制值或者格式 var current = 0 {
// 可以不声明新的变量名,使用newValue
willSet(newCurrent){
// 此时,current还是以前的值
print("Current value changed. The change is (abs(current-newCurrent))")
}
// property observer可以用来限制值或者格式
// 也可以用来做关联逻辑
// 可以不声明新的变量名,使用oldValue获取原来的值
didSet(oldCurrent){
// 此时,current已经是新的值
if current == LightBulb.maxCurrent{
print("Pay attention,the current value get to the maximum point.")
}
else if current > LightBulb.maxCurrent{
print("Current too high,falling back to previous setting.")
current = oldCurrent
}
print("The current is (current)")
}
}
注意:didSet和willSet不会在初始化阶段调用 如下的定义: enum Theme{
case DayMode
case NightMode
}
class UI{
var fontColor: UIColor!
var backgroundColor: UIColor!
var themeMode: Theme = .DayMode{
didSet{
switch(themeMode){
case .DayMode:
fontColor = UIColor.blackColor()
backgroundColor = UIColor.whiteColor()
case .NightMode:
fontColor = UIColor.whiteColor()
backgroundColor = UIColor.blackColor()
}
}
}
init(){
self.themeMode = .DayMode
}
}
进行如下的初始化,会发现 let ui = UI()
ui.themeMode
ui.fontColor//为nil
ui.backgroundColor//为nil
便利构造函数和指定构造函数要注意的点: 1.构造函数参数可以有默认值 两种构造器: 指定构造器-指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。 ``` init(parameters) { statements } ``` 便利构造器-便利构造器是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值 ``` convenience init(parameters) { statements } ``` 注意: 1.只有指定构造函数可以调用 可失败构造器一般来说,要让指定构造器不可失败,而让便利构造器可失败,如下的 class RocketComponent {
let model: String
let serialNumber: String
let reusable: Bool
// Init #1a - Designated
init(model: String,serialNumber: String,reusable: Bool) {
self.model = model
self.serialNumber = serialNumber
self.reusable = reusable
}
// Init #1b - Convenience
convenience init(model: String,serialNumber: String) {
self.init(model: model,serialNumber: serialNumber,reusable: false)
}
// Init #1c - Designated
convenience init?(identifier: String,reusable: Bool) {
let identifierComponents = identifier.components(separatedBy: "-")
guard identifierComponents.count == 2 else {
return nil
}
self.init(model: identifierComponents[0],serialNumber: identifierComponents[1],reusable: reusable) } }
类的两段式构造类的两段式构造需要注意的是: 1.关于父类的属性必须通过父类的构造函数来进行构造
如下: init(name: String,group: String){
// Phase1: 从子类向父类初始化所有的变量 self.group = group super.init(name: name) // Phase2: 所有成员变量初始化完成以后,进行成员变量相关的逻辑调整 if self.group == ""{ getScore(-10) self.life -= 5 } }
继承
构造函数的继承如果子类实现了父类所有的指定构造函数,则自动继承父类的所有便利构造函数 required关键字 //父类
required init(name: String){
self.name = name
}
//子类
convenience required init(name: String){
self.init(name: name,group: "")
}
注意: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |