🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
並列処理

複数の計算が同時に実行される手法

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

3237閲覧

[Swift] Timer関数を並列処理で行う

lahlah

総合スコア16

並列処理

複数の計算が同時に実行される手法

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2019/10/10 09:03

編集2019/10/17 07:19

前提・実現したいこと

PDFを見ている時に、Timer関数で別の処理を行おうとしています.
全てをメインスレッドを行うと、TimerのIntervalが設定した通りにならず、ズレてしまいます.
そこで、TimerのIntervalを出来るだけ正確にするために、Timer関数は別のスレッドで処理するようにしたいと考えています.

調べたところ、Swiftで並列処理を行う時は、GCD または OperationQueue を使うようだと分かりました.
しかし今回の場合、どちらを使う方が適しているのか、よく分かりませんでした.
取り敢えず、こちらのサイトを参考に、OperationQueueを使ってみようとしましたが、エラーが発生してしまいます.

そもそも、参考サイトと同じようなやり方で実現できるのか疑問なのですが、並列処理を使ったプログラムを書くのが初めてで、何をどう変えるべきなのか、調べてもよく分かりません.

どのようにすれば、Timer関数を別のスレッドで処理できるのでしょうか?
ご回答よろしくお願いします.

発生している問題・エラーメッセージ

Initializers may only be declared within a type

該当のソースコード

//OperationQueue class PendingOperations { lazy var timeQueue: OperationQueue = { var queue = OperationQueue() queue.name = "Timer Queue" queue.maxConcurrentOperationCount = 1 return queue }() } //タイマー class TimerCount: Operation { override func main(){ //キャンセルされているか if isCancelled { return } var timer = Timer() init(){ //タイマー開始 self.timer = Timer.scheduledTimer(timeInterval:0.02, target:self, selector: #selector(ComicViewController.update), userInfo: nil, repeats: true) } } }

試したこと

override func main() をコメントアウトしてみましたが、別のエラーメッセージ(Overriding declaration requires an 'override' keyword)が発生します.

補足情報(FW/ツールのバージョンなど)

バージョン
Xcode 10.3 → Xcode 11.1(10/17), Swift 5.0.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takabosoft

2019/10/11 07:52

> TimerのIntervalが設定した通りにならず、ズレてしまいます とありますが、そこまで精度が必要な理由ってなんでしょう?
lahlah

2019/10/11 08:21

>takabosoftさん 取得間隔が出来るだけ高い精度で、データを一定間隔ごとに取得したいため、その方法を考えています. 間隔がズレるタイミングがPDFが次のページ切り替わるところなどでしたので、UI関連(?)とは違うスレッドで処理を行う必要があると判断したのですが… >tyobigorouさん ありがとうございます!試してみます.
lahlah

2019/10/15 14:03

遅くなり申し訳ありません. 教えていただいた、RunLoopを使用する方法で、ほぼ改善されたのですが、未だ最初の5回分くらいについては取得間隔が安定しません.(5回分くらいであれば、そんなに支障はないとは思うのですが、可能ならば最初から取得間隔が安定していて欲しいと考えています) Timerは最初のほう取得間隔が安定しづらいといった傾向があるのでしょうか… もし別の原因が何か考えられるのであれば、教えていだだけると有難いです.
guest

回答2

0

自己解決

timer関数を使う場合

swift

1timer = Timer.scheduledTimer(timeInterval:0.1, target:self, selector: #selector(ViewController.update), userInfo: nil, repeats: true) 2RunLoop.current.add(timer, forMode: .common)

while文を使う場合

swift

1DispatchQueue.global().async { 2 while running == true { 3 //いまの時刻の ミリ秒 のところを取ってくる 4 let msec = Double(Calendar.current.component(.nanosecond, from: Date())) 5 let nano = msec / 1000000000.0 6 let ss = Int(floor(nano*1000)) 7 8 9 //if文使って取得間隔を一定に 10 //取得間隔をどう設定するかで判定方法は違うので、自由に設定して下さい 11 12 13 //必要に応じて繰り返しを減らす(CPUパワー食い過ぎないように) 14 //sleep時間は任意の時間でok 15 usleep(1000) 16 } 17}

このどちらかで取得間隔をそれなりの精度で取得できると思います.
取得間隔が最初の方安定しなかった原因はこちらのようでした.
ここを修正しても、長時間のデータでは間隔が安定しないかもしれません.

新しく分かったことがあれば、随時補足致します.
色々教えて下さったお二人ありがとうございました.

投稿2019/10/24 07:51

lahlah

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ググっただですが、この辺のタイマークラスを使用すると少しは改善したりしますかね?
https://medium.com/over-engineering/a-background-repeating-timer-in-swift-412cecfd2ef9
記事的にはバックグラウンドでタイマーが動くようなものだと思うのですが。

githubだとこちら:
https://gist.github.com/danielgalasko/1da90276f23ea24cb3467c33d2c05768

投稿2019/10/16 02:44

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lahlah

2019/10/17 06:54

ご回答ありがとうございます. こちらの方法も試してみましたが、やはり最初のほうは取得間隔が安定しないままでした… While文を使って現時刻を繰り返し取得し、ある秒数になるたびに関数(データを取得する)を呼び出すという方法も考えてみましたが、この場合もWhile文の処理は別のスレッドで行わなければ無限ループするだけになってしまうようでした.(この方法を試すとstoryboardで配置したボタンやラベルが、プログラムを実行した最初の段階から表示されなかったので、別のスレッドで実行しなければいけないのかと考えました.) これ以上の精度は期待できないと考えるべきでしょうか…?
takabosoft

2019/10/17 06:59

その「whileを使って時間を見続ける」という処理そのものを別スレッドでやるしかないでしょうね。適度にThread.sleep(forTimeInterval: 0.1)とかを入れないとCPUパワーを食いすぎそうな予感ですが・・・。 もともと別スレッドで動いていたとしても、それが期待通りのタイミングで動作する保証は何も無いいので、どれだけ誤差を小さくできるかという観点で検証してもらえればと思います。
lahlah

2019/10/17 07:16

コメントありがとうございます. 別スレッドで行っても上手くいくとは限らないのですね… 一応While文を別スレッドで行う方法も試してみます.(スレッドの立て方が未だ理解しきれていないので時間が掛かると思います)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問