Failure to save data to HealthKit (Cocoa error 4097) - ios

I'm currently having difficulty saving data to health kit and I'm unsure what the problem is. I have health kit enabled and have granted read and write permissions on my testing device when the app runs (everything looks OK and I'm able to query the health kit database without error). I'm using Swift.
The code I'm using to save is:
hksaver.healthStore!.saveObjects(samples, withCompletion: {
(success: Bool , error: NSError!) -> Void in
if success { ... } else {
println("Failed to save. Error: \(error)")
}
samples is an array of HKQuantity Samples. It is created by appending 'dataSample' as defined below:
let dataPoint = HKQuantity(unit: units, doubleValue: measurement.dataPoint)
let dataSample = HKQuantitySample(type: quantityType,
quantity: dataPoint, startDate: measurement.startDate,
endDate: measurement.endDate, metadata: metadata)
There are no errors when constructing this, so I believe that all the values are appropriate.
When I run, I'm getting the following error:
Failed to save. Error: Error Domain=NSCocoaErrorDomain Code=4097 "The
operation couldn’t be completed. (Cocoa error 4097.)" (connection to
service named com.apple.healthd.server) UserInfo=0x17047a0c0
{NSDebugDescription=connection to service named
com.apple.healthd.server}
I'm trying to write ~100,000 values to HealthKit though I haven't been able to find any limits (the same error occurred when I was trying to write ~50,000 values). I've tried to write this in chunks, but after around 5 calls to health kit it starts failing (I'm assuming there is a limit to prevent continuous calls although I haven't seen anything in any documentation I've looked at).
I've tried searching under the error code, under the entire error, and under everything I could think of to explain the problem. The only results I've returned deal with HomeKit and tend to be that it is not activated. However under the capabilities tab I have HealthKit turned on and everything is check marked so I don't think that is the problem.
Any thoughts would be appreciated!

Related

How does transactions in firestore error out?

I'm trying to produce an error in transaction and my question is when does transaction produces error ? I tried inserting random non existent collection and document, go offline, still it doesn't catch any error.
In what conditions does transaction error out ?
var db = Firestore.firestore()
let ref = db.collection("foo").document("bar")
db.runTransaction({ transaction, errorPointer -> Any? in
var document: DocumentSnapshot
do {
try document = transaction.getDocument(ref)
} catch let fetchError as NSError {
// no Error here even if ref doesn't exist or I go offline
errorPointer?.pointee = fetchError
return nil
}
return nil
}) { _, error in
if let error = error {
print("Transcation Completion Error: \(error)")
} else {
print("Transaction Succeeded!")
}
}
If you just want to test error handling then just throw your own error from within the transaction. The transaction closure has two arguments, the transaction object and an error pointer. Assign the error pointer an NSError and handle it in the completion block.
errorPointer?.pointee = NSError(domain: "yourDomain", code: 0, userInfo: nil)
Beyond this, a transaction could fail for a number of reasons, such as performing a read operation after a write operation, a network error, exceeding the allotted data-usage limit, or too many failed attempts at retrying the transaction (because the underlying documents were modified outside the transaction). Further reading at link below.
https://firebase.google.com/docs/firestore/manage-data/transactions#transaction_failure
According to Firebase documentation, a transaction can fail following the next options:
After the write operations, the transaction contains read operations.
Before any write operations, read operations must always occur first.
The transaction read a document that had been changed outside of it.
In this instance, the transaction is restarted automatically. A
certain number of times the transaction is retried.
The transaction's request size exceeds the 10 MiB limit.
The size of a transaction is determined by the size of the documents
and index items that it modifies. This contains the size of the
target document and the sizes of the index items eliminated due to
the operation.
When a transaction fails, it generates an error and does not write any data to the database. You don't have to roll back the transaction because Cloud Firestore does it for you.
Also, I would like to suggest you to check the NSError for Swift, here is a Github Repository that provides information of NSError, as well as this documentation that also describes the NSError of how to handle failed transactions and give appropriate error messages to the user as a feedback.

Error: "connection to service named com.apple.MapKit.SnapshotService" when starting MKMapSnapshotter

I try to create a snapshot of my map view to display later so I don't have another map view wasting memory.
Most of the time it works just fine, but recently I tried creating a snapshot of Paris and got the Error: "connection to service named com.apple.MapKit.SnapshotService".
I know it looks like a cut a part but no, it seems this is the whole error description.
Full Error:
Error Domain=MKErrorDomain Code=1 "(null)" UserInfo=. {NSUnderlyingError=0x284562610 {Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.MapKit.SnapshotService" UserInfo={NSDebugDescription=connection to service named com.apple.MapKit.SnapshotService}}}
I've tried multiple times, but it seems when taking a snapshot of Paris it just won't ever work out as it does for other cities. I've really got no clue where I could start solving the problem as I didn't find any information on the origin of my error.
EDIT: The behaviour actually does appear seemingly random in other cities too.
In viewDidLoad I initialize my options object like so:
snapShotOptions.size = mapView.frame.size
snapShotOptions.scale = UIScreen.main.scale
snapShotOptions.showsBuildings = false
When the user now decides to go on, I initialize & start the snapshotter and handle data accordingly, before that I also set the region for the snapshot:
snapShotOptions.region = mapView.region
snapShotter = MKMapSnapshotter(options: snapShotOptions)
// Take a snapshot.
snapShotter.start { (snapshot, error) -> Void in
if error == nil {
completionHandler(snapshot?.image ?? UIImage())
} else {
print(error!)
}
}
I hope someone can help me out here or at least give me a clue as to what the error actually means!
Recently, I encountered the same phenomenon.
In my case, it happens when I take a snapshot in a situation where a memory warning is occurring.
If this issue has already been resolved, I would be grateful if you could provide information.

Firestore document creation fails without an error

Edit3: Okay, it seems like it's an issue with Firebase, someone else tweeted about having the same issue. I also contacted support.
A piece of Swift code that handles creating documents suddenly stopped working. No errors are thrown, Firebase doesn't complain in the log and I can verify from the console that the document is not created, I can verify that the device has a healthy internet connection. I also disabled offline persistence for Firebase just to be sure.
When I try debugging it, the debugger jumps straight over the block that handles errors or successes, never running it (i.e. never finishing the Firestore request?).
Here is the code
func createConversation(){
let conversation : [String : Any] = ["owners" : [
UserProfile().getProfile().uid!],
"seeking" : true,
"timestamp" : Timestamp(date: Date())
]
var ref: DocumentReference? = nil
ref = DB().firestore().collection("Conversations").addDocument(data: conversation){ err in
if let err = err {
print("Error creating a convo: \(err)")
} else {
print("Conversation created with ID: \(ref!.documentID)")
StateMachine().action(a: .seekingStarted(ref!.documentID))
}
print("Conversation Creation finished")
}
let documentID = ref?.documentID
print(ref.debugDescription)
}
I'm not sure how to approach this issue, any ideas?
Edit: Okay, the issue is not limited to this block of code, it looks like Firebase is not communicating with the servers. I've waited for more than 5min for the addDocument to return(with error or success) but that never happened.
I noticed that at the initiation of the App BoringSSL complains a bit but this is not new and I don't have problems with the other Firebase services, they work just fine - reading and creating data with no problems.
Edit2: Apparently I can fetch collections and documents from Firestore, the issue seems to be limited to document/collection creation.
The document creation operation takes a little time, if you place the breakpoint inside the asynchronus completion block you will surely get an error or success.

Apple iOS ARKit: "A sensor failed to deliver the required input" error and stops working

I am developing an application that uses both ARKit and hardware video decoder. As soon as the decoder start to decode, the following error message appears in console and prevent tracking from working properly.
Occasionally, this error do not show up and the app works normally. After some debugging, I found out this error only happens at the "beginning" (shortly after launching the app). Once it passes that point, it works fine for the rest of the time.
Does anyone know what the problem is or how to go around it?
2017-08-11 20:48:02.550228-0700 PortalMetal[4037:893878] [] <<<<
AVCaptureSession >>>> -[AVCaptureSession
_handleServerConnectionDiedNotification]: (0x1c0007eb0)(pthread:0x170387000) ServerConnectionDied 2017-08-11
20:48:02.564053-0700 PortalMetal[4037:893747] [Session] Session did
fail with error: Error Domain=com.apple.arkit.error Code=102 "Required
sensor failed." UserInfo={NSLocalizedFailureReason=A sensor failed to
deliver the required input., NSUnderlyingError=0x1c4c51280 {Error
Domain=AVFoundationErrorDomain Code=-11819 "Cannot Complete Action"
UserInfo={NSLocalizedDescription=Cannot Complete Action,
NSLocalizedRecoverySuggestion=Try again later.}},
NSLocalizedRecoverySuggestion=Make sure that the application has the
required privacy settings., NSLocalizedDescription=Required sensor
failed.}
Update
The solution is to do with compass calibration being set in the phone settings. Credit to this answer.
Go to Settings > Privacy > Location Services > System Services, and set Compass Calibration to ON.
How to prevent Crashing
Declare your config at the top of your class e.g:
var configuration = ARWorldTrackingConfiguration() and make sure you setup and add your config in the viewWillAppear method.
Then add this method to handle the error.
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
print("Session failed. Changing worldAlignment property.")
print(error.localizedDescription)
if let arError = error as? ARError {
switch arError.errorCode {
case 102:
configuration.worldAlignment = .gravity
restartSessionWithoutDelete()
default:
restartSessionWithoutDelete()
}
}
}
It just handles the error that you've noticed.
Next, add this function to reset the session with a new config worldAlignment:
func restartSessionWithoutDelete() {
// Restart session with a different worldAlignment - prevents bug from crashing app
self.sceneView.session.pause()
self.sceneView.session.run(configuration, options: [
.resetTracking,
.removeExistingAnchors])
}
Hope it helps, and I also hope to find an actual fix to this apparent bug.
Setting worldAlignment to gravityAndHeading needs the location service to be enabled:
check if your device has location service turned on.
Check if Info.plist has set Privacy - Photo Library Additions Usage Description
If the compass orientation is crucial for your app, you should consider to guide the user to do turn the location service on and implement a fallback.

AVAssetWriter::append() returns false with no extra info (How to do segmenting of captured input to video-chunks with AVFoundation?)

I am building a feature where I record video and audio using AVFoundation. I will record for hours, but I want to upload chunks to our backend so that we can build a live HLS-playlist (after som processing of the segments).
First of all, is there a sample somewhere doing this? I haven't found any reference implementations so to say...
Here is my take on it:
It's pretty straight-forward to setup a AVCaptureSession following the docs and examples on the web.
I implement AVCaptureVideoDataOutputSampleBufferDelegate and AVCaptureAudioDataOutputSampleBufferDelegate to get access to the sample buffers
I have two AVAssetWriters and switch between, one with mediaType == AVMediaTypeVideo and one with mediaType == AVMediaTypeAudio.
Using CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer) I switch between the writers after typically 5 seconds.
Problems:
Sometimes, the when calling AVAssetWriter::append(), it just fails
and returns false
According to the documentation, one shall check AVAssetWriter.status.
In this situation it is set to AVAssetWriterStatusFailed and more information should be available in AVAssetWriter.error
AVAssetWriter.error is set to
Optional(Error Domain=AVFoundationErrorDomain Code=-11800 \"The operation could not be completed\" UserInfo={NSUnderlyingError=0x14e73dc10 {Error Domain=NSOSStatusErrorDomain Code=-16364 \"(null)\"},NSLocalizedFailureReason=An unknown error occurred (-16364), NSLocalizedDescription=The operation could not be completed})
AVFoundationErrorDomain.code 11800 means AVErrorUnknown
Anyone that has had the same problems or knows how to find more info?
Finally, when I switch between writers, there is a period from when I call AVAssetWriter.startWriting() (I do this when I create my idle writer, before it its time to switch to a new segment) to when I have called AVAssetWriter.startSession(atSourceTime: startTime). During this time I need to hold on to sampleBuffers (typically audio). I just make a copy
var copiedBuffer: CMSampleBuffer?
CMSampleBufferCreateCopy(nil, sampleBuffer, &copiedBuffer)
guard copiedBuffer != nil else {
throw VideoWriterError.failedToCopyBuffer
}
pendingSampleBuffers.append((isVideo, copiedBuffer))
After AVAssetWriter.StartSession(), I write them to the new writer:
while !pendingSampleBuffers.isEmpty {
let (isVideo, sampleBufferOpt) = pendingSampleBuffers.removeFirst()
guard let sampleBuffer = sampleBufferOpt else {
throw VideoWriterError.failedToCopyBuffer
}
try capturedFrame(sampleBuffer: sampleBuffer, isVideo: isVideo)
}
Seems to work, but there is a lot of posts about copying is shallow. I wonder if that can be related to my problems? Sample buffers exist in some kind of pool?
If false is returned, clients can check the value of the AVAssetWriter
status property to determine whether the writing operation completed,
failed, or was cancelled. If the status is failed, The AVAssetWriter
error property will contain an instance of NSErrorß that describes the
failure.
From append(_:).
I hope this helps. Please do comment for improvements.

Resources