解決したいこと
Xcodeで定期的に処理を行うアプリをつくっています。
定期的に処理を行う中である値を参照する前後で値が変わってしまう症状が見られました。
解決方法を教えて下さい。
開発環境
Xcode Version 14.2
Interface Storyboard
macOS monterey 13.0.1
問題点
以下のコードを出力した結果、2箇所の'print(deltaDegree)'で異なる値が出力されました。
出力結果は以下のとおりです。
2023-02-02 04:25:18.089535+0900 ButtonSample[43127:1394882] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600003622e00> F8BB1C28-BAE8-11D6-9C31-00039315CD46 0.12195121951219512 117480667527541.67
一つ目の結果(0.12195121951219512)は、直前の計算から得られたもので、自前の電卓を用いて計算しても同様の結果が得られました。
該当するソースコード
swift
1import UIKit 2import AVFoundation 3 4class ViewController: UIViewController { 5 6 @IBOutlet weak var btnCount: UIButton! 7 @IBOutlet weak var btnExplosion: UIButton! 8 @IBOutlet weak var imgBom: UIImageView! 9 10 // ボタンフラグ 11 var buttonStartFlg = true 12 // 現時点での回転角 13 var currentDegree: CGFloat = 0 14 // 定期割り込みのための Timer のインスタンス 15 var timer = Timer() 16 var interval: TimeInterval = 0.01 17 18 override func viewDidLoad() { 19 super.viewDidLoad() 20 } 21 22 @IBAction func btnCount(_ sender: Any) { 23 24 btnCount.isEnabled = false 25 btnExplosion.isEnabled = true 26 27 // 初期スピード 28 let degree: CGFloat = 30 29 // 回転処理に使われるメソッドは rotateImage) 30 timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(rotateImage), userInfo: degree, repeats: true) 31 buttonStartFlg = false 32 } 33 34 @IBAction func btnExplosion(_ sender: Any) { 35 // 初期スピード 36 let degree: CGFloat = 30 37 38 let stopDegree: CGFloat = 90.0 39 let dDmolecule = 0.5 * pow(degree, 2) 40 currentDegree = 0 41 let dDdenominator = (360.0 * 10) + stopDegree 42 43 let deltaDegree = dDmolecule / dDdenominator 44 45 print(deltaDegree) 46 47 // 定期的な呼び出しを中止する 48 timer.invalidate() 49 // 回転を徐々に止めるためのメソッドを1回だけ(repeats: false)呼び出し 50 // 止めるために使われるメソッドは stopImage 51 timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(stopImage(_:deltaDegree:)), userInfo: degree, repeats: false) 52 } 53 54 @objc func rotateImage(_ sender: Timer) { 55 let degree = sender.userInfo as! CGFloat 56 let angle = currentDegree * CGFloat.pi / 180 // Radian 57 let affine = CGAffineTransform(rotationAngle: angle) 58 imgBom.transform = affine 59 currentDegree += degree 60 currentDegree.formRemainder(dividingBy: 360.0) 61 } 62 63 // ストップボタンを押した後、止まるまで呼び出される回転処理 64 @objc func stopImage(_ sender: Timer , deltaDegree: CGFloat) { 65 66 print(deltaDegree) 67 68 var degree = sender.userInfo as! CGFloat 69 let angle = currentDegree * CGFloat.pi / 180 // Radian 70 let affine = CGAffineTransform(rotationAngle: angle) 71 72 imgBom.transform = affine 73 74 currentDegree += degree 75 currentDegree.formRemainder(dividingBy: 360.0) 76 77 // 回転角を減らす 78 degree -= deltaDegree 79 80 if degree > 0 { 81 // 回転角が正の間は、減らした回転角を使って再度タイマ割り込みを使う 82 timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(stopImage(_:deltaDegree:)), userInfo: degree, repeats: false) 83 } 84 } 85}
自分で試したこと
このコードは以下のサイトを参考に記述しました。
あなたの回答
tips
プレビュー