フリープログラマー日記

iOS,アンドロイド開発を気ままにしながら生きてるおじさんのブログです。

第35回 static でデータクラス

 またまた、2日間くらい悩みまくりました。
 私のアプリの場合、個人を "Runnerクラスのインスタンス"にして、それを束ねて、Arrayとする。この方向は間違っていないと思ってました。一般的なものでは、顧客クラスや社員クラスなどは同じような扱いなんだろうと思うのですが、他のクラスとやりとりが多く、混沌とした状態になって、とてもお見せできるものとは言えませんでした。

 よく見れば、Runnerは全て Teamクラスに属しています。社員オブジェクトが会社クラスに属しているのと同じなのかなと。
 そして、Teamクラスのコメント欄に、このクラスのインスタンスはアプリ開始時に一回だけ作る・・・と書いてある。いや、自分で忘れないように書いたのだけど、これって、Teamクラスのメンバを全て static にすればいいんじゃないかい?って思ったんですね。

こちらがその Team クラス。

import UIKit
class Team {
    // static でアクセスできるように変更
    // ランナーの所属に関する処理

    static var lastId: Int = 0     // メンバーIDの最後
    static var runners: Array<Runner> = []
    
    // ファイル操作
    static private func loadLastId() -> Int {
        var result: Int
        let userDefault = UserDefaults.standard
        if userDefault.object(forKey: "LastID") != nil {
            result = userDefault.integer(forKey: "LastID")
        } else {
            result = 0
        }
        return result
    }

    static func saveLastId() {
        let userDefault = UserDefaults.standard
        userDefault.set(lastId, forKey: "LastID")
    }
    
    // 選手のマネージメント ===============
    static private func loadAllRunner() {
        // 初期化作業、アプリ開始後に一回だけ実行
        // 登録数が 0 の時は、名前の読み込みはしない
        if lastId != 0 {
            var num: Int = 0
            for i in (1...lastId) {
                // 削除されたメンバーも含まれるが登録しない
                let runner = Runner(runnerId: i)
                if runner.isMember() {
                    num += 1
                    runner.setMyNumer(num: num)
                    runners.append(runner)
                }
            }
        }
    }
    
    // 選手の追加
    static func addRunner(name: String) {
        // 新しいrunnerオブジェクトを作り、氏名を保存する
        lastId += 1
        saveLastId()
        let newRunner: Runner = Runner(runnerId: lastId)
        newRunner.saveName(name: name)
        runners.append(newRunner)
    }
    // 選手の削除
    
}


そして、Runnerクラス。

import UIKit

class Runner {
    
    var myNumber: Int = 0
    let myId: Int
    private var myName: String = ""
    private var member: Bool = false
    var entry: Bool = false
    var lap: Int = 0
    private var time: [Int] = []    // タイムは100倍して切り捨て
    
    init(runnerId: Int) {
        // runnerIdを元にファイルから氏名とステータス(削除)をロードする
        myId = runnerId
        loadName(id: runnerId)
    }
    
    // 名前と部員状態のセーブとロード
    private func loadName(id: Int) {
        let userDefault = UserDefaults.standard
        let nameKey = "name\(id)"       // ファイル上の識別子
        if userDefault.object(forKey: nameKey) != nil {
            myName = userDefault.string(forKey: nameKey)!
        }
        let memberKey = "member\(id)"       // ファイル上の識別子
        if userDefault.object(forKey: memberKey) != nil {
            member = userDefault.bool(forKey: memberKey)
        }
    }
    
    public func saveName(name: String) {
        myName = name
        // ID番号を使って名前をUserDefaultsに保存してお
        let userDefault = UserDefaults.standard
        let nameKey = "name\(myId)"
        userDefault.set(myName, forKey: nameKey)
        let memberKey = "member\(myId)"       // ファイル上の識別子
        userDefault.set(member, forKey: memberKey)
    }
    
    public func setMyNumer(num: Int) {
        myNumber = num
    }

    public func getName() -> String {
        return myName
    }
    
    public func isMember() ->Bool {
        return member
    }
    
    // Entryビューの乗せるための部品
    public func makeRunnerEntryView() -> RunnerEntryView {
        
        let view: RunnerEntryView = RunnerEntryView(number: myNumber, name: myName)
        
        // ハンドラーのセット
        view.setEntryOk {
            self.entry = true
        }
        view.setEntryCancel {
            self.entry = false
        }   
        return view
    }
 
    // ラップデータの処理
    func setLapTime(rapTime: Float) {
        // 100倍して整数化
        let time100 = Int(rapTime*100)
        time.append(time100)
        lap += 1    // ラップ数をカウント
    }
    
    // ラップボタン
    func LapButton(frame: CGRect) -> UIButton {
        let lapButton: UIButton = UIButton(frame: frame)
        lapButton.setTitle(myName, for: .normal)   
        return lapButton
    }
}

Runnerクラスは結構ゴチャゴチャしてます。

こうすると、どのクラスからでも、 Team.runners[番号]の形でアクセスできてしまうので、楽なのかなと思っているところなのです。

staticの使い方を知らなかったので、しかも、正式に教わったものでもないので、これが正しい使い方かどうかわかりません。ま、動けば良しとした方が楽できるし、所詮、アマチュアプログラマーなので。

 ちなみに、某swift教科書には「"static"は構造体、または列挙型特有のプロパティとメソッドに指定する修飾子です。」と書いてある。・・・(よくわかりません)

 せめてもの救いは、javaもswiftも static をキーワードにもっているということで、そこで悩まなくていいので嬉しいかな。