Swift/初期化
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
&tag(Swift/初期化);
*目次 [#w2403ff2]
#contents
*関連ページ [#we2ee0c2]
*参考情報 [#b5a07582]
-[[The Swift Programming Language (Swift 4): Initializati...
*基本 [#fa706c14]
-クラスや構造体の使用するための準備。
-プロパティの設定やその他初期化処理を行う。
*プロパティへの初期値の設定 [#w32225f4]
-クラスや構造体は保存プロパティに適切な値を設定して初期化...
-initializerやプロパティ定義時のデフォルト値を使用する
**initializers [#o0ee8dde]
-initializerは特定の型のインスタンスを生成する際呼び出さ...
#pre{{
init() {
// perform some initialization here
}
}}
-以下の構造体はtemperatureプロパティを初期化する。
#pre{{
truct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahre...
// Prints "The default temperature is 32.0° Fahrenheit"
}}
**デフォルトプロパティ値 [#y742c939]
-以下のように初期化することもできる。
#pre{{
struct Fahrenheit {
var temperature = 32.0
}
}}
*カスタム初期化 [#nf992807]
-入力パラメータとオプショナルプロパティの型、定数プロパテ...
**初期化パラメータ [#hceda12c]
-初期化パラメータをinitializerに渡すことができる。摂氏ま...
#pre{{
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.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0
}}
***パラメータ名と引数ラベル [#u5ecffe4]
-関数と同じようにinitializerの本体で使用できるパラメータ...
-しかしinitializerは独自の名前をもたないので、Swiftは独自...
#pre{{
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)
}}
**引数ラベルなしのイニシャライザ [#m3009a6e]
-引数ラベルが不要な場合"_"を指定する。
#pre{{
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
}}
**オプショナルプロパティタイプ [#zc542b41]
-カスタムタイプが保存プロパティを持つ場合、そしてそのプロ...
-以下の例ではresponseがnilで初期化される。
#pre{{
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 ch...
cheeseQuestion.ask()
// Prints "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."
}}
**初期化中の定数プロパティの割り当て [#t202631f]
-初期化中に定数プロパティに値を割り当てることができる。
-一度値がわりあてられるとその後変更することはできない。
-以下の例ではtextプロパティが割り当てられる。
#pre{{
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 wit...
}}
*デフォルトinitializers [#l7b90fcf]
-Swiftは構造体やクラスにinitializerが一つも存在しない場合...
-以下の例ではデフォルト値で初期化されたインスタンスが生成...
#pre{{
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
}}
-ShoppingListItemの全てのプロパティはデフォルト値を持ち、...
**構造体のためのMemberwise initializer [#q44a6e3a]
-構造体の場合カスタムinitializerが存在しない場合、memberw...
-memberwise initializerは、プロパティを初期化できるイニシ...
#pre{{
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
}}
*値型のためのinitializer delegation [#la450571]
-initializerはほかのinitializerを呼び出すことができる。こ...
-initializer delegationの仕組みは値型とクラス型によって異...
-値型(構造体と列挙型)は継承をサポートしておらず、initiali...
-しかしクラス型は他のクラスを継承できるので、保存型プロパ...
-値型の場合self.initを利用して他のinitializerを呼び出すこ...
-値型でカスタムinitializerを作成した場合、デフォルトiniti...
-これによって作成されたinitializerを回避する、デフォルトi...
-Rect構造体は、Size、Pointをプロパティとして持つ。
#pre{{
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), ...
}
}
}}
-ユーザーは3つの方法でRectを初期化できる。
--ゼロで初期化
#pre{{
let basicRect = Rect()
// basicRect's origin is (0.0, 0.0) and its size is (0.0,...
}}
--原点で初期化
#pre{{
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...
}}
--中心で初期化
#pre{{
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...
}}
*クラス継承と初期化 [#j7f2274c]
-全てのクラスの保存プロパティは初期化中に値を割り当てられ...
-Swiftはこれを確実にするためクラス型に2種類のinitializer...
-それはdesignated initialzerとconvenience initializerとし...
**Designated initializerとConvenience Initializer [#le9d2...
-Designated initializer(指定イニシャライザ)は、クラスの中...
-クラスの全てのプロパティを初期化し、スーパークラスの適切...
-クラスは通常一つあるい少数の指定イニシャライザを持ち、
-Designated initializerは初期化処理が注ぎ込まれる場所で、...
-全てのクラスは最低一つのdesignated initializerを持つ必要...
-Automatic Initializer inheritanceによってスーパークラス...
-Convenience Initializerは、2番目のinitializerである。同...
**Designated initializerとConvenience Initializerのシンタ...
-Designated initializerは値型のためのinitializerと同じよ...
#pre{{
init(parameters) {
statements
}
}}
-Convenience Initializerは以下のようなmodifierを指定する。
#pre{{
convenience init(parameters) {
statements
}
}}
**クラス型のためのinitializer delegation [#ue9f1c99]
-designated、convenience initializerの関連をシンプルかす...
--Rule 1: designated initializerは、直近のスーパークラス...
--Rule 2: convenience initializerは同じクラスのinitialize...
--Rule 3: convenience initializerは最終的にはdesignated i...
-これを覚えるには
--designated initializerは常に上位に委譲する。
--convenience initializerは常に同じクラス内で委譲する。
※Appleサイトに分かりやすい図がある。
**ツーフェーズinitialization [#jd086fda]
-Swiftのクラスの初期化は2フェーズ。
-最初のフェーズではそのクラスの保存プロパティの初期化で、...
-2フェーズの初期化プロセスは、初期化を安全に行う。プロパ...
-Swiftのコンパイラは初期化がエラーなしに完成したか確認す...
--Safety check 1: クラスのプロパティがスーパークラスのプ...
--Safety check 2: designated initializeは継承プロパティに...
--Safety check 3: convenience initializerはプロパティにア...
--Safety check 4: initializerはインスタンスメソッドを呼び...
-インスタンスは最初のフェーズが終了するまで完全ではない。...
-これに基づき初期化は以下の手順で行われる。
-Phase 1:
--designated or convenience initializerが呼び出される。
--クラスの新しいインスタンスのメモリが割り当てられる。メ...
--designated initializerはクラスで導入された保存プロパテ...
--designated initializerはスーパークラスのinitializerを呼...
--継承チェーンを辿りトップまで繰り返す。
--トップに到達するとインスタンスのメモリの初期化が完了し...
-Phase 2:
--継承チェーンを戻り、それぞれのdesignated initializerは...
--最終的にconvenience initializerにもそのチャンスが巡って...
**initializer継承とオーバーライド [#d25956e4]
-Objective-Cと異なり、Swiftのサブクラスはスーパークラスの...
-Swiftの方法はサブクラスの複雑なinitializerが呼び出されず...
-もしスーパクラスと同じinitializerを定義したい場合、サブ...
-もしスーパークラスと全く同じdesignated initializerを定義...
-overrideモディファイアが存在すると、Swiftはスーパークラ...
-逆にサブクラスのinitializerがスーパークラスのconvenience...
-よって厳密にいえば、overrideはスーパークラスのconvenienc...
-以下の例を考える。
#pre{{
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
}}
-Vehicleクラスはデフォルト値を提供し、カスタムinitializer...
-デフォルトinitializerは自動的にdesignated initializerと...
#pre{{
class Bicycle: Vehicle {
override init() {
super.init()
numberOfWheels = 2
}
}
}}
-Bicycleはカスタムdesignated initializerを定義する。これ...
-init()はsuper.init()から始まる。これはnumberOfWheelsが初...
**自動initializer継承 [#sf0cd1a8]
-サブクラスは自動でinitializerを継承しない。しかし特定の...
-これによって多くの場合、サブクラスでoverrideする必要がな...
-サブクラスでデフォルト値を定義していたと想定すると、以下...
--Rule 1: サブクラスがdesignated initializerを定義してい...
--Rule 2: サブクラスがスーパークラスの全てのdesignated in...
**Designated and Convenience Initializerの動作 [#meb922e1]
-以下の例は、designated initializer、convenience initiali...
-Food、RecipeIngredient、ShoppingListItemがからむ。
#pre{{
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
}}
-Foodクラスはdesignated initializerとconvenience initiali...
-2番目のクラスはRecipeIngredientでFoodを継承する。
#pre{{
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)
}
}
}}
-RecipeIngredientは一つのdesignated initialzierと一つのco...
-convenience initializerはスーパークラスのinitializerと同...
-RecipeIngredientは全てのスーパークラスのdesignated initi...
-最後のクラスはRecipeIngredientのサブクラスであるShopping...
#pre{{
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}}
-プロパティにはデフォルト値が提供されていて独自のinitiali...
#pre{{
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)
}
}}
*Failable Initializers [#p97d2813]
-失敗する可能性のあるinitializerを定義できる。init?を使用...
-failable initializerはreturn nilによって失敗を表す。
#pre{{
let wholeNumber: Double = 12345.0
let pi = 3.14159
if let valueMaintained = Int(exactly: wholeNumber) {
print("\(wholeNumber) conversion to Int maintains val...
}
// Prints "12345.0 conversion to Int maintains value of 1...
let valueChanged = Int(exactly: pi)
// valueChanged is of type Int?, not Int
if valueChanged == nil {
print("\(pi) conversion to Int does not maintain valu...
}
// Prints "3.14159 conversion to Int does not maintain va...
}}
-例えば以下のように定義できる。
#pre{{
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 \(...
}
// Prints "An animal was initialized with a species of Gi...
}}
**Failabe Initializer for Enumerations [#y76c4b12]
-列挙型と組み合わせる。
#pre{{
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
}
}
}
}}
**Failable Initializer for Enumerations with Raw Values [...
-列挙型はrawValueを受け取るinitializerを自動で作成する。
#pre{{
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 initial...
}
// Prints "This is a defined temperature unit, so initial...
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so ini...
}
// Prints "This is not a defined temperature unit, so ini...
}}
**初期化失敗の伝達 [#obfa8713]
-初期化の失敗を伝達することを考える。
#pre{{
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)
}
}
}}
-スーパークラス、サブクラスどちらの条件が満たされなくても...
**Failable Initializerのオーバーライド [#iae0b14b]
-failable initializerはオーバーライドできる。またはスーパ...
#pre{{
class Document {
var name: String?
// this initializer creates a document with a nil nam...
init() {}
// this initializer creates a document with a nonempt...
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
}
}
}
}}
-AutomaticallyNamedDocumentはinit?をオーバーライドし、失...
-サブクラスでは強制アンラッピングをinitializerの中で呼び...
#pre{{
class UntitledDocument: Document {
override init() {
super.init(name: "[Untitled]")!
}
}
}}
**init! failable initializer [#t8a73101]
-失敗する可能性のあるinitializerとして普通はinit?を使うが...
*Required Initializers [#n90a3ab4]
-requiredモディファイアは、全てのサブクラスが実装しなけれ...
#pre{{
required init() {
// initializer implementation goes here
}
}
}}
-サブクラスでもrequiredをつけて実装する。
#pre{{
class SomeSubclass: SomeClass {
required init() {
// subclass implementation of the required initia...
}
}
}}
*Closure or Functionによるデフォルト値の設定 [#w12fc5cc]
-プロパティは以下のように実装できる。
#pre{{
class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside...
// someValue must be of the same type as SomeType
return someValue
}()
}
}}
-以下のような複雑な初期化も可能。
#pre{{
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]
}
}
}}
*落ち穂拾い [#zfbe932d]
**サブクラスからのsuper.init()の呼び出し [#qc71230b]
-[[【備忘録】initの動作検証 - Qiita:http://qiita.com/akik...
-サブクラスのイニシャライザからsuper.init()を呼び出せば、...
#pre{{
//super.init()の有無による実行順序の違い
class Parent {
let name = "Parent name"
init() {
print("\(name)")
}
}
class Child : Parent{
let childName = "Child name"
override init() {
// super.init()
print("\(childName)")
}
}
let child = Child()
//以下がprintされる。
//Parent name
//Child name
//
//super.init()をコメントアウトすると逆転する
//Child name
//Parent name
}}
**super.init()の自動呼び出し [#t84766db]
-[[[swift-users] super.init() called automatically?:https...
#pre{{
//super.init()の自動呼び出し。
//引数なしの一つのdesignated initializerが存在する場合、...
class Foo {
init() {
print("foo init")
}
}
class Bar: Foo {
init(x: Int) {
print("bar init")
}
}
let bar = Bar(x: 10)
//bar init
//foo init
}}
-対して以下の場合は自動で呼び出されない。
#pre{{
//super.init()が自動で呼び出されない場合。
class Parent2 {
let name: String
init(name: String) {
self.name = name
print("Parent2=\(name)")
}
init() {
self.name = "Unknown"
}
}
class Child2: Parent2 {
let childName: String
override init(name: String) {
self.childName = name
// super.init(name: name + "'s parent")
super.init()
}
}
let child2 = Child2(name: "abc")
}}
終了行:
&tag(Swift/初期化);
*目次 [#w2403ff2]
#contents
*関連ページ [#we2ee0c2]
*参考情報 [#b5a07582]
-[[The Swift Programming Language (Swift 4): Initializati...
*基本 [#fa706c14]
-クラスや構造体の使用するための準備。
-プロパティの設定やその他初期化処理を行う。
*プロパティへの初期値の設定 [#w32225f4]
-クラスや構造体は保存プロパティに適切な値を設定して初期化...
-initializerやプロパティ定義時のデフォルト値を使用する
**initializers [#o0ee8dde]
-initializerは特定の型のインスタンスを生成する際呼び出さ...
#pre{{
init() {
// perform some initialization here
}
}}
-以下の構造体はtemperatureプロパティを初期化する。
#pre{{
truct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahre...
// Prints "The default temperature is 32.0° Fahrenheit"
}}
**デフォルトプロパティ値 [#y742c939]
-以下のように初期化することもできる。
#pre{{
struct Fahrenheit {
var temperature = 32.0
}
}}
*カスタム初期化 [#nf992807]
-入力パラメータとオプショナルプロパティの型、定数プロパテ...
**初期化パラメータ [#hceda12c]
-初期化パラメータをinitializerに渡すことができる。摂氏ま...
#pre{{
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.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0
}}
***パラメータ名と引数ラベル [#u5ecffe4]
-関数と同じようにinitializerの本体で使用できるパラメータ...
-しかしinitializerは独自の名前をもたないので、Swiftは独自...
#pre{{
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)
}}
**引数ラベルなしのイニシャライザ [#m3009a6e]
-引数ラベルが不要な場合"_"を指定する。
#pre{{
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
}}
**オプショナルプロパティタイプ [#zc542b41]
-カスタムタイプが保存プロパティを持つ場合、そしてそのプロ...
-以下の例ではresponseがnilで初期化される。
#pre{{
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 ch...
cheeseQuestion.ask()
// Prints "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."
}}
**初期化中の定数プロパティの割り当て [#t202631f]
-初期化中に定数プロパティに値を割り当てることができる。
-一度値がわりあてられるとその後変更することはできない。
-以下の例ではtextプロパティが割り当てられる。
#pre{{
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 wit...
}}
*デフォルトinitializers [#l7b90fcf]
-Swiftは構造体やクラスにinitializerが一つも存在しない場合...
-以下の例ではデフォルト値で初期化されたインスタンスが生成...
#pre{{
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
}}
-ShoppingListItemの全てのプロパティはデフォルト値を持ち、...
**構造体のためのMemberwise initializer [#q44a6e3a]
-構造体の場合カスタムinitializerが存在しない場合、memberw...
-memberwise initializerは、プロパティを初期化できるイニシ...
#pre{{
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
}}
*値型のためのinitializer delegation [#la450571]
-initializerはほかのinitializerを呼び出すことができる。こ...
-initializer delegationの仕組みは値型とクラス型によって異...
-値型(構造体と列挙型)は継承をサポートしておらず、initiali...
-しかしクラス型は他のクラスを継承できるので、保存型プロパ...
-値型の場合self.initを利用して他のinitializerを呼び出すこ...
-値型でカスタムinitializerを作成した場合、デフォルトiniti...
-これによって作成されたinitializerを回避する、デフォルトi...
-Rect構造体は、Size、Pointをプロパティとして持つ。
#pre{{
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), ...
}
}
}}
-ユーザーは3つの方法でRectを初期化できる。
--ゼロで初期化
#pre{{
let basicRect = Rect()
// basicRect's origin is (0.0, 0.0) and its size is (0.0,...
}}
--原点で初期化
#pre{{
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...
}}
--中心で初期化
#pre{{
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...
}}
*クラス継承と初期化 [#j7f2274c]
-全てのクラスの保存プロパティは初期化中に値を割り当てられ...
-Swiftはこれを確実にするためクラス型に2種類のinitializer...
-それはdesignated initialzerとconvenience initializerとし...
**Designated initializerとConvenience Initializer [#le9d2...
-Designated initializer(指定イニシャライザ)は、クラスの中...
-クラスの全てのプロパティを初期化し、スーパークラスの適切...
-クラスは通常一つあるい少数の指定イニシャライザを持ち、
-Designated initializerは初期化処理が注ぎ込まれる場所で、...
-全てのクラスは最低一つのdesignated initializerを持つ必要...
-Automatic Initializer inheritanceによってスーパークラス...
-Convenience Initializerは、2番目のinitializerである。同...
**Designated initializerとConvenience Initializerのシンタ...
-Designated initializerは値型のためのinitializerと同じよ...
#pre{{
init(parameters) {
statements
}
}}
-Convenience Initializerは以下のようなmodifierを指定する。
#pre{{
convenience init(parameters) {
statements
}
}}
**クラス型のためのinitializer delegation [#ue9f1c99]
-designated、convenience initializerの関連をシンプルかす...
--Rule 1: designated initializerは、直近のスーパークラス...
--Rule 2: convenience initializerは同じクラスのinitialize...
--Rule 3: convenience initializerは最終的にはdesignated i...
-これを覚えるには
--designated initializerは常に上位に委譲する。
--convenience initializerは常に同じクラス内で委譲する。
※Appleサイトに分かりやすい図がある。
**ツーフェーズinitialization [#jd086fda]
-Swiftのクラスの初期化は2フェーズ。
-最初のフェーズではそのクラスの保存プロパティの初期化で、...
-2フェーズの初期化プロセスは、初期化を安全に行う。プロパ...
-Swiftのコンパイラは初期化がエラーなしに完成したか確認す...
--Safety check 1: クラスのプロパティがスーパークラスのプ...
--Safety check 2: designated initializeは継承プロパティに...
--Safety check 3: convenience initializerはプロパティにア...
--Safety check 4: initializerはインスタンスメソッドを呼び...
-インスタンスは最初のフェーズが終了するまで完全ではない。...
-これに基づき初期化は以下の手順で行われる。
-Phase 1:
--designated or convenience initializerが呼び出される。
--クラスの新しいインスタンスのメモリが割り当てられる。メ...
--designated initializerはクラスで導入された保存プロパテ...
--designated initializerはスーパークラスのinitializerを呼...
--継承チェーンを辿りトップまで繰り返す。
--トップに到達するとインスタンスのメモリの初期化が完了し...
-Phase 2:
--継承チェーンを戻り、それぞれのdesignated initializerは...
--最終的にconvenience initializerにもそのチャンスが巡って...
**initializer継承とオーバーライド [#d25956e4]
-Objective-Cと異なり、Swiftのサブクラスはスーパークラスの...
-Swiftの方法はサブクラスの複雑なinitializerが呼び出されず...
-もしスーパクラスと同じinitializerを定義したい場合、サブ...
-もしスーパークラスと全く同じdesignated initializerを定義...
-overrideモディファイアが存在すると、Swiftはスーパークラ...
-逆にサブクラスのinitializerがスーパークラスのconvenience...
-よって厳密にいえば、overrideはスーパークラスのconvenienc...
-以下の例を考える。
#pre{{
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
}}
-Vehicleクラスはデフォルト値を提供し、カスタムinitializer...
-デフォルトinitializerは自動的にdesignated initializerと...
#pre{{
class Bicycle: Vehicle {
override init() {
super.init()
numberOfWheels = 2
}
}
}}
-Bicycleはカスタムdesignated initializerを定義する。これ...
-init()はsuper.init()から始まる。これはnumberOfWheelsが初...
**自動initializer継承 [#sf0cd1a8]
-サブクラスは自動でinitializerを継承しない。しかし特定の...
-これによって多くの場合、サブクラスでoverrideする必要がな...
-サブクラスでデフォルト値を定義していたと想定すると、以下...
--Rule 1: サブクラスがdesignated initializerを定義してい...
--Rule 2: サブクラスがスーパークラスの全てのdesignated in...
**Designated and Convenience Initializerの動作 [#meb922e1]
-以下の例は、designated initializer、convenience initiali...
-Food、RecipeIngredient、ShoppingListItemがからむ。
#pre{{
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
}}
-Foodクラスはdesignated initializerとconvenience initiali...
-2番目のクラスはRecipeIngredientでFoodを継承する。
#pre{{
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)
}
}
}}
-RecipeIngredientは一つのdesignated initialzierと一つのco...
-convenience initializerはスーパークラスのinitializerと同...
-RecipeIngredientは全てのスーパークラスのdesignated initi...
-最後のクラスはRecipeIngredientのサブクラスであるShopping...
#pre{{
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}}
-プロパティにはデフォルト値が提供されていて独自のinitiali...
#pre{{
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)
}
}}
*Failable Initializers [#p97d2813]
-失敗する可能性のあるinitializerを定義できる。init?を使用...
-failable initializerはreturn nilによって失敗を表す。
#pre{{
let wholeNumber: Double = 12345.0
let pi = 3.14159
if let valueMaintained = Int(exactly: wholeNumber) {
print("\(wholeNumber) conversion to Int maintains val...
}
// Prints "12345.0 conversion to Int maintains value of 1...
let valueChanged = Int(exactly: pi)
// valueChanged is of type Int?, not Int
if valueChanged == nil {
print("\(pi) conversion to Int does not maintain valu...
}
// Prints "3.14159 conversion to Int does not maintain va...
}}
-例えば以下のように定義できる。
#pre{{
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 \(...
}
// Prints "An animal was initialized with a species of Gi...
}}
**Failabe Initializer for Enumerations [#y76c4b12]
-列挙型と組み合わせる。
#pre{{
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
}
}
}
}}
**Failable Initializer for Enumerations with Raw Values [...
-列挙型はrawValueを受け取るinitializerを自動で作成する。
#pre{{
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 initial...
}
// Prints "This is a defined temperature unit, so initial...
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so ini...
}
// Prints "This is not a defined temperature unit, so ini...
}}
**初期化失敗の伝達 [#obfa8713]
-初期化の失敗を伝達することを考える。
#pre{{
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)
}
}
}}
-スーパークラス、サブクラスどちらの条件が満たされなくても...
**Failable Initializerのオーバーライド [#iae0b14b]
-failable initializerはオーバーライドできる。またはスーパ...
#pre{{
class Document {
var name: String?
// this initializer creates a document with a nil nam...
init() {}
// this initializer creates a document with a nonempt...
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
}
}
}
}}
-AutomaticallyNamedDocumentはinit?をオーバーライドし、失...
-サブクラスでは強制アンラッピングをinitializerの中で呼び...
#pre{{
class UntitledDocument: Document {
override init() {
super.init(name: "[Untitled]")!
}
}
}}
**init! failable initializer [#t8a73101]
-失敗する可能性のあるinitializerとして普通はinit?を使うが...
*Required Initializers [#n90a3ab4]
-requiredモディファイアは、全てのサブクラスが実装しなけれ...
#pre{{
required init() {
// initializer implementation goes here
}
}
}}
-サブクラスでもrequiredをつけて実装する。
#pre{{
class SomeSubclass: SomeClass {
required init() {
// subclass implementation of the required initia...
}
}
}}
*Closure or Functionによるデフォルト値の設定 [#w12fc5cc]
-プロパティは以下のように実装できる。
#pre{{
class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside...
// someValue must be of the same type as SomeType
return someValue
}()
}
}}
-以下のような複雑な初期化も可能。
#pre{{
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]
}
}
}}
*落ち穂拾い [#zfbe932d]
**サブクラスからのsuper.init()の呼び出し [#qc71230b]
-[[【備忘録】initの動作検証 - Qiita:http://qiita.com/akik...
-サブクラスのイニシャライザからsuper.init()を呼び出せば、...
#pre{{
//super.init()の有無による実行順序の違い
class Parent {
let name = "Parent name"
init() {
print("\(name)")
}
}
class Child : Parent{
let childName = "Child name"
override init() {
// super.init()
print("\(childName)")
}
}
let child = Child()
//以下がprintされる。
//Parent name
//Child name
//
//super.init()をコメントアウトすると逆転する
//Child name
//Parent name
}}
**super.init()の自動呼び出し [#t84766db]
-[[[swift-users] super.init() called automatically?:https...
#pre{{
//super.init()の自動呼び出し。
//引数なしの一つのdesignated initializerが存在する場合、...
class Foo {
init() {
print("foo init")
}
}
class Bar: Foo {
init(x: Int) {
print("bar init")
}
}
let bar = Bar(x: 10)
//bar init
//foo init
}}
-対して以下の場合は自動で呼び出されない。
#pre{{
//super.init()が自動で呼び出されない場合。
class Parent2 {
let name: String
init(name: String) {
self.name = name
print("Parent2=\(name)")
}
init() {
self.name = "Unknown"
}
}
class Child2: Parent2 {
let childName: String
override init(name: String) {
self.childName = name
// super.init(name: name + "'s parent")
super.init()
}
}
let child2 = Child2(name: "abc")
}}
ページ名: