How to detect jump with Core Motion? - ios

I want to make jump rope counter, but I don't know how to detect jump and I did't find any solution for it. Please, help!
final class WorkoutViewController: UIViewController {
private var motionManager = CMMotionManager()
private var jumpCounter = 0
func jump() {
let xAxis = motionManager.deviceMotion!.userAcceleration.x
let yAxis = motionManager.deviceMotion!.userAcceleration.y
let zAxis = motionManager.deviceMotion!.userAcceleration.z
let xGravity = motionManager.deviceMotion!.gravity.x
let yGravity = motionManager.deviceMotion!.gravity.y
let zGravity = motionManager.deviceMotion!.gravity.z
// I don't know how to detect a jump here
}
override func viewDidLoad() {
super.viewDidLoad()
motionManager.deviceMotionUpdateInterval = self.updateDataInterval
motionManager.startDeviceMotionUpdates(to: .main) { (_, _) in
self.jump()
}
}
}

Related

How can I combine all 3 gyroscope axis to produce 1 int? Xcode Swift Core Motion

I've followed a few things including Apple's documentation on the core motion. This is probably very simple to do, I just can't put my finger on it. Basically, I'm trying to get all of the X, Y, and Z data, combine it and make it constantly add to the "scoreValue" text. Basically, a constant counter that counts the total degrees rotated ever.
import UIKit
import CoreMotion
class ViewController: UIViewController {
#IBOutlet var scoreValue: UITextView!
#IBOutlet weak var Label: UILabel!
var motion = CMMotionManager()
override func viewDidLoad() {
super.viewDidLoad()
myGyroscope()
view.backgroundColor = .systemBlue
}
func myGyroscope() {
motion.gyroUpdateInterval = 0.1
motion.startGyroUpdates(to: OperationQueue.current!) { [self]
(data, error) in
print(data as Any)
if let trueData = data {
self.view.reloadInputViews()
let x = trueData.rotationRate.x
let y = trueData.rotationRate.y
let z = trueData.rotationRate.z
self.UNDEFINED.text = "\(Double(x).rounded(toPlaces :0))"
self.UNDEFINED.text = "\(Double(y).rounded(toPlaces :0))"
self.UNDEFINED.text = "\(Double(z).rounded(toPlaces :0))"
}
}
return
}
}
extension Double {
/// Rounds the double to decimal places value
func rounded(toPlaces places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}

How use accelerometer in swift 3

I need help to use accelerometer with swift 3.
This is my code:
var motion = CMMotionManager()
#IBOutlet weak var statusAccel: UILabel!
override func viewDidAppear(_ animated: Bool) {
motion.startAccelerometerUpdates(to: OperationQueue.current!){
(data , error) in
if let trueData = data {
self.view.reloadInputViews()
self.statusAccel.text = "\(trueData)"
}
}
}
It works but it just show me X Y and Z and i want to use Z.
Example : if Z = 2 do something
You can access the acceleration on the Z-axis by calling CMAccelerometerData.acceleration.z. If you are unsure about how to access a certain property of a class, always check the documentation either in Xcode directly or on Apple's documentation website, you can save a lot of time with this approach.
motion.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: { data, error in
guard error == nil else { return }
guard let accelerometerData = data else { return }
if accelerometerData.acceleration.z == 2.0 {
//do something
}
})
The data object that gets returned by startAccelerometerUpdates(...) is of type CMAccelerometerData which has a CMAcceleration property. From this you can get the z component.
var motion = CMMotionManager()
#IBOutlet weak var statusAccel: UILabel!
override func viewDidAppear(_ animated: Bool) {
motion.startAccelerometerUpdates(to: OperationQueue.current!){
(data , error) in
if let trueData = data {
self.view.reloadInputViews()
self.statusAccel.text = "\(trueData)"
if trueData.acceleration.z == 2 {
// do things...
}
}
}
}

How do i use mapbox's new MGLOfflinePackDelegate correctly?

I'm creating an app which needs an offline map. I'm testing with MapBox, which supports offline maps since today (yay!). The code I have now seems to work for downloading the map, but the delegate to report on progress never triggers, and I don't have a clue why this is.
I have this class for my mapView:
import UIKit
import Mapbox
class MapController: UIViewController, MGLMapViewDelegate, UIPopoverPresentationControllerDelegate {
#IBOutlet var mapView: MGLMapView!
override func viewDidLoad() {
super.viewDidLoad()
downloadIfNeeded()
mapView.maximumZoomLevel = 18
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func downloadIfNeeded() {
MGLOfflineStorage.sharedOfflineStorage().getPacksWithCompletionHandler { (packs, error) in guard error == nil else {
return
}
for pack in packs {
let userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context) as! [String: String]
if userInfo["name"] == "London" {
// allready downloaded
return
}
}
// define the download region
let sw = CLLocationCoordinate2DMake(51.212120, 4.415906)
let ne = CLLocationCoordinate2DMake(51.223781, 4.442401)
let bounds = MGLCoordinateBounds(sw: sw, ne: ne)
let region = MGLTilePyramidOfflineRegion(styleURL: MGLStyle.streetsStyleURL(), bounds: bounds, fromZoomLevel: 10, toZoomLevel: 12)
let userInfo = ["name": "London"]
let context = NSKeyedArchiver.archivedDataWithRootObject(userInfo)
MGLOfflineStorage.sharedOfflineStorage().addPackForRegion(region, withContext: context) { (pack, error) in
guard error == nil else {
return
}
// create popup window with delegate
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let downloadProgress: MapDownloadController = storyboard.instantiateViewControllerWithIdentifier("MapDownloadController") as! MapDownloadController
downloadProgress.modalPresentationStyle = .Popover
downloadProgress.preferredContentSize = CGSizeMake(300, 150)
let popoverMapDownloadController = downloadProgress.popoverPresentationController
popoverMapDownloadController?.permittedArrowDirections = .Any
popoverMapDownloadController?.delegate = self
popoverMapDownloadController?.sourceView = self.mapView
popoverMapDownloadController?.sourceRect = CGRect(x: self.mapView.frame.midX, y: self.mapView.frame.midY, width: 1, height: 1)
self.presentViewController(downloadProgress, animated: true, completion: nil)
// set popup as delegate <----
pack!.delegate = downloadProgress
// start downloading
pack!.resume()
}
}
}
}
And the MapDownloadController is a View which is displayed as popup (see code above) and has the MGLOfflinePackDelegate:
import UIKit
import Mapbox
class MapDownloadController: UIViewController, MGLOfflinePackDelegate {
#IBOutlet var progress: UIProgressView!
#IBOutlet var progressText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func offlinePack(pack: MGLOfflinePack, progressDidChange progress: MGLOfflinePackProgress) {
// this function is never called, but why? <----
let completed = progress.countOfResourcesCompleted
let expected = progress.countOfResourcesExpected
let bytes = progress.countOfBytesCompleted
let MB = bytes / 1024
let str: String = "\(completed)/\(expected) voltooid (\(MB)MB)"
progressText.text = str
self.progress.setProgress(Float(completed) / Float(expected), animated: true)
}
func offlinePack(pack: MGLOfflinePack, didReceiveError error: NSError) {
// neither is this one... <----
let userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context) as! [String: String]
let strError = error.localizedFailureReason
}
func offlinePack(pack: MGLOfflinePack, didReceiveMaximumAllowedMapboxTiles maximumCount: UInt64) {
// .. or this one <----
let userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context) as! [String: String]
}
}
This is all pretty much taken from the documentation, so why are the delegate's functions (func offlinePack) never called? I did test with breakpoints so i am sure it is not. Still, the popup is shown and the region gets downloaded. (Checked with observing network traffic and with other code which lists the offline packs.)
Here’s an extremely simple implementation of Minh’s answer, using the current v3.2.0b1 example code. Expect this answer to become outdated quickly, as we’re still working on the v3.2.0 release.
import UIKit
import Mapbox
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate, MGLOfflinePackDelegate {
#IBOutlet var mapView: MGLMapView!
// Array of offline packs for the delegate work around (and your UI, potentially)
var offlinePacks = [MGLOfflinePack]()
override func viewDidLoad() {
super.viewDidLoad()
mapView.maximumZoomLevel = 2
downloadOffline()
}
func downloadOffline() {
// Create a region that includes the current viewport and any tiles needed to view it when zoomed further in.
let region = MGLTilePyramidOfflineRegion(styleURL: mapView.styleURL, bounds: mapView.visibleCoordinateBounds, fromZoomLevel: mapView.zoomLevel, toZoomLevel: mapView.maximumZoomLevel)
// Store some data for identification purposes alongside the downloaded resources.
let userInfo = ["name": "My Offline Pack"]
let context = NSKeyedArchiver.archivedDataWithRootObject(userInfo)
// Create and register an offline pack with the shared offline storage object.
MGLOfflineStorage.sharedOfflineStorage().addPackForRegion(region, withContext: context) { (pack, error) in
guard error == nil else {
print("The pack couldn’t be created for some reason.")
return
}
// Set the pack’s delegate (assuming self conforms to the MGLOfflinePackDelegate protocol).
pack!.delegate = self
// Start downloading.
pack!.resume()
// Retain reference to pack to work around it being lost and not sending delegate messages
self.offlinePacks.append(pack!)
}
}
func offlinePack(pack: MGLOfflinePack, progressDidChange progress: MGLOfflinePackProgress) {
let userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context) as! [String: String]
let completed = progress.countOfResourcesCompleted
let expected = progress.countOfResourcesExpected
print("Offline pack “\(userInfo["name"])” has downloaded \(completed) of \(expected) resources.")
}
func offlinePack(pack: MGLOfflinePack, didReceiveError error: NSError) {
let userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context) as! [String: String]
print("Offline pack “\(userInfo["name"])” received error: \(error.localizedFailureReason)")
}
func offlinePack(pack: MGLOfflinePack, didReceiveMaximumAllowedMapboxTiles maximumCount: UInt64) {
let userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context) as! [String: String]
print("Offline pack “\(userInfo["name"])” reached limit of \(maximumCount) tiles.")
}
}
(Cross-posted from this GitHub issue.)
This is a bug in the SDK. The workaround is for the completion handler to assign the passed-in MGLOfflinePack object to an ivar or other strong reference in the surrounding MapDownloadController class (example).

Swift - Animate dynamically created UIImageView

Initially I had this code working when I was just animating the one UIImageView that I had. But then I changed it to animate several dynamically created UIImageViews, however since they are dynamically created inside a for loop, I'm finding it difficult to animate them as I did the initial one.
override func viewDidLoad() {
super.viewDidLoad()
var sprite: UIImage = UIImage(named: "sprites/areaLocatorSprite.png")!
var locations:NSArray = animal[eventData]["locations"] as NSArray
for var i = 0; i < locations.count; i++ {
println(locations[i]["locationx"])
var locationx = locations[i]["locationx"] as String
var locationy = locations[i]["locationy"] as String
let x = NSNumberFormatter().numberFromString(locationx)
let y = NSNumberFormatter().numberFromString(locationy)
let cgfloatx = CGFloat(x!)
let cgfloaty = CGFloat(y!)
var mapSprite: UIImageView
mapSprite = UIImageView(image: sprite)
mapSprite.frame = CGRectMake(cgfloatx,cgfloaty,10,10)
townMap.addSubview(mapSprite)
timer = NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: Selector("flash"), userInfo: nil, repeats: true)
}
}
func flash() {
var mapSprite:UIImageView?
if mapSprite?.alpha == 1 {
mapSprite?.alpha = 0
} else {
mapSprite?.alpha = 1
}
}
This does not work as the mapSprite in the flash function is different to the one in the for loop. How can I refer to the one in the for loop and then animate it? Or would there be a better alternative to what I'm currently doing?
Many thanks!
EDIT
Using Xcode 6.2
You need to store the views into a property and then enumerate that property each time your timer event is fired
var sprites: [UIImageView]?
override func viewDidLoad() {
super.viewDidLoad()
var sprite = UIImage(named: "sprites/areaLocatorSprite.png")!
var locations:NSArray = animal[eventData]["locations"] as NSArray
self.sprites = map(locations) {
var locationx = $0["locationx"] as String
var locationy = $0["locationy"] as String
let x = NSNumberFormatter().numberFromString(locationx)
let y = NSNumberFormatter().numberFromString(locationy)
let cgfloatx = CGFloat(x!)
let cgfloaty = CGFloat(y!)
var mapSprite = UIImageView(image: sprite)
mapSprite.frame = CGRectMake(cgfloatx,cgfloaty,10,10)
townMap.addSubview(mapSprite)
return mapSprite
}
timer = NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: Selector("flash"), userInfo: nil, repeats: true)
}
func flash() {
if let sprites = self.sprites {
for sprite in sprites {
sprite.alpha = sprite.alpha == 0 ? 1 : 0
}
}
}

Execute function on startup

I'm trying to develop an application for IOS using swift language that is a news for me. I want to fill a dictionary (tobaccoList) on the application startup. I have a csv file, so I take data from this file and than i fill the dictionary:
class DataManager{
var latitudes = Array<Double>()
var longitudes = Array<Double>()
var tobaccoList = Dictionary<Double, Tabacchino>()
init(){
if let url = NSURL(fileURLWithPath: "/Users/brunopistone/Developer/apptabacchi/LocationList_sorted.csv" , isDirectory: true) {
var error: NSErrorPointer = nil
if let csv = CSV(contentsOfURL: url, error: error) {
//put every tabbacchino in a Dictionary tobaccoList
let rows = csv.rows
let totalRows = rows.count
for var index = 1; index < totalRows; index++ {
let temp = csv.rows[index]
let tabacchino = Tabacchino(
name: temp["Name"]!, phone: temp["tnumber"]!, lat: NSString(string: temp["Latitude"]!).doubleValue, lon: NSString(string: temp["Longitude"]!).doubleValue
)
let keyGeo = NSString(string: temp["Latitude"]!).doubleValue
storeTobaccoShop(keyGeo, value: tabacchino)
var doubleLatitude = NSString(string: temp["Latitude"]!).doubleValue
var doubleLongitude = NSString(string: temp["Longitude"]!).doubleValue
storeLatitude(doubleLatitude)
storeLongitudes(doubleLongitude)
}
}
}
}
func storeTobaccoShop(key: Double, value: Tabacchino) {
self.tobaccoList[key] = value
}
In the viewController file of the home page i have:
class ViewController: UIViewController, CLLocationManagerDelegate {
let startFunction = DataManager()
let locationManager = CLLocationManager()
var latitude = Double()
var longitude = Double()
var tobaccoList = Dictionary<Double, Tabacchino>()
override func viewDidLoad() {
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
tobaccoList = startFunction.getTobaccoList()
}
In the home page, I have a button that calls another view, and i want to pass the dictionary to the other view in order to use it, so I use this method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "tobaccoListSegue"{
let viewList = segue.destinationViewController as! ViewList
viewList.tabacchini = tobaccoList
}
}
The problem is, when i click on the button in order to call viewList, the application fills again the dictionary. What i want is to fill the dictionary only when I open the application.
Please help me fix this thing. Thanks
Put this line
let startFunction = DataManager()
Inside viewdidload() method.

Resources