I'm making an app to track your sleep by getting any movement of the iPhone. I searched everywhere and there are many ways you can get data from this but non worked. Here's my code.
func startManager() {
let manager = CMMotionManager()
manager.startAccelerometerUpdates()
let accelerometer = manager.accelerometerData
}
But manager.accelerometerData is nil. I also tried it with DeviceMotion, Gyro and UserAcceleration, non of them worked. I also tried this.
print(manager.isAccelerometerActive)
It printed false so I think this is the problem but I still cannot make it active.
I tried putting the let manager = CMMotionManager() to the top and it still won't work.
I tried putting manager.startAccelerometerUpdates() in the ViewDidLoad and still doesn't work.
I also tried another way which is this.
manager.startAccelerometerUpdates(to: OperationQueue.main) { (data : CMAccelerometerData, error : Error) in
print(data)
}
but it gave me an error saying that I have to add as! CMAccelerometerHandler but after I added that it tell me to add it again.
I want to get raw value from the Accelerometer as x, y and z
(I imported CoreMotion)
I'm doing this using Swift 3 on XCode 8.2.1 and testing it on iPhone 6s.
In Swift3, you should use optional parameters in the handler
motionManager.startAccelerometerUpdates(
to: OperationQueue.main ,
withHandler:{ (data : CMAccelerometerData?, error : Error?) in
print(data)
})
Related
I'm beginner in Swift. I have made a document picker at my task. But I see the documentation it was deprecated to used open var documentPickerMode: UIDocumentPickerMode { get }. While the project in my task runs with minimum deployment of IOS13.
Is there a solution for this feature that can be used on IOS14 and below? Or is this normal, where users need to update IOS?. Forgive me for my ignorance, as I'm new to swift world.
If you look at the docs:
https://developer.apple.com/documentation/uikit/uidocumentpickerviewcontroller
...you'll see the list of four initializers introduced in iOS 14. Each one configures the picker for one specific type of task. There is no need for a "mode" because you cannot not know how your picker is configured, because you configured it. That is the modern architecture.
At the bottom of the same page you will see the three deprecated initializers from iOS 13 and before, each of which takes a "mode" as a parameter. That is what you must use if you insist upon supporting iOS 13, even though they are deprecated in later systems. And that's fine. "Deprecated" means discouraged and superseded; it does not mean illegal. What you're getting is just a warning, not (as your title wrongly stated) an error.
just try this one code
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
guard url.startAccessingSecurityScopedResource() else {
return
}
defer { url.stopAccessingSecurityScopedResource() }
var error: NSError? = nil
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { (url) in
let _ : [URLResourceKey] = [.nameKey, .isDirectoryKey]
let documentFileData = NSData(contentsOf: (url)) as Data?
pickImageCallback?(nil, url.lastPathComponent, documentFileData)
}
}
I'm new to Swift and OS X programming. I'm trying to use a progress monitor to indicate the progress of my speech synthesizer speaking text.
let speechSynthesizer = NSSpeechSynthesizer()
speechSynthesizer.delegate = self;
speechSynthesizer.startSpeakingString(contents)
I would like to set
progressIndicator.maxValue = Double(NSSpeechStatusNumberOfCharactersLeft.characters.count)
and then periodically update the progressIndicator with NSSpeechStatusNumberOfCharactersLeft, which according to Apple's documentation should hit 0.
Every way I try to access this key, it returns the same inaccurate number, so I'm obviously not using it correctly. The only example I found was in Objective-C
NSNumber *n = [[self.speechSynth objectForProperty:NSSpeechStatusProperty error:NULL] objectForKey:NSSpeechStatusNumberOfCharactersLeft];
and I tried to translate that to Swift, but still, no dice.
let count = try speechSynthesizer.objectForProperty(NSSpeechStatusProperty).objectForKey(NSSpeechStatusNumberOfCharactersLeft)
I've also tried
speechSynthesizer.valueForKey(NSSpeechStatusNumberOfCharactersLeft))
speechSynthesizer.valueWithName(NSSpeechStatusNumberOfCharactersLeft, inPropertyWithKey: NSSpeechStatusProperty))
which throw runtime exceptions. Any thoughts? Thanks in advance!
Your second attempt is pretty close to correct:
let count = try speechSynthesizer.objectForProperty(NSSpeechStatusProperty).objectForKey(NSSpeechStatusNumberOfCharactersLeft)
Without an error message (and since I don't have a Swift 2 compiler handy) I'm guessing the reason that this fails is that the return value of objectForProperty isn't known to be an dictionary, so you can't look up values in it.
Here's my quick & dirty Swift 3 playground for testing this:
import PlaygroundSupport
import Cocoa
let synth = NSSpeechSynthesizer()
synth.startSpeaking("I'm not standing still, I am lying in wait")
// quick way to test for progress without setting up an app and delegate
PlaygroundPage.current.needsIndefiniteExecution = true
let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
let statusDict = try! synth.object(forProperty: NSSpeechStatusProperty) as! [String: Any]
print(statusDict[NSSpeechStatusNumberOfCharactersLeft])
}
(Obviously, you don't need all the timer stuff or playground business if you're running this in an app with a synthesizer delegate.)
The key bit (no pun intended) is to cast the return value of objectForProperty so that Swift knows it's a dictionary, then look up the number of characters in that dictionary.
Now, this code runs correctly, but it doesn't completely work for setting a progress bar — when the synthesizer finishes speaking, NSSpeechStatusNumberOfCharactersLeft is likely to be some nonzero value. (In that case, another status key, NSSpeechStatusOutputBusy will become false.) So your progress bar will get to not quite 100%, and you can use either the NSSpeechStatusOutputBusy key or the delegate didFinishSpeaking callback to take your bar the rest of the way, remove your progress UI, or whatever.
I've got a simple class that uses an NSURLSession.
class test {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration());
func f() {
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0), { () -> Void in
var task = self.session.dataTaskWithRequest(request, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
if error != nil {
// cry
return;
}
var error: NSError? = nil;
var dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &error) as! Dictionary<String, String>;
// use dict
});
task.resume();
});
}
When I try to deserialize the data as JSON, the application crashes.
I've determined that the data seems to be of the right length but the content looks like garbage in the debugger, so it seems to me that the data object passed in is broken. Furthermore, I suspect some stack smashing as I can step through this completion handler and see that it's the attempt to deserialize the data that's crashing, but when the actual crash occurs, the stack in the debugger mentions nothing about the completion handler or any of my code.
I've seen several samples of using NSURLSession that look pretty much exactly like mine that just work. I tried using the shared session instead of making a new one, but that did not help either.
What is causing this crash?
Seems that the JSON was not actually all strings- I brainfarted and one of them was actually a number.
The real problem in the question is that Swift is completely worthless when handling the problem of force casts failing. Not only do you not get any kind of useful error at runtime that you could handle or recover from, but the debugging information presented when it occurs is completely misleading and points to totally the wrong place. You simply get a trap in a function without symbols with the wrong callstack.
Trying to follow along and code the Smashtag project while watching the Lecture 10 iTunes video.
When I add the dowloaded Twitter package to my Smashtag project, XCode couldn't find the Tweet class when I made reference to it in the TweetTableViewController.
Because of the problem described above, I added the four classes belonging to the Twitter package individually to the project. XCode found the four classes but adding them in this manner generated 11 compile errors.
I'm using XCode Version 6.3 (6D570) which is subsequent to the iOS 8.3 release.
Has anyone else encountered this issue?
Thank you for reading my question.
~ Lee
Possibly not the most-correct (read: best practice) way to do this, but I'm going to chalk it up to doing what it takes to finish the course.
I just went through the list of compile errors and changed the relevant properties to var instead of let. Constants can't be changed and in the new version of Swift they can only be instantiated once. So for the sake of not rewriting too much code, I chose to make certain properties vars instead of lets.
Other bugs I found following the iTunes U course:
The named ‘handler:’ argument needs the name explicitly in a few places.
The simulator will show "TwitterRequest: Couldn\'t discover Twitter account type.” until you go to Settings (inside the simulator) and set the Twitter account. At this point I had to reboot the device, as the call is made in the ViewDidLoad, and thus is only called the first time the view loads. (Alternatively, you could close out the app from the app switcher in the simulator and relaunch that way.)
Here is a gist with corrected code that you can use as a Twitter package that will work with the course and has fixes for the aforementioned bugs, minus the Twitter account setting:
https://gist.github.com/mattpetters/ccf87678ccce0c354398
As Christian R. Jimenez said, "I went to Settings in the Simulated iphone and add my Twitter Account. And everything works perfect." in http://cs193p.m2m.at/cs193p-lecture-10-table-view-winter-2015/. I just added my Twitter Account and tested it, it works!
I had similar problems with the Twitter packages using Swift 2.0 and Xcode 7.2
I'm very new to Swift, so there is a good chance the changes I made are not best practices, but the updated files do work: https://gist.github.com/awaxman11/9c48c0b4c622bffb879f.
For the most part I used Xcode's suggested changes. The two larger changes I made were:
In Tweet.swift I updated the the IndexedKeyword struct's init method to use advanceBy() instead of advance()
In TwitterRequest.swift I updated the signature of NSJSONSerialization to conform to the new error handling system
I've just had a big session fixing the Twitter package files for this same version of Xcode.
It seems that what has broken is that in this version of Swift, constants ('let x...') may only be initialized once, so if a constant is given a value in the declaration ('let x = false'), it may not be changed in the init() function. The Twitter package gives some constants initial values, but then changes the values in the init() function.
My solution to this was to follow the styles suggested in the current version of the Apple Swift language book: declare (many of) the constants as implicitly unwrapped optionals, unconditionally assign a value to them in the init() function (which value may be nil), then test whether any of them are nil, and, if so, return nil from init().
See https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html, click "On This Page" and choose "Failable Initializers"
Also, in TwitterRequest.swift, I needed to add the parameter name 'handler:' in a couple of calls to performTwitterRequest(request, handler: handler).
As an example of constant initialization, in MediaItem.swift:
<< Original Code >>
...
public let aspectRatio: Double = 0
...
init?(data: NSDictionary?) {
var valid = false
if let urlString = data?.valueForKeyPath(TwitterKey.MediaURL) as? NSString {
if let url = NSURL(string: urlString) {
self.url = url
let h = data?.valueForKeyPath(TwitterKey.Height) as? NSNumber
let w = data?.valueForKeyPath(TwitterKey.Width) as? NSNumber
if h != nil && w != nil && h?.doubleValue != 0 {
aspectRatio = w!.doubleValue / h!.doubleValue
valid = true
}
}
}
if !valid {
return nil
}
}
...
<< Updated code >>
...
public let aspectRatio: Double
...
init?(data: NSDictionary?) {
if let urlString = data?.valueForKeyPath(TwitterKey.MediaURL) as? NSString {
if let url = NSURL(string: urlString as String) {
self.url = url
let h = data?.valueForKeyPath(TwitterKey.Height) as? NSNumber
let w = data?.valueForKeyPath(TwitterKey.Width) as? NSNumber
if h != nil && w != nil && h?.doubleValue != 0 {
aspectRatio = w!.doubleValue / h!.doubleValue
return
}
}
}
return nil
}
...
This produces "fatal error: Can't unwrap Optional.None" and I don't seem to get why
var motionManager = CMMotionManager()
motionManager.accelerometerUpdateInterval = 0.2
motionManager.startAccelerometerUpdates()
var accelerationData = motionManager.accelerometerData
var accel = accelerationData.acceleration.x
If anyone can help me out, that would be great.
The issue is accelerationData is nil and you aren't checking for this. From the docs:
If no accelerometer data is available, the value of this property is nil.
You should check to make sure there is actually data before calling methods on it like this
if let accelerationData = motionManager.accelerometerData {
var accel = accelerationData.acceleration.x
}
That will ensure that if there is no data your app won't crash. Now to make sure you get some data.
You aren't getting any data because you're asking for data immediately after you initialize the core motion manager. You can show this by waiting a few seconds before checking. You can add NSThread.sleepForTimeInterval(3) right above the if let and run the project and it will enter the if let. Make sure you are using an actual device though, the simulator won't generate any motion data.