Swift 构造过程+析构过程(十三)

构造过程 (Initialization)

1.存储类型的初始赋值

类和结构在创建实例的时候,必须为所有的存储属性设置值,不能为nil

1.1构造器

构造器在创建某个特定类型的新实例的时候调用,最简形式类似不带参数的方法,以init命名
  1. structFahrenheit{
  2. vartemperature:Double
  3. init(){
  4. temperature=32.0
  5. }
  6. }
  7. varf=Fahrenheit()
  8. println("Thedefaulttemperatureis\(f.temperature)°Fahrenheit")
  9. //prints"Thedefaulttemperatureis32.0°Fahrenheit"

1.2默认属性值

在属性生命的时候直接为其设置默认值
    vartemperature=32.0
  1. }

2.定制化构造过程

2.1构造参数

在定义构造器的时候提供构造参数,语法跟函数和方法相同
    structCelsius{
  1. temperatureInCelsius:Double=0.0
  2. init(fromFahrenheitfahrenheit:Double){
  3. temperatureInCelsius=(fahrenheit-32.0)/1.8
  4. init(fromKelvinkelvin:Double){
  5. temperatureInCelsius=kelvin-273.15
  6. letboilingPointOfWater=Celsius(fromFahrenheit:212.0)
  7. //boilingPointOfWater.temperatureInCelsiusis100.0
  8. letfreezingPointOfWater=Celsius(fromKelvin:273.15)
  9. //freezingPointOfWater.temperatureInCelsiusis0.0

2.2内部和外部参数名

构造函数存在一个构造器内部使用的参数名和一个在调用时使用的外部参数名,如果没有提供参数的外部名字,Swift会自动为每个构造器的参数生成一个跟内部参数名相同的外部参数名
    structColor{
  1. letred=0.0,green=0.0,blue=0.0
  2. init(red:Double,green:Double,blue:Double){
  3. self.red=red
  4. self.green=green
  5. self.blue=blue
  6. letmagenta=Color(red:1.0,0); background-color:inherit">green:0.0,0); background-color:inherit">blue:1.0)
  7. //如果不通过外部参数名传值,编译时无法通过
  8. letveryGreen=Color(0.0,1.0,0.0)
  9. //thisreportsacompile-timeerror-externalnamesarerequired

2.3可选属性类型

如果定义的类型包含一个可以为空的存储型属性,需要将其定义为可选类型 (optional type), 则自动初始化为nil,表示这个属性是故意初始化设置为空的
    classSurveyQuestion{
  1. text:String
  2. varresponse:String?
  3. init(text:String){
  4. self.text=text
  5. funcask(){
  6. println(text)
  7. letcheeseQuestion=SurveyQuestion(text:"Doyoulikecheese?")
  8. cheeseQuestion.ask()
  9. //prints"Doyoulikecheese?"
  10. cheeseQuestion.response="Yes,Idolikecheese."

2.4构造过程中常量的修改

只要在构造过程结束后能确定常量的值,就可以在构造过程之中随意修改常量的值
    //尽管text属性是常量,但在构造过程之中还是可以修改的,构造过程结束时候不能再修改
  1. classSurveyQuestion{
  2. lettext:String
  3. response:String?
  4. init(text:String){
  5. self.text=text
  6. funcask(){
  7. println(text)
  8. letbeetsQuestion=SurveyQuestion(text:"Howaboutbeets?")
  9. beetsQuestion.ask()
  10. //prints"Howaboutbeets?"
  11. beetsQuestion.response="Ialsolikebeets.(Butnotwithcheese.)"

3.默认构造器

Swift为素有属性已提供默认值的但自身没有构造器的结构体或基类提供一个默认的构造器,构造器创建一个将所有属性值都设置为默认值的实例
    classShoppingListItem{
  1. name:String?
  2. varquantity=1
  3. varpurchased=false
  4. varitem=ShoppingListItem()
  5. structSize{
  6. varwidth=0.0,height=0.0
  7. lettwoByTwo=Size(width:2.0,0); background-color:inherit">height:2.0)

4.值类型的构造器代理

构造器通过调用其他构造器来完成实例的部分构造,提高代码利用率,称为构造器的代理
    structPoint{
  1. varx=0.0,y=0.0
  2. structRect{
  3. varorigin=Point()
  4. varsize=Size()
  5. init(){}
  6. init(origin:Point,0); background-color:inherit">size:Size){
  7. self.origin=origin
  8. self.size=size
  9. init(center:Point,248)"> letoriginX=center.x-(size.width/2)
  10. letoriginY=center.y-(size.height/2)
  11. self.init(origin:Point(x:originX,0); background-color:inherit">y:originY),0); background-color:inherit">size:size)
  12. letbasicRect=Rect()
  13. //basicRect'soriginis(0.0,0.0)anditssizeis(0.0,0.0)
  14. letoriginRect=Rect(origin:Point(x:2.0,0); background-color:inherit">y:2.0),
  15. size:Size(width:5.0,0); background-color:inherit">height:5.0))
  16. //originRect'soriginis(2.0,2.0)anditssizeis(5.0,5.0)

5.类的继承和构造过程

类里所有的存储类型属性包括继承父类的属性都需要在构造过程中设置初始值,Swift提供两种类型的类构造器来确保所有类实例中的存储属性都能获得初始值

5.1指定构造器和便利构造器

指定构造器是类中最主要的构造器,将初始化类中所提供的所有属性,每个类至少需要一个指定构造器,便利构造器是辅助型的构造器,可调用同一类中的指定构造器,并为其参数提供默认值

5.2构造器链

Swift采用三条规则来限制构造器之间的代理调用
a.指定构造器必须调用其直接父类的指定构造器
b.便利构造器必须调用同一类中定义的其他构造器
c.便利构造器最终必须调用一个指定构造器结束
(指定构造器总是向上代理,便利构造器总是横向代理)

5.3构造器的继承和重载

Swift中的子类默认不会继承父类的构造器,防止父类的简单构造被子类继承,并错误的创建子类的实例,如果希望子类能继承父类相同的构造器,需要定制子类的构造器

5.4指定构造器和便利构造器的语法

    init(parameters){
  1. statements
  2. //便利构造器前置convenience关键字
  3. convenienceinit(parameters){
  4. classFood{
  5. name:String
  6. init(name:String){
  7. self.name=name
  8. convenienceinit(){
  9. self.init(name:"[Unnamed]")
  10. letnamedMeat=Food(name:"Bacon")
  11. //namedMeat'snameis"Bacon"
  12. letmysteryMeat=Food()
  13. //mysteryMeat'snameis"[Unnamed]"
  14. classRecipeIngredient:Food{
  15. quantity:Int
  16. init(name:String,0); background-color:inherit">quantity:Int){
  17. self.quantity=quantity
  18. super.init(name:name)
  19. convenienceinit(name:String){
  20. self.init(name:name,0); background-color:inherit">quantity:1)
  21. letoneMysteryItem=RecipeIngredient()
  22. letoneBacon=RecipeIngredient(name:"Bacon")
  23. letsixEggs=RecipeIngredient(name:"Eggs",0); background-color:inherit">quantity:6)
  24. ShoppingListItem:RecipeIngredient{
  25. varpurchased=false
  26. description:String{
  27. varoutput="\(quantity)x\(name.lowercaseString)"
  28. output+=purchased?"✔":"✘"
  29. returnoutput
  30. varbreakfastList=[
  31. ShoppingListItem(),
  32. ShoppingListItem(name:"Bacon"),
  33. ShoppingListItem(name:"Eggs",0); background-color:inherit">quantity:6),108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> ]
  34. breakfastList[0].name="Orangejuice"
  35. breakfastList[0].purchased=true
  36. foriteminbreakfastList{
  37. println(item.description)
  38. //1xorangejuice✔
  39. //1xbacon✘
  40. //6xeggs✘

6.通过闭包和函数来设置属性的默认值

属性可以使用闭包或全局函数来提供默认值,当创建新实例时,对应的闭包或函数就会被调用,返回值当做这个属性的默认值
    //闭包结尾的大括号后接空得小括号,告诉Swift立刻执行此闭包,如果忽略这个括号,相当于闭包本身作为值赋给属性,而不是将闭包的返回值赋给属性
  1. classSomeClass{
  2. someProperty:SomeType={
  3. //createadefaultvalueforsomePropertyinsidethisclosure
  4. //someValuemustbeofthesametypeasSomeType
  5. returnsomeValue
  6. }()
  7. structCheckerboard{
  8. boardColors:Bool[]={
  9. vartemporaryBoard=Bool[]()
  10. varisBlack=foriin1...10{
  11. forjin1...10{
  12. temporaryBoard.append(isBlack)
  13. isBlack=!isBlack
  14. returntemporaryBoard
  15. }()
  16. funcsquareIsBlackAtRow(row:Int,0); background-color:inherit">column:Int)->Bool{
  17. returnboardColors[(row*10)+column]
  18. letboard=Checkerboard()
  19. println(board.squareIsBlackAtRow(0,0); background-color:inherit">column:1))
  20. //prints"true"
  21. println(board.squareIsBlackAtRow(9,0); background-color:inherit">column:9))
  22. //prints"false"


析构过程 (Deinitialization)

类的实例被释放之前,析构函数被立即调用,deinit表示析构过程

1.原理

Swift会自动释放不需要的实例以释放资源,但当使用自己的资源的时候,需要清理额外的信息,如创建一个自定义的类来打开文件并写入数据,可能需要在类实例被释放之前关闭该文件
每个类组多只有一个析构函数,不允许主动调用,在实例被释放的前一步被自动调用,因为析构函数知道实例被释放才会被调用,所以可以访问实例的所有属性,并进行操作
    deinit{
  1. //performthedeinitialization
  2. }

2.操作

    structBank{
  1. staticvarcoinsInBank=10_000
  2. staticfuncvendCoins(varnumberOfCoinsTovend:Int)->Int{
  3. numberOfCoinsTovend=min(numberOfCoinsTovend,coinsInBank)
  4. coinsInBank-=numberOfCoinsTovend
  5. returnnumberOfCoinsTovend
  6. staticfuncreceiveCoins(coins:Int){
  7. coinsInBank+=coins
  8. classPlayer{
  9. coinsInPurse:Int
  10. init(coins:Int){
  11. coinsInPurse=Bank.vendCoins(coins)
  12. funcwinCoins(coins:Int){
  13. coinsInPurse+=Bank.vendCoins(coins)
  14. deinit{
  15. Bank.receiveCoins(coinsInPurse)
  16. playerOne:Player?=Player(coins:100)
  17. println("Anewplayerhasjoinedthegamewith\(playerOne!.coinsInPurse)coins")
  18. //prints"Anewplayerhasjoinedthegamewith100coins"
  19. println("ThereareNow\(Bank.coinsInBank)coinsleftinthebank")
  20. //prints"ThereareNow9900coinsleftinthebank"
  21. playerOne!.winCoins(2_000)
  22. println("PlayerOnewon2000coins&Nowhas\(playerOne!.coinsInPurse)coins")
  23. //prints"PlayerOnewon2000coins&Nowhas2100coins"
  24. println("ThebankNowonlyhas\(Bank.coinsInBank)coinsleft")
  25. //prints"ThebankNowonlyhas7900coinsleft"
  26. playerOne=nil
  27. println("PlayerOnehasleftthegame")
  28. //prints"PlayerOnehasleftthegame"
  29. println("ThebankNowhas\(Bank.coinsInBank)coins")
  30. //prints"ThebankNowhas10000coins"

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...