学习如下教程的记录
Getting to Know Enums,Structs and Classes in Swift Swift Tutorial: Initialization In Depth,Part 1/2Swift中的type system:
枚举参考:
官方文档-枚举明确指定后备存储(backing store)类型的枚举被称为RawRepresentable,因为它们自动采用RawRepresentable
协议。
如下定义一个颜色枚举colorname
:
enum colorname: String { case black case silver case gray case white case maroon case red}
当使用字符串作为枚举类型的原始值时,每个枚举成员的隐式原始值为该枚举成员的名称。
所以let black = colorname.black.rawValue
为black
颜色处了有使用名字表示外,还可以使用RGB或者HSL来表示
如下定义CSScolor
enum CSScolor { case named(colorname) case rgb(UInt8,UInt8,UInt8)}
如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法接收一个叫做rawValue
的参数,参数类型即为原始值类型,返回值则是枚举成员或nil
。
在swift中,枚举与其它named type一样,可以采用协议
如果想输出CSScolor
对象,可以采用customstringconvertible
协议
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 } }}带原始值的枚举类型的可失败构造器
带原始值的枚举类型会自带一个可失败构造器init?(rawValue:)
,该可失败构造器有一个名为rawValue
的参数
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,但结构体和类是可以的
Swift Standard library
团队建议当创建一个新的model的时候,先使用protocol
创建一个interface。在这里图形要可绘制,所以定义如下的protocol
:
protocol Drawable { func draw(with context: DrawingContext)}
DrawingContext
也是一个protocol
,DrawingContext
知道如何绘制纯几何类型:Circle
,Rectangle
和其他类型。实际的绘制方法要自己实现
protocol DrawingContext { func draw(circle: Circle) // more primitives will go here ...}
如下,定义一个结构体Circle
采用Drawable
协议:
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
声明
mutating func shift(x: Double,y: Double) { center.x += x center.y += y}结构体构造过程 默认构造器
如果没有存储属性,或者存储属性都有默认值时,可直接使用默认的构造器。同样,如果有可选类型的属性的变量,由于可选类型的存储属性默认初始化为nil
,所以也看直接使用默认的构造器
struct RocketConfiguration { let name: String = "Athena 9 Heavy" let numberOfFirstStageCores: Int = 3 let numberOfSecondStageCores: Int = 1 var numberOfStageReuseLandingLegs: Int?}let athena9Heavy = RocketConfiguration()
但如果把var numberOfStageReuseLandingLegs: Int?
,改为常量let
let numberOfStageReuseLandingLegs: Int?
这时let athena9Heavy = RocketConfiguration()
就会编译报错
处理默认构造器,如果结构体没有提供自定义的构造器,它们将自动获得一个逐一成员构造器,即使结构体的存储型属性没有默认值。
逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。
struct RocketStageConfiguration { let propellantMass: Double let liquIDOxygenMass: Double let nominalBurnTime: Int}let stageOneConfiguration = RocketStageConfiguration(propellantMass: 119.1,liquIDOxygenMass: 276.0,nominalBurnTime: 180)
要注意的是:
如果调整存储属性的顺序,上面的构造方法也会报错,因为逐一构造器的方法的参数的顺序与存储属性的顺序是一致的 如果存储属性有默认值,如let nominalBurnTime: Int = 180
,上面的构造方法也会报错。这是因为逐一构造器的参数只针对没有默认值的存储顺序 如果添加了自定义的构造方法,原来自动生成的逐一构造器方法就会无效
struct RocketStageConfiguration { let propellantMass: Double let liquIDOxygenMass: Double let nominalBurnTime: Int init(propellantMass: Double,liquIDOxygenMass: Double) { self.propellantMass = propellantMass self.liquIDOxygenMass = liquIDOxygenMass self.nominalBurnTime = 180 }}let stageOneConfiguration = RocketStageConfiguration(propellantMass: 119.1,nominalBurnTime: 180)//报错
但如果任然需要自动生成的逐一构造器方法,该怎么办呢?答案是使用extension
,即把自定义的初始化方法放在extension
中
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 initPhase 1 initCombustionChAmberStatus fully initializedPhase 2 initPhase 2 delegating init
可见Phase 1 delegating init
和self.init(.....)
之间,不可以使用self
你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在init
关键字后面添加问号(init?
)
注意:你只是用return nil表明可失败构造器构造失败,而不要用关键字return来表明构造成功。
struct Animal { let specIEs: String init?(specIEs: String) { if specIEs.isEmpty { return nil } self.specIEs = specIEs }}
除了返回nil
,还可以抛出异常,如下:
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!
try、try?、try!的区别?
参考try,try! & try? what’s the difference,and when to use each?
try?会试图执行一个可能会抛出异常的 *** 作。如果成功抛出异常,执行的结果就会包裹在可选值(optional)里;如果抛出异常失败(比如:已经在处理 error),那么执行的结果就是nil,而且没有 error。try?配合if let和guard一起使用效果更佳
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}属性观察器
属性观察器可以用来限制值或者格式
willSet
在赋值之前处理一些逻辑,使用newValue
获取新值
当调用dIDSet
的时候,属性的值已经变成了新值,要想获取原值可以使用oldValue
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不会在初始化阶段调用
因此,dIDSet
和willSet
对常量let没有意义,因为let只在初始化阶段赋值
如下的定义:
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 }}
进行如下的初始化,会发现Fontcolor
和backgroundcolor
为nil
:
let ui = UI()ui.themeModeui.Fontcolor//为nilui.backgroundcolor//为nil便利构造函数和指定构造函数
要注意的点:
1.构造函数参数可以有默认值
2.构造函数可以重载
两种构造器:
指定构造器-指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。
```init(parameters) { statements}```
便利构造器-便利构造器是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值
```convenIEnce init(parameters) { statements}```
注意:
1.只有指定构造函数可以调用super.init()
,便利构造函数不能调用super.init()
2.便利构造函数最终一定要调用一个指定的构造函数
一般来说,要让指定构造器不可失败,而让便利构造器可失败,如下的RocketComponent
类
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.关于父类的属性必须通过父类的构造函数来进行构造
2.在swifi语言中,必须将子类相关的所有量进行初始化之后,才能调用super.init()
3.在swift中整个构造函数可以分为2部分,顺序不能混淆
构造初值,在类没有构造完成的时候,不能使用self
。但是静态的方法和静态量在第一阶段是可以使用的
convenIEnce init(group: String = ""){ let name = User.generateUsername() self.init(name:name,group: group) } static func generateUsername() -> String{ return "Player" + String(rand()%1_000_000) }进一步完成类相关属性的值
如下:
init(name: String,group: String){ // Phase1: 从子类向父类初始化所有的变量 self.group = group super.init(name: name) // Phase2: 所有成员变量初始化完成以后,进行成员变量相关的逻辑调整 if self.group == ""{ getscore(-10) self.life -= 5 } }继承
final
表示类不可继承
如果子类实现了父类所有的指定构造函数,则自动继承父类的所有便利构造函数
required关键字
required
表示必须被子类所实现的构造函数
//父类 required init(name: String){ self.name = name } //子类 convenIEnce required init(name: String){ self.init(name: name,group: "") }
注意:
1.required
关键字标注的的构造函数,不需要写overrIDe
关键字
以上是内存溢出为你收集整理的Swift-枚举、结构体、类全部内容,希望文章能够帮你解决Swift-枚举、结构体、类所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)