美文网首页
Swift11 - 构造过程/可选链式调用

Swift11 - 构造过程/可选链式调用

作者: 暗物质 | 来源:发表于2020-06-12 17:27 被阅读0次

    基类-不继承其他类的类
    Swift 中的类并不是从一个通用的基类继承而来的
    重写 - 子类可以为继承来的实例方法,类方法,实例属性,类属性,或下标提供自己定制的实现, 前面加上 override 关键字
    你可以通过把方法,属性或下标标记为 final 来防止它们被重写(final class)来将整个类标记为 final 。这样的类是不可被继承的

    构造过程

    构造过程中常量属性的赋值
    你可以在构造过程中的任意时间点给常量属性赋值,只要在构造过程结束时它设置成确定的值。一旦常量属性被赋值,它将永远不可更改。
    指定构造器是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并调用合适的父类构造器让构造过程沿着父类链继续往上进行。
    类倾向于拥有极少的指定构造器,普遍的是一个类只拥有一个指定构造器
    便利构造器是类中比较次要的、辅助型的构造器。

    指定构造器
    init(parameters) {
        statements
    }
    便利构造器
    convenience init(parameters) {
        statements
    }
    

    指定构造器必须调用其直接父类的的指定构造器。
    便利构造器必须调用同类中定义的其它构造器。
    便利构造器最后必须调用指定构造器。

    接下来的例子将在实践中展示指定构造器、便利构造器以及构造器的自动继承:

    class Food {
        var name: String
        init(name: String) { //指定构造器
            self.name = name
        }
        
        convenience init() { //Food 类同样提供了一个没有参数的便利构造器 init()
            self.init(name: "")
        }
    }
    
    let namedMeat = Food(name: "Bacon") // namedMeat 的名字是 "Bacon"
    let mysteryMeat = Food() // mysteryMeat 的名字是 [Unnamed]
    
    
    class RecipeIngredient: Food {
        var quantity: Int
        init(name: String, quantity: Int) {
            self.quantity = quantity
            super.init(name: name)
        }
        convenience override init(name: String) { //便利构造器重写了父类的指定构造器 init(name: String),因此必须在前面使用 override 修饰符
            self.init(name: name, quantity: 1)
        }
    }
    //所有的这三种构造器都可以用来创建新的 RecipeIngredient 实例:
    let oneMysteryItem = RecipeIngredient()
    let oneBacon = RecipeIngredient(name: "Bacon")
    let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
    
    class ShoppingListItem: RecipeIngredient {
        var purchased = false
        var description: String {
            var output = "\(quantity) x \(name)"
            output += purchased ? "✅" : "❌"
            return output
        }
    }
    
    var breakfastList = [
        ShoppingListItem(),
        ShoppingListItem(name: "Bacon"),
        ShoppingListItem(name: "Eggs", quantity: 6)
    ]
    breakfastList[0].name = "Orange juice"
    breakfastList[0].purchased = true
    for item in breakfastList {
        print(item.description)
    }
    // 1 x orange juice ✔
    // 1 x bacon ✘
    // 6 x eggs ✘
    
    

    可失败构造器
    带原始值的枚举类型会自带一个可失败构造器 init?(rawValue:),该可失败构造器有一个合适的原始值类型的 rawValue 形参,选择找到的相匹配的枚举成员,找不到则构造失败。

    struct Animal {
        let species: String
        init?(species: String) {
            if species.isEmpty {
                return nil
            }
            self.species = species
        }
    }
    //枚举类型的可失败构造器
    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
            }
        }
    }
    let unknownUnit = TemperatureUnit(symbol: "X") //nil
    

    必要构造器

    class SomeClass {
        required init() {
            // 构造器的实现代码
        }
    }
    

    可选链式调用

    可选链式调用是一种可以在当前值可能为 nil 的可选值上请求和调用属性、方法及下标的方法。
    如果可选值有值,那么调用就会成功;如果可选值是 nil,那么调用将返回 nil。
    多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为 nil,整个调用链都会失败,即返回 nil。

    class Person {
        var residence: Residence?
    }
    
    class Residence {
        var rooms = [Room]()
        var numberOfRooms: Int {
            return rooms.count
        }
        subscript(i: Int) -> Room {
            get {
                return rooms[i]
            }
            set {
                rooms[i] = newValue
            }
        }
        func printNumberOfRooms() {
            print("The number of rooms is \(numberOfRooms)")
        }
        
        var address: Address?
    }
    
    class Address {
        var buildingName: String?
        var buildingNumber: String?
        var street: String?
        func buildingIdentifier() -> String? {
            if buildingName != nil {
                return buildingName
            } else if let buildingNumber = buildingNumber, let street = street {
                return "\(buildingNumber) \(street)"
            } else {
                return nil
            }
        }
    }
    
    class Room {
        let name: String
        init(name: String) {
            self.name = name
        }
    }
    
    let john = Person()
    //可选链式调用提供了另一种访问 numberOfRooms 的方式
    if let roomCount = john.residence?.numberOfRooms {
        print("John's residence has \(roomCount) room(s).")
    }else {
        print("Unable to retrieve the number of rooms.")
    }
    // 打印“Unable to retrieve the number of rooms.”
    //将一个 Residence 的实例赋给 john.residence,这样它就不再是 nil 了:
    john.residence = Residence()
    if let roomCount = john.residence?.numberOfRooms {
        print("John's residence has \(roomCount) room(s).")
    }else {
        print("Unable to retrieve the number of rooms.")
    }
    // 打印“John's residence has 1 room(s).”
    
    
    let someAddress = Address()
    someAddress.buildingNumber = "29"
    someAddress.street = "Acacia Road"
    john.residence?.address = someAddress
    //等号右侧的代码不会被执行。对于上面的代码来说,很难验证这一点,因为像这样赋值一个常量没有任何副作用
    
    //用一个函数来创建 Address 实例,然后将该实例返回用于赋值。该函数会在返回前打印“Function was called”,这使你能验证等号右侧的代码是否被执行。
    func createAddress() -> Address {
        print("Function was called.")
        
        let someAddress = Address()
        someAddress.buildingNumber = "29"
        someAddress.street = "Acacia Road"
    
        return someAddress
    }
    john.residence?.address = createAddress()
    
    //在可选值上通过可选链式调用来调用这个方法,该方法的返回类型会是 Void?
    if john.residence?.printNumberOfRooms() != nil {
        print("It was possible to print the number of rooms.")
    } else {
        print("It was not possible to print the number of rooms.")
    }
    //同样的,可以据此判断通过可选链式调用为属性赋值是否成功。
    if (john.residence?.address = someAddress) != nil {
        print("It was possible to set the address.")
    }else {
        print("It was not possible to set the address.")
    }
    
    
    
    //通过可选链式调用访问可选值的下标时,应该将问号放在下标方括号的前面而不是后面
    let johnsHouse = Residence()
    johnsHouse.rooms.append(Room(name: "Living Room"))
    johnsHouse.rooms.append(Room(name: "Kitchen"))
    john.residence = johnsHouse
    if let firstRoomName = john.residence?[0].name {
        print("The first room name is \(firstRoomName).")
    }else {
        print("Unable to retrieve the first room name.")
    }
    john.residence?[0] = Room(name: "Bathroom")
    
    // 在方法的可选返回值上进行可选链式调用
    if let beginsWithThe =
        john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
            if beginsWithThe {
                print("John's building identifier begins with \"The\".")
            } else {
                print("John's building identifier does not begin with \"The\".")
            }
    }
    

    相关文章

      网友评论

          本文标题:Swift11 - 构造过程/可选链式调用

          本文链接:https://www.haomeiwen.com/subject/egkstktx.html