Swift入門メモ -get/set,willSet/didSet・Optionl Chaining・Type Casting-

19 get/set,willSet/didSet

dotinstall.com

get/set

  • プロパティを動的に計算
  • プロパティの値を取得する時と設定する時に計算式が書ける
class Student {
    var name: String
    var number: Int
    var attendance: Int = 0
    var rate: Int {
        get {
            // selfは省略出来る
            return Int(Float(attendance) / 10.0 * 100)
        }
        set {
            // 渡された値を「newValue」でとることが出来る
            // attendanceの値を書き換える
            attendance = Int(newValue / 10)
        }
    }
    
    init(name: String, number: Int) {
        self.name = name
        self.number = number
    }
    func attended() {
        attendance++
    }
}

var mayama = Student(name: "rika", number: 3)
mayama.attendance // 0
mayama.rate // 0
mayama.attendance = 1
mayama.rate // 10
mayama.attendance = 3
mayama.rate // 30


// rateを更新してattendanceの値を変える
mayama.rate = 100
mayama.attendance // 10
mayama.rate = 80
mayama.attendance // 8
  • getしか使わない場合
class Student {
    var name: String
    var number: Int
    var attendance: Int = 0
    var rate: Int { // getだけの場合はreturnを書くだけ
        return Int(Float(attendance) / 10.0 * 100)
    }
    
    init(name: String, number: Int) {
        self.name = name
        self.number = number
    }
    func attended() {
        attendance++
    }
}

willSet/didSet

  • プロパティの状態監視
  • 値が変わった時、変わる前と変わった後で何らかの処理を入れることができる
  • プロパティが最初に初期化されるときには実行されない
class Student {
    var name: String
    var number: Int
    var attendance: Int = 0 {
        willSet { // 変わる前にしたい処理
            // 新しい値は「newValue」
            println("willSet: \(attendance) -> \(newValue)")
        }
        didSet { // 変わった後にしたい処理
            // 古い値は「oldValue」
            println("didSet: \(oldValue) -> \(attendance)")
        }
    }
    var rate: Int {
        return Int(Float(attendance) / 10.0 * 100)
    }
    
    init(name: String, number: Int) {
        self.name = name
        self.number = number
    }
    func attended() {
        attendance++
    }
}


var mayama = Student(name: "rika", number: 3)
mayama.attendance = 9 // willSet: 0 -> 9 / didSet: 0 -> 9
mayama.attendance = 10 // willSet: 9 -> 10 / didSet: 9 -> 10

20 Optionl Chaining

dotinstall.com

  • クラスなどが複雑に入り組んでいた時に、プロパティやメソッドがあるか安全に確かめる方法
  • 先頭から調べて行って、nilだった場合はそこで評価を止め、安全に終了させてnilを返す
  • 複雑になると、?マークがたくさんついていく
class User {
    var blog: Blog? // Blog型のOptional
}

class Blog {
    var title = "My Blog"
}

var gawao = User()

// ================
// ★blogプロパティが存在する場合は以下のように取れる
// gawao.blog = Blog()
// Unwrapしてtitleを取得
// gawao.blog!.title // My Blog


// ================
// ★blogプロパティがnilの場合 「gawao.blog!.title」でエラーになる
// Optional Chainingを使う
gawao.blog?.title // nil

// ================
// ★よく書くやり方
// titleがある場合はtを表示する
// - nilの場合はエラーなく終了
// - gawao.blogがある場合は「My Blog」と表示される
if let t = gawao.blog?.title {
    println(t)
}

21 Type Casting

dotinstall.com

  • クラスの型をチェックしたり、あるクラスを親クラス・子クラスとして扱うための方法
  • クラスの型チェックはis
  • asを使ってあるクラスを子クラスに変換することをダウンキャストするという
  • どのようなオブジェクトのインスタンスでもいいという特殊なデータ型がある AnyObject
class User {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class AdminUser: User {}

let kashiwagi = User(name: "hinata")
let matsuno = AdminUser(name: "rina")

// クラスの型が違うがエラーにならない
let users: [User] = [kashiwagi, matsuno]

// クラスごとに処理を分けたいとき
// 型チェック、変換に使える-> is / as

for user in users {
    // AdminUserクラスか調べる->is
    if user is AdminUser {
        // UserクラスからAdminUserクラスにダウンキャスト->as
        let u = user as AdminUser
        println(u.name) //  rina
    }
}
    // userをダウンキャスト->うまくいったらブロックの処理。うまくいかなかったらnilを返す
    if let u = user as? AdminUser {
        println(u.name) //  rina
    }

// ====↓の部分は↑のように書き換えることが出来る====

//    // AdminUserクラスか調べる->is
//    if user is AdminUser {
//        // UserクラスからAdminUserクラスにダウンキャスト->as
//        let u = user as AdminUser
//        println(u.name) //  rina
//    }
class User {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class AdminUser: User {}

class SomeUser {}

let kashiwagi = User(name: "hinata")
let matsuno = AdminUser(name: "rina")
let nakayama = SomeUser()


// 継承関係にないインスタンスが含まれているのでエラーになる
// let users: [User] = [kashiwagi, matsuno, nakayama]

// どのようなオブジェクトのインスタンスでもOKなAnyObjectを使う
let users: [AnyObject] = [kashiwagi, matsuno, nakayama]