71027


Swiftでの配列とメモリの扱いについて知りたいです。

配列に大量の要素をappendする場合、変数に対して大量のデータを入れると、そのデータはメモリ内部に蓄積されたままになると思います。あまり望ましくない状態なのではないかと思います。

このデータをテキストファイルなどに保存しておくのが良いのか、userDefaultなどに保存するのが良いのか、どのような扱いをするのが良いのかアドバイスがほしいです。

以下のようなコードを試しました。  
1秒間に100回ループを回して、配列に現在時刻を追加するだけのコードです。  
配列に保存したデータは、一定数溜まったら、あとでprint文で使用します。  
毎秒100回ループでprintを行います。  
数十分から数時間のデータ記録と再生を想定しています。

[code]

    import UIKit
    
    class ViewController: UIViewController {
        
        var timer: Timer!
        var recordedArray:[String] = []
        var recordedArrayPlayCount = 0
        var play_or_rec = "rec"
    
        override func viewDidLoad() {
            super.viewDidLoad()
        
            //0.01秒ごとに繰り返す、repeat every 3 seconds
            timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
            timer.fire()
        }
        
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(true)
            timer.invalidate()
        }
        
        @objc func update(tm: Timer) {
            //この関数を繰り返す、repeat this function
            if self.play_or_rec == "rec"
            {
                //recモードのときは配列に追加する
                let nowTime = getNowClockString()
                recordedArray.append(nowTime)
            }
            else if self.play_or_rec == "play"
            {
                //playモードのときはprintする
                if recordedArray.count > self.recordedArrayPlayCount
                {
                    print(recordedArray[self.recordedArrayPlayCount])
                    self.recordedArrayPlayCount += 1
                }
                else
                {
                    self.play_or_rec = "rec"
                }
            }
        }
        
        //現在時刻の文字列を取得
        func getNowClockString() -> String {
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ss"
            let now = Date()
            return formatter.string(from: now)
        }
        
        //recordとplayとstopを切り替える
        @IBAction func playOrRecordButtonTapped(_ sender: Any)
        {
            if self.play_or_rec == "rec"//record状態からstop1へ移行
            {
                self.play_or_rec = "stop1"
            }
            else if self.play_or_rec == "stop1"//stop1状態からplay状態へ移行
            {
                self.play_or_rec = "play"
                self.recordedArrayPlayCount = 0
            }
            else if  self.play_or_rec == "play"//play状態からstop2状態へ移行
            {
                self.play_or_rec = "stop2"
            }
            else if  self.play_or_rec == "stop2"//stop2状態からrecord状態へ移行
            {
                self.play_or_rec = "rec"
            }
        }
        
    }
    
[/code]

playOrRecordButtonTappedの部分を、以下のようなコードに書き換えた場合、効果はあるのでしょうか？  
stop状態の間は、userDefaultsにデータを預けて、配列を初期化しています。  
こうすることで、メモリを空けて、ストレージ側にデータが行くのでマシンには優しい設計になるかと思ったのですが、どうでしょうか...?  
正しくない設計でしょうか...?

[code]

        //recordとplayとstopを切り替える
        @IBAction func playOrRecordButtonTapped(_ sender: Any)
        {
            if self.play_or_rec == "rec" //record状態からstop1状態へ以降
            {
                //配列をuserDefaultsに保存
                userDefaults.set(self.recordedArray, forKey: "recordedArray")
                userDefaults.synchronize()
                
                //停止中はメモリを空けておきたいので、配列を初期化
                self.recordedArray = []
                
                self.play_or_rec = "stop1"
            }
            else if self.play_or_rec == "stop1"//stop1状態からplay状態へ以降
            {
                self.recordedArray = userDefaults.object(forKey: "recordedArray") as! [String]
                self.recordedArrayPlayCount = 0
                self.play_or_rec = "play"
            }
            else if  self.play_or_rec == "play"//play状態からstop2状態へ以降
            {
                //停止中はメモリを空けておきたいので、配列を初期化
                self.recordedArray = []
                
                self.play_or_rec = "stop2"
            }
            else if self.play_or_rec == "stop2"
            {
                self.play_or_rec = "rec"
            }
        }
    
[/code]

メモリ等のパフォーマンスがよくなるように、よりよい方法があったら教えて頂きたいです。


CC BY-SA 4.0
2020-10-08T14:12:11.053
71022
2020-10-08T16:31:08.027
36446
question
swift
Swiftでの配列への大量のデータのappendとメモリの使用率等について


このケースの場合、フラグだけでは無く、配列の最大長を設定しておき、その条件判定も含めて保存するか決めた方が良さそうです。一定以上の配列長になった場合は常に保存し、メモリを無制限に使わないようにする必要があります。

また、UserDefaultsは大量のデータを入れるためのものではなく、基本的にアプリ設定などを保存するためのものです。特性として、大量データを入出力すると保存・読み出し共に大幅に性能が落ちてしまいます。  
今回の場合は、テキストファイルでデータを保存するのが一番簡単でやりやすいと思います。


CC BY-SA 4.0
2020-10-08T16:31:08.027
71027
2020-10-08T16:31:08.027
8795
71022
answer