関数と変数をまとめる[クラス]
クラスの定義
- クラス定義
class Counter { var count = 0 func increment() -> Int { ret } }
対象 | 表記 |
---|---|
クラス | アッパーキャメル |
プロパティ | ロウワーキャメル |
メソッド | ロウワーキャメル |
スネークケース「_」は非推奨
インスタンスの作成
- クラスインスタンス
var cnt1 = Counter() var cnt2 = Counter()
インスタンスを定数に代入した場合、以降のインスタンスの代入は不可
ただし、インスタンスのプロパティは変更可
プロパティ
- プロパティへのアクセス
var c = Count() c.count // 0 c.increment() c.count // 1
ストアドプロパティ
クラスの持つ値を格納するプロパティのこと
letキーワード付きは変更不可
レイジーストアドプロパティ
「lazy」キーワードがついたプロパティ
クラスに必要な情報が不確定の際に利用し、実際の使用まで初期化させない
コンピューテッドプロパティ
- コンピューテッドプロパティの定義
var プロパティ名 : 型 { // 必須 get { ゲッター処理 } // 必須ではない set(セットする値){ セッター処理 } }
計算によって値を返すプロパティ
ゲッター関数で値を返す
- コンピューテッドプロパティの例
class Rectangle { // ストアドプロパティ var origin = (x: 0, y: 0) var size = (width: 0, height: 0) // コンピューテッドプロパティ var center : (x: Int, y: Int) { // ゲッタ get { let centerX = origin.x + (size.width / 2) let centerY = origin.y + (size.height / 2) return (x: centerX, y: centerY) } // セッタ set(newCenter) { origin.x = newCenter.x - (size.width / 2) origin.y = newCenter.y - (size.height / 2) } } } var rect = Rectangle() rect.origin = (x: 100, y: 100) rect.size = (width: 50, height: 50) rect.center // (.0 125, .1 125) rect.center = (x: 200, y: 200) rect.center // (.0 200, .1 200)
- セッタのパラメタの省略
set { origin.x = newCenter.x - (size.width / 2) origin.y = newCenter.y - (size.height / 2) }
- 読み取り専用コンピューテッドプロパティ
class Rectangle { // ストアドプロパティ var origin = (x: 0, y: 0) var size = (width: 0, height: 0) // コンピューテッドプロパティ var center : (x: Int, y: Int) { let centerX = origin.x + (size.width / 2) let centerY = origin.y + (size.height / 2) return (x: centerX, y: centerY) } }
- タイププロパティ(static)
class Foo { class var bar: Int { return 100 } } Foo.bar // 100
インスタンスには関連付いていない
構造体や列挙型を総称して「 タイプ 」
コンピューテッドプロパティとしてしか使用できない
classキーワードとvarキーワードで表記
- 特殊なプロパティ / すべてのインスタンスは「 self 」という特別なプロパティを持つ
class Rectangle { var x = 0, y = 0 var width = 0, height = 0 // クラスプロパティと同一名の引数 func center(x: Int, y: Int) -> (x: Int, y: Int) { // selfキーワードを使用して自クラスのプロパティとして宣言 let centerX = self.x + (width / 2) let centerY = self.y + (height / 2) return (x: centerX, y: centerY) } }
- プロパティオブザーバ / プロパティが設定されるたびに呼び出される関数
class Wallet { var money: Int = 0 { // 設定する前に呼び出される willSet { println("財布の中身が\(newValue)円になりました") } // 設定した後に呼び出される didSet { if oldValue < money { println("\(meney - oldValue)円増えました") } else { println("\(oldValue - meney)円減りました") } } } } var w = Wallet() w.meney = 100 // 財布の中身が100円になりました // 100円増えました w.meney = 150 // 財布の中身が150円になりました // 50円増えました
「willSet」「didSet」は片方のみ定義可。最初の初期化では呼び出されない
「newValue」「oldValue」という名前でそれぞれの定数にアクセス可
- 通常の変数への適用 / コンピューテッドプロパティ・プロパティオブサーバは一般変数にも適用可
var absolute = Int = 0 { didSet { if absolute < 0 { absolute *= -1 } } } absolute = -10 absolute // 10
class Counter { var count = 0 func increment() -> Int { return ++ count } func incrementBy(amount: Int) -> Int { count += amount return count } func incrementBy(amount: Int, times: Int) -> Int { count += amount * times return count } } var c = Counter() c.count // 0 c.increment() c.increment() c.count // 2 c.incrementBy(3) c.count // 5
var c = Counter() c.count // 0 // 外部名が指定されていなくても内部名を外部名として指定可 c.incrementBy(5, times: 3) c.count // 15
メソッド名の最後には、最初の引数を説明する単語を置くという命名ルール
- パラメタを指定しない形の新スタンスメソッド
class Counter { var count = 0 func incrementBy(amount: Int, _ times: Int) -> Int { count += amount * times return count } } var c = Counter() c.count // 0 c.incrementBy(5, 3) c.count // 15
- タイプメソッド(classキーワード)
class Foo { class func bar() { // タイプメソッド処理 } }
クラスの継承
- クラスの継承の宣言
class クラス名 : スーパークラス名 { クラス定義 }
- ベースクラスの定義と継承の例
class Instrument { var rangeOfOctaves = 1 var description: String { return "\(rangeOfOctaves)オクターブの音がでます" } func play(){ } } class Guitar: Instrument { var numberOfString = 6 } var g = Guitar() g.rangeOfOctaves = 4 g.numberOfString // 6
- メソッドのオーバーライド
class Trumpet: Instrument { override func play() { println("ぷぷー!") } }
- プロパティのオーバーライド
class Trumpet: Instrument { var lowestNote = "C4" // コンピューテッドプロパティdescriptionのゲッタをオーバーライド override var description: String { return "\(lowestNote)から" + super.description } override func play(){ println("ぷぷー!") } }
セッタをオーバーライドする場合には、ゲッタもオーバーライドが必要
初期化
- イニシャライザ
class Distance { var distanceInKm: Double init() { distanceInKm = 0 } }
ストアドプロパティはインスタンスの初期化で値の設定が必要
定義時設定か、初期化にて設定。
letはイニシャライザ初期化可。以後は変更不可。
- Optional型のプロパティの初期化
class Article { var title: String? } var a = Article() a.title // nilで初期化される
- 定数プロパティ
class Article { var title: String? let category: String = "default" init() { } init(category: String){ self.category = category } } var a1 = Article() a1.category // default定義 var a2 = Aeticle(category: "Blog") // イニシャライザで設定 a2.category // Blog
- 複数のイニシャライザ
class Distance { var distanceInKm: Double init(){ distanceInKm = 0 } init(fromMeter meter: Double){ distanceInKm = meter / 1000 } init(fromMile: Double){ distanceInKm = fromMile * 1.609344 } } var d1 = Distance(fromMeter: 10) d1.distanceInKm // 0.01 var d2 = Distance(fromMile: 10) d2.distanceInKm // 16.09344
外部名を指定。外部名が定義されていない場合は内部名。
『_』を指定して、外部名を省略可。
- デフォルトイニシャライザ
ベースのクラスでプロパティが指定され、イニシャライザが定義されていない場合、 自動的に定義される。引数なし。
- 失敗可能なイニシャライザ / init?キーワード
let urlOptional = NSURL(string: "http://www.google.com") // urlはOptional型の変数 if let url = urlOptional { // 成功 } else { // 失敗ではnilが返る }
- クラスの継承とイニシャライザ
サブクラスの初期化はスーパークラスも含めた初期化が必要。
Swiftは正しく初期化されるため、2種類のイニシャライザを定義している。
1 指定イニシャライザ
2 コンビニエンスイニシャライザ
- 指定イニシャライザ
init(パラメタ) { // 初期化処理 } // 自身がサブクラスなら、スーパークラスのイニシャライザを実行する
- コンビニエンスイニシャライザ
convenience init(パラメタ) { // 初期化処理 }
イニシャライザのルール
上記を考慮した例
class Instrument { var rangeOfOctaves = 0 var description: String { return "\(rangeOfOctaves)オクターブの音がでます" } func play() { } } class Trumpet: Instrument { var lowestNote: String override init (){ lowestNote = "C4" super.init() rangeOfOctaves = 1 } } var t = Trmpet() t.description // 1オクターブの音がでます
イニシャライザの継承 サブクラスはスーパークラスのイニシャライザを通常は継承しないが、特定の条件を満たすとスーパークラスのイニシャライザが継承される。 1 サブクラスに指定イニシャライザを定義していない時。
2 サブクラスにスーパークラスが持つ全てのイニシャライザが定義されている時。この場合、スーパークラスのコンビニエンスイニシャライザが継承される。関数やクロージャを使用した初期化
class Dice { var spot: UInt32 { return arc4random_uniform(6) }() }
デイニシャライザ / インスタンスが破棄される前に実行される処理
- デイニシャライザの定義
deinit { // 処理 }
プログラム内で明示的に実行できない・・・。
class MediaItem { var title: String init(title: String) { self.title = title } } class CD: MediaItem { var artist: String init(title: String, artist: String) { self.artist = artist super.init(title: title) } } class DVD: MediaItem { var director: String init(title: String, director: String){ self.director = director super.init(title: title) } } let mediaLibrary = [ CD(title: "Music", artist: "Madonna"), CD(title: "時間の翼", artist: "ZARD"), DVD(title: "The Devil Wears Prada", director: "David Frankel"), DVD(title: "天空の城ラピュタ", director: "宮崎駿"), ] // 型推測でMediaItem型の配列となる
- 型チェック演算子『is』の例
for item in mediaLibrary { if item is CD { println("CD: \(item.title)") } else if item is DVD { println("DVD: \(item.title)") } }
- ダウンキャスト
for item in mediaLibrary { if let cd = item ~~as?~~as! CD { println("CD: '\(cd.title)' artist: '\(cd.artist)'") } else if let dve = item ~~as?~~as! DVD { println("DVD: '\(dvd.title)' director: '\(dvd.director)'") } }
解説:『as?』『as!』を使用して、Optional型としてダウンキャストの結果を取得し、
Optional Bindingを使用してOptional型をアンラップし元の型を得ている。
- AnyObject型とAny型
AnyObject
すべてのクラスを含む型として使用可能
Any
Int型やString型などの値や構造体、クラスなど関数型以外のすべて
- 型チェックとダウンキャストの応用
var things = [Any]() things = [ 0, 0.0, 10, "swift", (10, 10), CD(title: "Music", artist: "Madonna"), ] for thing in things { switch thing { case 0 as Int: println("Intとしての0") case 0 as Double: println("Doubleとしての0") case let someInt as Int: println("何らかのInt: \(someInt)") case let someString as String: println("何らかのString: \(someString)") case let cd as CD: println("DC: \(cd.title)") default: println("それ以外のクラス") } }
メソッド・プロパティの設計のみを定義
- プロトコルの定義
protocol SomeProtocol { var someProperty: Int { get set } // セッタ・ゲッタを持つプロパティ var someReadOnlyProperty: Int { get } // ゲッタのみのプロパティ class func someTypeMethod() // タイプメソッド func someInstanceMethod(str: String) -> String // インスタンスメソッド }
- プロトコルの採用
class SomeClass: SomeProtocol { var someProperty = 10 var someReadOnlyProperty = 30 clss func someTypeMethod() { println("type method") } func someInstanceMethod(str: String) -> String { return "instance method" } }
お疲れ様でした。