Swift/class
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
[[Swift]]
*Swift/クラス [#n73f083c]
**概要 [#deccc028]
クラスのインスタンスは参照型である。
すなわち、変数に代入したりメソッドの引数に渡す時に、コピ...
class 型名 [: スーパークラス] {
[変数/定数定義]
[イニシャライザ定義]
[メソッド定義]
[その他の定義]
}
クラスでは memberwise initializer は利用できない。
内部の変数の名前を指定して初期値を与えるのは、オブジェク...
(encapsulation) を台無しにしてしまうので。
クラス定義にイニシャライザがない場合、「クラス名()」とい...
でインスタンスを生成できるが、すべてのインスタンスプロパ...
class Time {
var hour = 0, min = 0
init(hour:Int, min:Int) {
self.hour = hour; self.min = min
}
func add(min:Int) {
let m = self.min + min
if m = 60 {
self.min = m % 60
let t = self.hour + m / 60
self.hour = t % 24
} else {
self.min = m
}
}
}
let t1 = Time(hour:13, min:20)
let t2 = t1
print(t1.toString()) // 13:20 と表示される
ti.inc()
print(t2.toString()) // 13:21 と表示される
構造体の定義ではメンバ変数の値を変更するメソッドには muta...
クラスの定義では必要ない。
クラスのインスタンスは、定数と変数のどちらに格納されてい...
LEFT:
||クラス|構造体|列挙型|
|参照型/値型|参照型|値型|値型|
|変更に関する制約|なし|(*1)|(*2)|
|インスタンスプロパティ|格納型/計算型|格納型/計算型|-/計...
|タイププロパティ|格納型/計算型|格納型/計算型|格納型/計算...
|継承|◯|-|-|
|プロトコル継承|◯|◯|◯|
|memberwise initializer|-|◯|-|
-(*1) --- インスタンスの格納型プロパティの値を変更するメ...
-(*2) selfの値を変更するメソッドにmutating指定が必要。
*** クラスの継承 [#zce9016e]
ルートクラスは NSObject。
継承において、スーパークラスのメソッドを上書き(override)...
メソッドの先頭部分に override という修飾語を記述する必要...
class クラス名 : スーパークラス名, プロトコル1, プロトコ...
class Time12 : Time, CustomStringConvertible {
var pm: Bool // 午後ならtrue
init(hour:Int, min:Int, pm:Bool) {
self.pm = pm
super.init(hour:hour, min:min)
}
override convenience init(hour:Int, min:Int) { // 24時制
let isPm = hour >= 12
self.init(hour: isPm ? hour - 12 : hour, min: min, p...
}
override func add(min:Int) {
super.add(min)
while hour >= 12 {
hour -= 12
pm = !pm
}
}
var description: String {
return toString() + " " + (pm ? "PM" : "AM")
}
}
クラスの継承を利用すると、スーパークラスに対して定義され...
実行時に動的に動作を決めることができる(dynamic binding)。
var array = [Time]() // Time型の配列
array.append(Time(hour:13, min:10))
array.append(Time12(hour:13, min:20))
array.append(Time12(hour:1, min:30, pm:true))
for t in array {
if t is Time12 { // is は動的にインスタンスの型を調...
print(t) // Time12型ならそのまま表示
} else {
print(">", t.toString()) // 先頭の">"の後に表示...
}
}
if let u = array[2] as? Time12 { // オプショナル束縛構文
print(u.pm ? "PM" : "AM")
}
インスタンスをキャスト(cast)する演算子として as, as?, as!...
クラスメソッドや、クラスプロパティでは class という修飾語...
タイプメソッドやタイププロパエィは上書きできないが、
クラスメソッドやクラスプロパティはサブクラスで定義を上書...
クラスプロパティは計算型プロパティに限定されている。
clas A : CustomStringConvertible {
static var className : String { return "A" } // 計...
static var total: Int = 0 // 格...
class var level: Int = { return 1 } // 計...
static func point() -> Int { return 1000 } // タ...
class func say() -> String { return "Ah." } // ク...
init() {) { ++A.total }
var description: String {
return "\(A.toal): \(A.clasName), Level=\(A.level), ...
}
}
class B : A {
override init() { super.ini(); ++B.total }
override var description : String {
return "\(B.toal): \(B.className), level=\(B.level),...
}
}
let a = A()
print(a) // "1: A, Level=1, 1000pt, ah."と表示される
let b = B()
print(b) // "3: A, Level=1, 1000pt, ah."と表示される
クラスBの中で、クラスAのタイププロパティやクラスプロパテ...
class B : A {
// override static var className: String { return "B" ...
// static var total:Int = 0 ...
override class var level : Int { return 2 }
// override static func point() -> Int { return 2000 }...
override class func day() -> String { return "Boo" }
override init() { super.ini(); ++B.total }
override var description : String {
return "\(B.toal): \(B.className), level=\(B.level),...
}
}
let a = A()
print(a) // "1: A, Level=1, 1000pt, ah."と表示される
let b = B()
print(b) // "3: A, Level=2, 1000pt, Boo"と表示される
***継承とメソッド呼び出し [#me0bbc73]
継承関係にあるクラスA, Bはそれぞれ show メソッドを持って...
class A {
func show() { print("A") }
func who() { show() }
}
class B: A {
override func show() { print("B") }
}
var a = A()
var b = B()
a.who() // Aと表示される
b.who() // Bと表示される
メソッドwhoにおけるshowの呼び出しは, self.show() と記述さ...
実際に実行されているインスタンスのメソッド定義が呼び出さ...
クラスメソッドについても同様である。
class A {
class func show() { print("A") }
class func who() { show() }
}
class B: A {
override class func show() { print("B") }
}
var a = A()
var b = B()
a.who() // Aと表示される
b.who() // Bと表示される
**イニシャライザ [#u2c116b3]
-designated initializer --- ベースクラスでは、そのイニシ...
-convenience initializer --- 他のイニシャライザを呼び出し...
スーパークラスのdesignated initializerと同じイニシャライ...
override というキーワードをつける必要がある。
designated initializer
init([仮引数: 型]... ) { 文 ... }
convenience initializer
convenience init([仮引数: 型] ...) { 文 ... }
初期化の手順と守るべきルール
+サブクラスのイニシャライザが呼び出される。もしconvenienc...
+そのサブクラスで追加された変数や定数の初期化を行う。初期...
+サブクラスからスーパークラスのイニシャライザを呼び出す。
+ベースクラスのイニシャライザが、ベースクラスの変数と定数...
+サブクラスのイニシャライザは、スーパークラスで初期化され...
次の制約に気をつけること。
-designated initializerは、スーパークラスに初期化を任せる...
変数と定数の初期化(値の代入、初期値の設定)を済ませている...
-サブクラスのイニシャライザは、スーパークラスのdesignated...
-convenience initializerは、同じクラスの他のイニシャライ...
-イニシャライザは、ベースクラスで変数と定数の初期化が終わ...
呼び出したり、インスタンス変数を読み出したり、selfを値と...
イニシャライザの中で何かの関数を使いたい場合は、グローバ...
実装するとよい。
クラス継承の例題
class DayOfMonth : CustomStringConvertible {
var month, day: Int
init(month:Int, day:INt) { // イニシャライザ
self.month = month; self.day = day
}
var description: String { // 計算型プロパティ
return DayOfMonth.twoDigits(month)+"/"+DayOfMonthTwo...
}
class func twoDigits(n:Int) -> String { // クラスメソ...
let i = n % 100
if (i < 10) { return "0\(i)" }
return "\(i)"
}
func dayOfWeek(var m:Int, let d:Int, var year y:Int) -> ...
if m < 3 { m += 12; --y }
let leap = y + y / 4 - y / 100 + y / 400
return (leap + (13 * m + 8)/5 + d) % 7
}
class Date : DayOfMonth {
var year: Int
var dow: Int
init(_ y:Int, _ m:Int, _ d:Int) {
year = y; // 新しいインスタンス変...
dow = dayOfWeek(m,d,year:y) // 初期化してから
super.init(month:m, day:d) // スーパークラスを初期...
}
}
class DateW : Date {
static let nameOfDay = { "Sun","Mon","Tue","Wed","Thu"...
var dweek = String() // 注意!!
override init(_ y:Int, _ m:Int, _ d:Int) { // overrid...
super.init(y,m,d)
dweek = DateW.namesOfDay[dow] // 注意!!
}
convenience init(_ m:Int, _ d:Int, year:Int = 2016) {
self.init(year,m, d)
}
override var day:Int { // プロパティの上書きなのでove...
didSet {
dow = dayOfWeek(month,day,year:year)
dweek = DateW.nameOfDay[dow]
}
}
override var description: String { // 計算型プロパテ...
return "\(year)/" + super.description + "(\(dweek))"
}
}
designated initializerはスーパークラスに初期化を任せる前...
追加された変数や定数の初期化を済ませていなくてはいけない。
そのため、一旦dweekにString()を入れておいて、スーパークラ...
終了した段階で、本来の値を代入している。
***イニシャライザの継承 [#z021ecb5]
Swiftでは、スーパークラスのイニシャライザを、サブクラスで...
しかし、次の2つの条件のどちらかに当てはまる場合は、継承で...
-サブクラスでdesignated initializerをひとつも定義していな...
-サブクラスがスーパクラスのdesignated initializerを全て持...
すべてを定義して実装している場合と、ひとつも定義せずにス...
スーパークラスのconvenience initializerをすべて継承できる。
***必須イニシャライザ [#xf2dae44]
イニシャライザの定義で init の前に required という修飾語...
「必須イニシャライザ (required initializer)」となり、
そのクラスを継承したサブクラスはすべてそのイニシャライザ...
(スーパークラスからイニシャライザを継承した場合は書かなく...
class ICCard {
static let Deposit = 500 // 定数 (タイププロパティ)
var money = 0
required init(charge:Int) { // 必須イニシャライザ
money = charge - ICCard.Deposit // 保証金を差し引く
}
}
class Icocai : ICCard {
static var serial = 0 // 通し番号 (タイププロ...
let idnumber: Int // 初期値は指定せず
init(id:Int, money:Int) { // 別のdesignated initia...
idnumber = id;
super.init(charge:money)
}
required init(charge:Int) { // 必須イニシャライザを...
idnumber = ++Icocai.serial
super.init(charge:money)
}
}
class Suiica: ICCard { // イニシャライザは継承さ...
var name = String()
}
必須イニシャライザは、サブクラスでconvenience initializer...
required convenience init(charge:Int) {
self.init(id:++icocai.Serial, money:charge)
}
***失敗のあるイニシャライザと継承 [#tb57acb5]
クラス定義でも失敗のあるイニシャライザ (failable initiali...
ただし、イニシャライザの途中で return nil する場合に次の...
-designated initializerの場合~
すべてのプロパティに値が設定されるまで return nil しては...
サブクラスのイニシャライザの場合は、スーパークラスのイニ...
-convenience initializerの場合~
return nilをする場所の制約はない。
サブクラスのイニシャライザがスーパークラスの失敗のあるイ...
サブクラスのイニシャライザも失敗のあるイニシャライザとな...
スーパークラスのイニシャライザが return nil した場合は、...
class NamePlate {
let name, title: String
init() { name ="inviter"; title = "" }
init?(name:String,title:String) { // 失敗のあるイニシ...
// if name == "" { return il} // ここでreturn nil...
self.name = name
self.title = title
if name == "" { return nil} // 全てのプロパティ...
}
}
class SpeakerNamePlate : NamePlate {
override init?(name:String,title:String) {
// if title == "" { return nil } // ここで return ...
super.init(name:name, title:title)
if title == "" { return nil } // スーパークラス...
}
}
***失敗のあるイニシャライザを失敗しないようにする。 [#o4d...
let plate = NamePlate(name:"Taro", title:"Main")! // un...
super.init(name:yourName,title:what)! // unwrapする。
イニシャライザが同一かどうかは、キーワードと引数の型で判...
同じキーワードと引数の型を持つイニシャライザは、失敗する...
同じイニシャライザと見なされる。
class GuestNamePlate : NamePlate {
override init(name:String, title:String) { // 失敗の...
if (name == "") {
super.init() // 失敗のない定義を呼ぶ
} else {
super.init(name:name,title:title)! //失敗のない...
}
}
}
**継承とサブクラス [#a0b6d0a3]
スーパークラスのプロパティを継承できる。
スーパークラスでread only であったプロパティを read and w...
継承では、サブクラスがスーパークラスの機能を包含している...
class Prop {
var attr = 0
}
class PropA : Prop { // 0か1を返す(奇数で...
override var attr : Int {
get { return super.attr & 1 }
set { super.attr = newValue } // 省略できない
}
}
class PropB : Prop { // 1の位を切り捨てて...
override var attr : Int {
get { return super.attr } // 省略できない
set { super.attr = newValue / 10 * 10 }
}
}
添字付けの継承
class Recipe {
let amount = [ 6.6, 8.9, 7.5, 9.1 ]
subscript(idx: Int) -> Double { // read only
return idx < 4 ? amount[idx] : 0.0
}
}
class Arrange : Recipe {
var custom: [Double] = []
override init() {
super.init()
custom = amount
}
override subscript(idx:Int) -> Double { // read and wr...
get { return idx < 4 ? custom[idx] : 0.0 }
set { if idx < 4 { custom[idx] = newValue } }
}
func recall(idx: Int) { // 指定した添字について元の値...
self[idx] = super[idx] // idxが範囲外でも問題ない
}
}
***継承とプロパティオブザーバ [#o92aebbd]
プロパティオブザーバは、サブクラスでoverrideされても順番...
つまり、動作がメソッドやプロパティとは異る。
class PropA {
var attr = 0
}
class PropB : PropA {
override var attr : Int {
willSet { print("B: will set") }
didSet { print("B: did set") }
}
}
class PropC : PropB {
override var attr : Int {
willSet { print("C: will set") }
didSet { print("C: did set") }
}
}
var x = propC()
x.attr = 1
次のように表示される。
C: will set
B: will set
B: did set
C: did set
***継承させない指定 [#pbfaed10]
finalという修飾語をつかって、継承させない指定を行う。
***キャスト演算子とパターンマッチ [#ef8c7497]
let s = [ "John", "Smith" ] as Set<String>
// s = Set<String>([ "John", "Smith" ]) // と同じ
// s:Set<String> = [ "John", "Smith" ] // と同じ
let c = "字" as Character
// s = Character("字") // と同じ
case let 定数名 as 型
switch t { // tはTime型またはTime12型(サブクラス)...
case let u as Time12:
print("Time12:", u)
default:
print("TIme:", t.toStirng())
}
次の例では条件が成立した場合定数vはTime12型として処理の中...
if let v = obj as? Time12 { ... }
if case let v as Time12 = obj { ... }
***継承と型推論 [#j38d764f]
クラスTime12がクラスTimeを継承しているものとする。
これらのインスタンスを同時に含む配列を作ると、共通のスー...
var array = [ Time12(hour:13, min:20), Time(hour:18, min...
継承関係がないインスタンスの場合は AnyObject 型となる。
var all:[AnyObject] = [ Time12(hour:0, min:15), SOS() ]
print( all[0] as! Time12 ) // 0:15 AM と表示される
AnyObjectはクラスのインスタンスだけを扱う。全ての型をまと...
var every: [Any] = [ Time12(hour:16, min:30), "駅前", 5 ]
print( all[0] as! Time12 ) // 4:30 PM と表示される
***クラスのメタタイプ [#r0332965]
インスタンスに dynamicType という問い合せを行うと、実際に...
クラスAのクラスオブジェクトの型は A.Type と記述し、これを...
クラスAのクラスオブジェクトの値は A.self と記述する。
クラスオブジェクトに対して、クラスメソッドを呼び出したり...
class Avatar {
class func say() { print("Avatar") } // class...
required init() { }
}
class Player : Avatar {
override class func say() { print("Player") } // clas...
let name : String
init(name: String) { self.name = name; super.init() }
required convenience init() { self.init(name: "none") }
}
var meta: Avatar.Type = Player.self // メタタイプの変...
meta.say() // Player と表示...
let p:Avatar = meta.init() // インスタンスを...
if p.dynamicType === Player.self { // === 演算子で比...
print( (p as! Player).name) // none と表示さ...
}
let q = Avatar()
meta = q.dynamicType // インスタンスか...
meta.say() // Avatar と表示...
**開放時処理 [#y8129ef8]
***デイニシャライザ [#s1970af6]
クラスのインスタンスは参照型であり、インスタンスはリファ...
デイニシャライザはクラスのインスタンスが開放される直前に...
デイニシャライザが実行される時、そのインスタンスのプロパ...
deinit {
文 ...
}
クラスに継承関係がある場合は、サブクラスのデイニシャライ...
スーパークラスのデイニシャライザが実行される。
開放されるクラスにデイニシャライザが存在しなくても、スー...
必ず実行される。
class ReadWord {
var fp: UnsafeMutablePointer<FILE> = nil
init?(open:String) { // 失敗のあるイニシャライザ
fp = fopen(open,"r") // C言語のFILE*型
if fp == nil { return nil }
}
dinit {
pirnt("deinit"); self.close()
}
func close() {
if fp != nil {
fclose(fp); fp = nil
}
}
func nextWord() -> String? { // オプショナル型を返す
var ch:Int
repeat {
ch = Int( fgetc(fp) ) // 1byte読み込んで
if ch < 0 { return nil } // EOFならばnilを返す
} while ch <= 0x20 // 空白や改行を読み飛ばす
var s = String(UnicodeScalar(ch)) // 1文字だけの文...
while true { // 非空白文字の列を作る
ch = Int( fgetc( fp ) ) // 1byte読み込んで
if ch <= 0x20 { break } // 空白や改行ならば中断
s.append(UnicodeScalar(ch))
}
return s
}
}
func readIt() {
if let reader = ReadWord(open:"text.txt") { // オープ...
while let w = reader.nextWord() { // オプシ...
if w == "Q!" { return } // 処理を中断
print(w,terminator:" ")
}
print("EOF")
reader.close()
}
}
**遅延格納型プロパティ [#bca6ee69]
**遅延格納型プロパティ [#k409aaaa]
「初期化のときには値を決めず、必要になったときに初めて値...
これを遅延格納型プロパティ (lazy stored property) と呼び...
定数ではなく、変数として宣言する。
// ファイルの属性を遅延で取得する例
import Foundation
class FileAttr {
let filename: String
lazy var size: Int = self.getFileSize() // 遅延評価...
init(file:String) {
filename = file
}
func getFileSize() -> Int {
var buffer = stat() // 構造体の初期化
stat(filename,&buffer) // statを呼び出す
print("getFileSize") // 動作確認のための表示
return Int(buffer.st_size) // 得られた値をInt型に...
}
}
または
import Foundation
class FileAttr {
let filename: String
lazy var size: Int = { // クロージャの記述開始
var buffer = stat() // 構造体の初期化
stat(filename,&buffer) // statを呼び出す
print("getFileSize") // 動作確認のための表示
return Int(buffer.st_size) // 得られた値をInt型に...
}() // クロージャの呼び出...
self.getFileSize() // 遅延評価で値を決定する
init(file:String) {
filename = file
}
}
実行
let d = FileAttr(file: "text.txt")
print(d.filename)
print(d.size)
print(d.size)
表示
text.txt
getFileSize // ここで遅延評価が実行されている
332
332 // 一旦値が決まったら、次からは呼び出さ...
終了行:
[[Swift]]
*Swift/クラス [#n73f083c]
**概要 [#deccc028]
クラスのインスタンスは参照型である。
すなわち、変数に代入したりメソッドの引数に渡す時に、コピ...
class 型名 [: スーパークラス] {
[変数/定数定義]
[イニシャライザ定義]
[メソッド定義]
[その他の定義]
}
クラスでは memberwise initializer は利用できない。
内部の変数の名前を指定して初期値を与えるのは、オブジェク...
(encapsulation) を台無しにしてしまうので。
クラス定義にイニシャライザがない場合、「クラス名()」とい...
でインスタンスを生成できるが、すべてのインスタンスプロパ...
class Time {
var hour = 0, min = 0
init(hour:Int, min:Int) {
self.hour = hour; self.min = min
}
func add(min:Int) {
let m = self.min + min
if m = 60 {
self.min = m % 60
let t = self.hour + m / 60
self.hour = t % 24
} else {
self.min = m
}
}
}
let t1 = Time(hour:13, min:20)
let t2 = t1
print(t1.toString()) // 13:20 と表示される
ti.inc()
print(t2.toString()) // 13:21 と表示される
構造体の定義ではメンバ変数の値を変更するメソッドには muta...
クラスの定義では必要ない。
クラスのインスタンスは、定数と変数のどちらに格納されてい...
LEFT:
||クラス|構造体|列挙型|
|参照型/値型|参照型|値型|値型|
|変更に関する制約|なし|(*1)|(*2)|
|インスタンスプロパティ|格納型/計算型|格納型/計算型|-/計...
|タイププロパティ|格納型/計算型|格納型/計算型|格納型/計算...
|継承|◯|-|-|
|プロトコル継承|◯|◯|◯|
|memberwise initializer|-|◯|-|
-(*1) --- インスタンスの格納型プロパティの値を変更するメ...
-(*2) selfの値を変更するメソッドにmutating指定が必要。
*** クラスの継承 [#zce9016e]
ルートクラスは NSObject。
継承において、スーパークラスのメソッドを上書き(override)...
メソッドの先頭部分に override という修飾語を記述する必要...
class クラス名 : スーパークラス名, プロトコル1, プロトコ...
class Time12 : Time, CustomStringConvertible {
var pm: Bool // 午後ならtrue
init(hour:Int, min:Int, pm:Bool) {
self.pm = pm
super.init(hour:hour, min:min)
}
override convenience init(hour:Int, min:Int) { // 24時制
let isPm = hour >= 12
self.init(hour: isPm ? hour - 12 : hour, min: min, p...
}
override func add(min:Int) {
super.add(min)
while hour >= 12 {
hour -= 12
pm = !pm
}
}
var description: String {
return toString() + " " + (pm ? "PM" : "AM")
}
}
クラスの継承を利用すると、スーパークラスに対して定義され...
実行時に動的に動作を決めることができる(dynamic binding)。
var array = [Time]() // Time型の配列
array.append(Time(hour:13, min:10))
array.append(Time12(hour:13, min:20))
array.append(Time12(hour:1, min:30, pm:true))
for t in array {
if t is Time12 { // is は動的にインスタンスの型を調...
print(t) // Time12型ならそのまま表示
} else {
print(">", t.toString()) // 先頭の">"の後に表示...
}
}
if let u = array[2] as? Time12 { // オプショナル束縛構文
print(u.pm ? "PM" : "AM")
}
インスタンスをキャスト(cast)する演算子として as, as?, as!...
クラスメソッドや、クラスプロパティでは class という修飾語...
タイプメソッドやタイププロパエィは上書きできないが、
クラスメソッドやクラスプロパティはサブクラスで定義を上書...
クラスプロパティは計算型プロパティに限定されている。
clas A : CustomStringConvertible {
static var className : String { return "A" } // 計...
static var total: Int = 0 // 格...
class var level: Int = { return 1 } // 計...
static func point() -> Int { return 1000 } // タ...
class func say() -> String { return "Ah." } // ク...
init() {) { ++A.total }
var description: String {
return "\(A.toal): \(A.clasName), Level=\(A.level), ...
}
}
class B : A {
override init() { super.ini(); ++B.total }
override var description : String {
return "\(B.toal): \(B.className), level=\(B.level),...
}
}
let a = A()
print(a) // "1: A, Level=1, 1000pt, ah."と表示される
let b = B()
print(b) // "3: A, Level=1, 1000pt, ah."と表示される
クラスBの中で、クラスAのタイププロパティやクラスプロパテ...
class B : A {
// override static var className: String { return "B" ...
// static var total:Int = 0 ...
override class var level : Int { return 2 }
// override static func point() -> Int { return 2000 }...
override class func day() -> String { return "Boo" }
override init() { super.ini(); ++B.total }
override var description : String {
return "\(B.toal): \(B.className), level=\(B.level),...
}
}
let a = A()
print(a) // "1: A, Level=1, 1000pt, ah."と表示される
let b = B()
print(b) // "3: A, Level=2, 1000pt, Boo"と表示される
***継承とメソッド呼び出し [#me0bbc73]
継承関係にあるクラスA, Bはそれぞれ show メソッドを持って...
class A {
func show() { print("A") }
func who() { show() }
}
class B: A {
override func show() { print("B") }
}
var a = A()
var b = B()
a.who() // Aと表示される
b.who() // Bと表示される
メソッドwhoにおけるshowの呼び出しは, self.show() と記述さ...
実際に実行されているインスタンスのメソッド定義が呼び出さ...
クラスメソッドについても同様である。
class A {
class func show() { print("A") }
class func who() { show() }
}
class B: A {
override class func show() { print("B") }
}
var a = A()
var b = B()
a.who() // Aと表示される
b.who() // Bと表示される
**イニシャライザ [#u2c116b3]
-designated initializer --- ベースクラスでは、そのイニシ...
-convenience initializer --- 他のイニシャライザを呼び出し...
スーパークラスのdesignated initializerと同じイニシャライ...
override というキーワードをつける必要がある。
designated initializer
init([仮引数: 型]... ) { 文 ... }
convenience initializer
convenience init([仮引数: 型] ...) { 文 ... }
初期化の手順と守るべきルール
+サブクラスのイニシャライザが呼び出される。もしconvenienc...
+そのサブクラスで追加された変数や定数の初期化を行う。初期...
+サブクラスからスーパークラスのイニシャライザを呼び出す。
+ベースクラスのイニシャライザが、ベースクラスの変数と定数...
+サブクラスのイニシャライザは、スーパークラスで初期化され...
次の制約に気をつけること。
-designated initializerは、スーパークラスに初期化を任せる...
変数と定数の初期化(値の代入、初期値の設定)を済ませている...
-サブクラスのイニシャライザは、スーパークラスのdesignated...
-convenience initializerは、同じクラスの他のイニシャライ...
-イニシャライザは、ベースクラスで変数と定数の初期化が終わ...
呼び出したり、インスタンス変数を読み出したり、selfを値と...
イニシャライザの中で何かの関数を使いたい場合は、グローバ...
実装するとよい。
クラス継承の例題
class DayOfMonth : CustomStringConvertible {
var month, day: Int
init(month:Int, day:INt) { // イニシャライザ
self.month = month; self.day = day
}
var description: String { // 計算型プロパティ
return DayOfMonth.twoDigits(month)+"/"+DayOfMonthTwo...
}
class func twoDigits(n:Int) -> String { // クラスメソ...
let i = n % 100
if (i < 10) { return "0\(i)" }
return "\(i)"
}
func dayOfWeek(var m:Int, let d:Int, var year y:Int) -> ...
if m < 3 { m += 12; --y }
let leap = y + y / 4 - y / 100 + y / 400
return (leap + (13 * m + 8)/5 + d) % 7
}
class Date : DayOfMonth {
var year: Int
var dow: Int
init(_ y:Int, _ m:Int, _ d:Int) {
year = y; // 新しいインスタンス変...
dow = dayOfWeek(m,d,year:y) // 初期化してから
super.init(month:m, day:d) // スーパークラスを初期...
}
}
class DateW : Date {
static let nameOfDay = { "Sun","Mon","Tue","Wed","Thu"...
var dweek = String() // 注意!!
override init(_ y:Int, _ m:Int, _ d:Int) { // overrid...
super.init(y,m,d)
dweek = DateW.namesOfDay[dow] // 注意!!
}
convenience init(_ m:Int, _ d:Int, year:Int = 2016) {
self.init(year,m, d)
}
override var day:Int { // プロパティの上書きなのでove...
didSet {
dow = dayOfWeek(month,day,year:year)
dweek = DateW.nameOfDay[dow]
}
}
override var description: String { // 計算型プロパテ...
return "\(year)/" + super.description + "(\(dweek))"
}
}
designated initializerはスーパークラスに初期化を任せる前...
追加された変数や定数の初期化を済ませていなくてはいけない。
そのため、一旦dweekにString()を入れておいて、スーパークラ...
終了した段階で、本来の値を代入している。
***イニシャライザの継承 [#z021ecb5]
Swiftでは、スーパークラスのイニシャライザを、サブクラスで...
しかし、次の2つの条件のどちらかに当てはまる場合は、継承で...
-サブクラスでdesignated initializerをひとつも定義していな...
-サブクラスがスーパクラスのdesignated initializerを全て持...
すべてを定義して実装している場合と、ひとつも定義せずにス...
スーパークラスのconvenience initializerをすべて継承できる。
***必須イニシャライザ [#xf2dae44]
イニシャライザの定義で init の前に required という修飾語...
「必須イニシャライザ (required initializer)」となり、
そのクラスを継承したサブクラスはすべてそのイニシャライザ...
(スーパークラスからイニシャライザを継承した場合は書かなく...
class ICCard {
static let Deposit = 500 // 定数 (タイププロパティ)
var money = 0
required init(charge:Int) { // 必須イニシャライザ
money = charge - ICCard.Deposit // 保証金を差し引く
}
}
class Icocai : ICCard {
static var serial = 0 // 通し番号 (タイププロ...
let idnumber: Int // 初期値は指定せず
init(id:Int, money:Int) { // 別のdesignated initia...
idnumber = id;
super.init(charge:money)
}
required init(charge:Int) { // 必須イニシャライザを...
idnumber = ++Icocai.serial
super.init(charge:money)
}
}
class Suiica: ICCard { // イニシャライザは継承さ...
var name = String()
}
必須イニシャライザは、サブクラスでconvenience initializer...
required convenience init(charge:Int) {
self.init(id:++icocai.Serial, money:charge)
}
***失敗のあるイニシャライザと継承 [#tb57acb5]
クラス定義でも失敗のあるイニシャライザ (failable initiali...
ただし、イニシャライザの途中で return nil する場合に次の...
-designated initializerの場合~
すべてのプロパティに値が設定されるまで return nil しては...
サブクラスのイニシャライザの場合は、スーパークラスのイニ...
-convenience initializerの場合~
return nilをする場所の制約はない。
サブクラスのイニシャライザがスーパークラスの失敗のあるイ...
サブクラスのイニシャライザも失敗のあるイニシャライザとな...
スーパークラスのイニシャライザが return nil した場合は、...
class NamePlate {
let name, title: String
init() { name ="inviter"; title = "" }
init?(name:String,title:String) { // 失敗のあるイニシ...
// if name == "" { return il} // ここでreturn nil...
self.name = name
self.title = title
if name == "" { return nil} // 全てのプロパティ...
}
}
class SpeakerNamePlate : NamePlate {
override init?(name:String,title:String) {
// if title == "" { return nil } // ここで return ...
super.init(name:name, title:title)
if title == "" { return nil } // スーパークラス...
}
}
***失敗のあるイニシャライザを失敗しないようにする。 [#o4d...
let plate = NamePlate(name:"Taro", title:"Main")! // un...
super.init(name:yourName,title:what)! // unwrapする。
イニシャライザが同一かどうかは、キーワードと引数の型で判...
同じキーワードと引数の型を持つイニシャライザは、失敗する...
同じイニシャライザと見なされる。
class GuestNamePlate : NamePlate {
override init(name:String, title:String) { // 失敗の...
if (name == "") {
super.init() // 失敗のない定義を呼ぶ
} else {
super.init(name:name,title:title)! //失敗のない...
}
}
}
**継承とサブクラス [#a0b6d0a3]
スーパークラスのプロパティを継承できる。
スーパークラスでread only であったプロパティを read and w...
継承では、サブクラスがスーパークラスの機能を包含している...
class Prop {
var attr = 0
}
class PropA : Prop { // 0か1を返す(奇数で...
override var attr : Int {
get { return super.attr & 1 }
set { super.attr = newValue } // 省略できない
}
}
class PropB : Prop { // 1の位を切り捨てて...
override var attr : Int {
get { return super.attr } // 省略できない
set { super.attr = newValue / 10 * 10 }
}
}
添字付けの継承
class Recipe {
let amount = [ 6.6, 8.9, 7.5, 9.1 ]
subscript(idx: Int) -> Double { // read only
return idx < 4 ? amount[idx] : 0.0
}
}
class Arrange : Recipe {
var custom: [Double] = []
override init() {
super.init()
custom = amount
}
override subscript(idx:Int) -> Double { // read and wr...
get { return idx < 4 ? custom[idx] : 0.0 }
set { if idx < 4 { custom[idx] = newValue } }
}
func recall(idx: Int) { // 指定した添字について元の値...
self[idx] = super[idx] // idxが範囲外でも問題ない
}
}
***継承とプロパティオブザーバ [#o92aebbd]
プロパティオブザーバは、サブクラスでoverrideされても順番...
つまり、動作がメソッドやプロパティとは異る。
class PropA {
var attr = 0
}
class PropB : PropA {
override var attr : Int {
willSet { print("B: will set") }
didSet { print("B: did set") }
}
}
class PropC : PropB {
override var attr : Int {
willSet { print("C: will set") }
didSet { print("C: did set") }
}
}
var x = propC()
x.attr = 1
次のように表示される。
C: will set
B: will set
B: did set
C: did set
***継承させない指定 [#pbfaed10]
finalという修飾語をつかって、継承させない指定を行う。
***キャスト演算子とパターンマッチ [#ef8c7497]
let s = [ "John", "Smith" ] as Set<String>
// s = Set<String>([ "John", "Smith" ]) // と同じ
// s:Set<String> = [ "John", "Smith" ] // と同じ
let c = "字" as Character
// s = Character("字") // と同じ
case let 定数名 as 型
switch t { // tはTime型またはTime12型(サブクラス)...
case let u as Time12:
print("Time12:", u)
default:
print("TIme:", t.toStirng())
}
次の例では条件が成立した場合定数vはTime12型として処理の中...
if let v = obj as? Time12 { ... }
if case let v as Time12 = obj { ... }
***継承と型推論 [#j38d764f]
クラスTime12がクラスTimeを継承しているものとする。
これらのインスタンスを同時に含む配列を作ると、共通のスー...
var array = [ Time12(hour:13, min:20), Time(hour:18, min...
継承関係がないインスタンスの場合は AnyObject 型となる。
var all:[AnyObject] = [ Time12(hour:0, min:15), SOS() ]
print( all[0] as! Time12 ) // 0:15 AM と表示される
AnyObjectはクラスのインスタンスだけを扱う。全ての型をまと...
var every: [Any] = [ Time12(hour:16, min:30), "駅前", 5 ]
print( all[0] as! Time12 ) // 4:30 PM と表示される
***クラスのメタタイプ [#r0332965]
インスタンスに dynamicType という問い合せを行うと、実際に...
クラスAのクラスオブジェクトの型は A.Type と記述し、これを...
クラスAのクラスオブジェクトの値は A.self と記述する。
クラスオブジェクトに対して、クラスメソッドを呼び出したり...
class Avatar {
class func say() { print("Avatar") } // class...
required init() { }
}
class Player : Avatar {
override class func say() { print("Player") } // clas...
let name : String
init(name: String) { self.name = name; super.init() }
required convenience init() { self.init(name: "none") }
}
var meta: Avatar.Type = Player.self // メタタイプの変...
meta.say() // Player と表示...
let p:Avatar = meta.init() // インスタンスを...
if p.dynamicType === Player.self { // === 演算子で比...
print( (p as! Player).name) // none と表示さ...
}
let q = Avatar()
meta = q.dynamicType // インスタンスか...
meta.say() // Avatar と表示...
**開放時処理 [#y8129ef8]
***デイニシャライザ [#s1970af6]
クラスのインスタンスは参照型であり、インスタンスはリファ...
デイニシャライザはクラスのインスタンスが開放される直前に...
デイニシャライザが実行される時、そのインスタンスのプロパ...
deinit {
文 ...
}
クラスに継承関係がある場合は、サブクラスのデイニシャライ...
スーパークラスのデイニシャライザが実行される。
開放されるクラスにデイニシャライザが存在しなくても、スー...
必ず実行される。
class ReadWord {
var fp: UnsafeMutablePointer<FILE> = nil
init?(open:String) { // 失敗のあるイニシャライザ
fp = fopen(open,"r") // C言語のFILE*型
if fp == nil { return nil }
}
dinit {
pirnt("deinit"); self.close()
}
func close() {
if fp != nil {
fclose(fp); fp = nil
}
}
func nextWord() -> String? { // オプショナル型を返す
var ch:Int
repeat {
ch = Int( fgetc(fp) ) // 1byte読み込んで
if ch < 0 { return nil } // EOFならばnilを返す
} while ch <= 0x20 // 空白や改行を読み飛ばす
var s = String(UnicodeScalar(ch)) // 1文字だけの文...
while true { // 非空白文字の列を作る
ch = Int( fgetc( fp ) ) // 1byte読み込んで
if ch <= 0x20 { break } // 空白や改行ならば中断
s.append(UnicodeScalar(ch))
}
return s
}
}
func readIt() {
if let reader = ReadWord(open:"text.txt") { // オープ...
while let w = reader.nextWord() { // オプシ...
if w == "Q!" { return } // 処理を中断
print(w,terminator:" ")
}
print("EOF")
reader.close()
}
}
**遅延格納型プロパティ [#bca6ee69]
**遅延格納型プロパティ [#k409aaaa]
「初期化のときには値を決めず、必要になったときに初めて値...
これを遅延格納型プロパティ (lazy stored property) と呼び...
定数ではなく、変数として宣言する。
// ファイルの属性を遅延で取得する例
import Foundation
class FileAttr {
let filename: String
lazy var size: Int = self.getFileSize() // 遅延評価...
init(file:String) {
filename = file
}
func getFileSize() -> Int {
var buffer = stat() // 構造体の初期化
stat(filename,&buffer) // statを呼び出す
print("getFileSize") // 動作確認のための表示
return Int(buffer.st_size) // 得られた値をInt型に...
}
}
または
import Foundation
class FileAttr {
let filename: String
lazy var size: Int = { // クロージャの記述開始
var buffer = stat() // 構造体の初期化
stat(filename,&buffer) // statを呼び出す
print("getFileSize") // 動作確認のための表示
return Int(buffer.st_size) // 得られた値をInt型に...
}() // クロージャの呼び出...
self.getFileSize() // 遅延評価で値を決定する
init(file:String) {
filename = file
}
}
実行
let d = FileAttr(file: "text.txt")
print(d.filename)
print(d.size)
print(d.size)
表示
text.txt
getFileSize // ここで遅延評価が実行されている
332
332 // 一旦値が決まったら、次からは呼び出さ...
ページ名: