Initialization 程式範例 — Apple’s The Swift Programming Language

彼得潘的 iOS App Neverland
7 min readSep 17, 2018

Initializers

struct Fahrenheit {   var temperature: Double   init() {      temperature = 32.0   }}var f = Fahrenheit()print("The default temperature is \(f.temperature)° Fahrenheit")// Prints "The default temperature is 32.0° Fahrenheit"

Default Property Values

struct Fahrenheit {   var temperature = 32.0}

Initialization Parameters

有參數的 init。

struct Celsius {   var temperatureInCelsius: Double   init(fromFahrenheit fahrenheit: Double) {      temperatureInCelsius = (fahrenheit - 32.0) / 1.8   }   init(fromKelvin kelvin: Double) {      temperatureInCelsius = kelvin - 273.15   }}let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)// boilingPointOfWater.temperatureInCelsius is 100.0let freezingPointOfWater = Celsius(fromKelvin: 273.15)// freezingPointOfWater.temperatureInCelsius is 0.0

Parameter Names and Argument Labels

struct Color {   let 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 veryGreen = Color(0.0, 1.0, 0.0)// this reports a compile-time error - argument labels are required

Initializer Parameters Without Argument Labels

利用 _ 取消 argument label。

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 bodyTemperature = Celsius(37.0)// bodyTemperature.temperatureInCelsius is 37.0

Optional Property Types

class SurveyQuestion {   var text: String   var response: String?   init(text: String) {      self.text = text   }   func ask() {      print(text)   }}let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")cheeseQuestion.ask()// Prints "Do you like cheese?"cheeseQuestion.response = "Yes, I do like cheese."

Assigning Constant Properties During Initialization

class SurveyQuestion {   let text: String   var response: String?   init(text: String) {      self.text = text   }   func ask() {      print(text)   }}let beetsQuestion = SurveyQuestion(text: "How about beets?")beetsQuestion.ask()// Prints "How about beets?"beetsQuestion.response = "I also like beets. (But not with cheese.)"

Default Initializers

當 property 在宣告時都有設定初始值,而且沒有另外定義 init 時,Swift 將自動生成沒有參數的 Default Initializer,init()。利用 default Initializer 生成東西時,東西的 property 將為當初宣告時設定的初始值。

class ShoppingListItem {   var name: String?   var quantity = 1   var purchased = false}var item = ShoppingListItem()

Memberwise Initializers for Structure Types

struct Size {   var width = 0.0, height = 0.0}let twoByTwo = Size(width: 2.0, height: 2.0)

Initializer Delegation for Value Types

struct Size {   var width = 0.0, height = 0.0}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)   }}let basicRect = Rect()// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)let originRect = Rect(origin: Point(x: 2.0, y: 2.0),size: Size(width: 5.0, height: 5.0))// originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0)let centerRect = Rect(center: Point(x: 4.0, y: 4.0),size: Size(width: 3.0, height: 3.0))// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

Initializer Inheritance and Overriding

class Vehicle {   var numberOfWheels = 0   var description: String {      return "\(numberOfWheels) wheel(s)"   }}let vehicle = Vehicle()print("Vehicle: \(vehicle.description)")// Vehicle: 0 wheel(s)class Bicycle: Vehicle {   override init() {      super.init()      numberOfWheels = 2   }}let bicycle = Bicycle()print("Bicycle: \(bicycle.description)")// Bicycle: 2 wheel(s)

Designated and Convenience Initializers in Action

class Food {   var name: String   init(name: String) {      self.name = name   }   convenience init() {      self.init(name: "[Unnamed]")    }}let mysteryMeat = Food()// mysteryMeat's name is "[Unnamed]"class RecipeIngredient: Food {     var quantity: Int   init(name: String, quantity: Int) {      self.quantity = quantity      super.init(name: name)   }   override convenience init(name: String) {      self.init(name: name, quantity: 1)   }}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 = truefor item in breakfastList {print(item.description)}// 1 x Orange juice ✔// 1 x Bacon ✘// 6 x Eggs ✘

Failable Initializers

inti? ,可能失敗的 init。生成的東西是 optional,失敗時會生成 nil。

let wholeNumber: Double = 12345.0let pi = 3.14159if let valueMaintained = Int(exactly: wholeNumber) {print("\(wholeNumber) conversion to Int maintains value of \(valueMaintained)")}// Prints "12345.0 conversion to Int maintains value of 12345"let valueChanged = Int(exactly: pi)// valueChanged is of type Int?, not Intif valueChanged == nil {print("\(pi) conversion to Int does not maintain value")}// Prints "3.14159 conversion to Int does not maintain value"

生成 Animal 時,當 species 是空字串時回傳 nil。

struct Animal {   let species: String   init?(species: String) {      if species.isEmpty { return nil }         self.species = species      }   }   let someCreature = Animal(species: "Giraffe")   // someCreature is of type Animal?, not Animal   if let giraffe = someCreature {      print("An animal was initialized with a species of \(giraffe.species)")   }   // Prints "An animal was initialized with a species of Giraffe"   let anonymousCreature = Animal(species: "")// anonymousCreature is of type Animal?, not Animal   if anonymousCreature == nil {      print("The anonymous creature could not be initialized")   }   // Prints "The anonymous creature could not be initialized"

Failable Initializers for Enumerations

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 fahrenheitUnit = TemperatureUnit(symbol: "F")if fahrenheitUnit != nil {   print("This is a defined temperature unit, so initialization succeeded.")}// Prints "This is a defined temperature unit, so initialization succeeded."let unknownUnit = TemperatureUnit(symbol: "X")if unknownUnit == nil {   print("This is not a defined temperature unit, so initialization failed.")}// Prints "This is not a defined temperature unit, so initialization failed."

Failable Initializers for Enumerations with Raw Values

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.")}// Prints "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.")}// Prints "This is not a defined temperature unit, so initialization failed."

Propagation of Initialization Failure

呼叫父類別的 init?,也可能造成失敗,得到 nil。

class Product {   let name: String   init?(name: String) {      if name.isEmpty { return nil }      self.name = name   }}class CartItem: Product {   let quantity: Int   init?(name: String, quantity: Int) {      if quantity < 1 { return nil }      self.quantity = quantity      super.init(name: name)   }}if let twoSocks = CartItem(name: "sock", quantity: 2) {   print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")}// Prints "Item: sock, quantity: 2"if let zeroShirts = CartItem(name: "shirt", quantity: 0) {   print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")} else {   print("Unable to initialize zero shirts")}// Prints "Unable to initialize zero shirts"if let oneUnnamed = CartItem(name: "", quantity: 1) {   print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")} else {   print("Unable to initialize one unnamed product")}// Prints "Unable to initialize one unnamed product"

Overriding a Failable Initializer

覆寫父類別的 Failable Initializer 時,也可以定義成 nonfailable initializer。不過如果在 nonfailable initializer 裡呼叫父類別的 Failable Initializer 時,要加 force-unwrap !。

class Document {   var name: String?   // this initializer creates a document with a nil name value   init() {}   // this initializer creates a document with a nonempty name value   init?(name: String) {      if name.isEmpty { return nil }      self.name = name   }}class AutomaticallyNamedDocument: Document {   override init() {      super.init()      self.name = "[Untitled]"   }   override init(name: String) {      super.init()      if name.isEmpty {         self.name = "[Untitled]"      } else {         self.name = name      }   }}class UntitledDocument: Document {   override init() {      super.init(name: "[Untitled]")!   }}

The init! Failable Initializer

除了定義 init?,也可以定義 init!。

Required Initializers

加了 required 的 initializers,子類別也要定義(或繼承)。

class SomeClass {   required init() {      // initializer implementation goes here   }}class SomeSubclass: SomeClass {   required init() {      // subclass implementation of the required initializer goes here   }}

Setting a Default Property Value with a Closure or Function

利用 closure 或 global function 設定 property。

例子:

西洋棋的格子。true 代表黑色,false 代表白色。

struct Chessboard {   let boardColors: [Bool] = {      var temporaryBoard = [Bool]()      var isBlack = false      for i in 1...8 {         for j in 1...8 {            temporaryBoard.append(isBlack)            isBlack = !isBlack         }         isBlack = !isBlack      }      return temporaryBoard   }()   func squareIsBlackAt(row: Int, column: Int) -> Bool {      return boardColors[(row * 8) + column]   }}let board = Chessboard()print(board.squareIsBlackAt(row: 0, column: 1))// Prints "true"print(board.squareIsBlackAt(row: 7, column: 7))// Prints "false"

--

--

彼得潘的 iOS App Neverland

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com