#StackBounty: #swift #ios #reactive-programming #rx-swift UIView position updates based on device motion via RxSwift

Bounty: 50

I’ve created a simple function to work as a level, where the dot on screen is centered when the device is completely flat. It changes position based on device orientation. I use RxSwift to update the position of the dot. I’m relatively new to RxSwift, so I’m worried that I’m not using it correctly or to its full value.

I also don’t understand capturing self all that well, so please feel free to analyze that as well.

Any input is appreciated!

class ViewController: UIViewController {

    @IBOutlet var levelDot: UIView!
    var positiveMax: (x: CGFloat, y: CGFloat)!
    
    override func viewDidLoad() {
        levelDot.center = self.view.center
        super.viewDidLoad()
        positiveMax = (view.frame.maxX, view.frame.maxY)
        initGryo()
    }

    fileprivate func initGryo() {
        let pitch = PublishSubject<Double>()
        let roll = PublishSubject<Double>()
        let motion = CMMotionManager()
        guard motion.isDeviceMotionAvailable else { return }
        motion.deviceMotionUpdateInterval = 1/60
        motion.startDeviceMotionUpdates()
        let gyroTimer = Timer(fire: Date(), interval: 1/60, repeats: true, block: { timer in
            if let attitude = motion.deviceMotion?.attitude {
                let yModifier: CGFloat = 1.3 // modifier is to make small changes seem bigger on the screen
                
                _ = pitch.map( { (self.positiveMax!.y + CGFloat($0)*self.positiveMax!.y * yModifier) })
                    .map( {$0 / 2} )
                    .subscribe(onNext: { centerY in
                        
//prevent dot from moving off screen
                        guard centerY < self.positiveMax.y else { 
                            self.levelDot.center.y = self.positiveMax.y
                            return
                        }
                        guard centerY > 0 else {
                            self.levelDot.center.y = 0
                            return
                        }
//dot position -- does this capture self? would making levelDot a weak var prevent this?
                        self.levelDot.center.y = centerY
                        
                    })
                pitch.onNext(attitude.pitch)
                
                let xModifier: CGFloat = 1.15 // modifier is to make small changes seem bigger on the screen
                _ = roll.map( { (self.positiveMax!.x + CGFloat($0)*self.positiveMax!.x*xModifier) })
                    .map({ $0 / 2 })
                    .subscribe(onNext: { centerX in
//prevent dot from moving off screen
                        guard centerX < self.positiveMax.x else {
                            self.levelDot.center.x = self.positiveMax.x
                            return
                        }
                        guard centerX > 0 else {
                            self.levelDot.center.x = 0
                            return
                        }
//dot position 
                        self.levelDot.center.x = centerX
                    })
                roll.onNext(attitude.roll)
            }
        })
        RunLoop.current.add(gyroTimer, forMode: .default)
        
    }
    
}


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.