When I setup an HKObserverQuery, the update handler always gets immediately called (something I didn't expect). It also gets called when I add data points through Health.app, as you would expect. I am tending to think I am not doing something right with the completion handler, but the docs are fairly sparse on what is supposed to happen here.
Question: Below is basically what I'm doing. Is this expected behavior, or am I missing something?
func listenForUpdates() {
let bodyMassType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)
let updateHandler: (HKObserverQuery!, HKObserverQueryCompletionHandler!, NSError!) -> Void = { query, completion, error in
if !error {
println("got an update")
// ... perform a sample query to get the actual data
completion() // is this the right thing to do?
} else {
println("observer query returned error: \(error)")
}
}
let query = HKObserverQuery(sampleType: bodyMassType, predicate: nil, updateHandler: updateHandler)
healthStore?.executeQuery(query)
}
Edit: discovered completion handler should only be called when there wasn't an error, so moved into the !error block. An error is present when the app is not authorized.
Yes, this is expected behavior. The update handler will always be called on first execution so that you can use it to fetch your initial data (from your sample query, anchored object query, etc) and populate your UI.
The completion handler is only necessary if you intend to use background delivery, it informs HealthKit that you have received and processed the data you need so that HealthKit knows to stop launching your app in the background. If you have not registered your app for background delivery, then the completion handler is essentially a no-op and you don't need to worry about it.
Related
Using LiveData to signal a fragment to update it's display based on work done off of the main thread can be done by the postValue() function instead of setValue() but it has the problem that every posted value may not be observed on the main thread in the fragment.
A simple way to solve the problem is set the value from the worker running on Dispatchers.IO using withContext. Below is simple extension function that decides if this is needed using #OptIn(ExperimentalStdlibApi::class), which suggests this is a bad idea:
companion object {
#OptIn(ExperimentalStdlibApi::class)
suspend fun WorkingDepth.resetDepthOnMain() {
if (currentCoroutineContext()[CoroutineDispatcher].toString() == "Dispatchers.Main") {
resetDepth()
} else {
coroutineScope {
withContext(Dispatchers.Main) {
// This is the technique to ensure that the main thread sees
// the notification. If done off the main thread via a post
// it is not guaranteed that the observer will get the notification.
resetDepth()
}
}
}
}
}
The "opt in" annotation is avoided by treating all dispatchers as not Dispatchers.Main. Probably the unnecessary overhead is inconsequential, but the nagging question remains why is it not built in to "set on main" instead of "post and hope off of main".
Setting off of main throws an exception, so another way is the catch the exception and then switch threads and try again.
In a simple example where the live data is supposed to show landmarks along a work path it was seen that some expected landmarks do not get shown with "post and hope".
The withContext() method already includes the optimization suggested in the question.
This is explained in the comment for the fast paths in the coroutine library:
// FAST PATH #1 -- new context is the same as the old one
...
// FAST PATH #2 -- the new dispatcher is the same as the old one (something else changed)
...
Bottom line: If you must ensure execution on Main just wrap in a withContext(Dispatchers.Main) block.
I'm writing a custom controller for Kubernetes in Go with the help of client-go.
It is based on the sample-controller and working great so far.
The SharedIndexInformer has the option to periodically resync all objects. (Parameter resyncPeriod is set to 30 seconds in the sample-controller.)
Is there a way to force a resync immediately?
The code which seems to handle the periodic resync seems to call store.Resync().
I've tried calling fooInformer.Informer().GetStore().Resync(). The call succeeds, but the resync is not happening. What did I miss?
I'm using client-go v0.17.2 and the server is EKS v1.14.9-eks-c0eccc.
This is not possible.
The cache.Store that does the periodic resync is instantiated in newInformer in k8s.io/client-go/tools/cache/controller.go as a cache.DeltaFIFO queue:
// This will hold incoming changes. Note how we pass clientState in as a
// KeyLister, that way resync operations will result in the correct set
// of update/delete deltas.
fifo := NewDeltaFIFOWithOptions(DeltaFIFOOptions{
KnownObjects: clientState,
EmitDeltaTypeReplaced: true,
})
This is returned by cache.New() as an unexported field cache.controller{}.config.Queue, which there is no exported function for accessing- so no way to manually call Resync().
Upon calling fooInformer.Informer().GetStore().Resync() you are using Resync function/method of the Store type defined in: client-go/tools/cache/store.go
And there we can see the following:
In the Store type definition:
// Resync is meaningless in the terms appearing here but has
// meaning in some implementations that have non-trivial
// additional behavior (e.g., DeltaFIFO).
Resync() error
And in the Resync definition further below:
// Resync is meaningless for one of these
func (c *cache) Resync() error {
return nil
}
Unless you actually have some other class to do the Resync, this is supposed to really do nothing.
That is why
The call succeeds, but the resync is not happening.
Hope that helps!
You can achieve this by listing every object from the informer store, then calling ResourceEventHandlerFuncs's AddFunc (usually xxxController.OnAddXxx).
for _, v := range xxxController.xxxInformer.GetStore().List() {
xxxController.OnAddXxx(v)
}
Or, if you'd like to hack, you can use reflect
field := reflect.ValueOf(xxxController.xxxInformer).Elem().FieldByName("controller").Elem().Elem().FieldByName("reflector").Elem().FieldByName("store")
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface().(*cache.DeltaFIFO).Resync()
I'm actually on swift 2.3.
Inbound Call works great with CallKit. But OutGoing Call ....
I saw the SpeakerBox project, I do the same things.
But it doesn't work.
To start my call, I used
let handle = CXHandle(type: .PhoneNumber, value: "TOTO")
let startCallAction = CXStartCallAction(callUUID: uuid, handle: handle)
startCallAction.video = video
let transaction = CXTransaction()
transaction.addAction(startCallAction)
requestTransaction(transaction)
After, in SpeakerBox Project, this function is called :
func provider(provider: CXProvider, perform action: CXStartCallAction)
But not in my project. Then, when i hangup, i see : "Call failed".
Do you have an idea ?
Be sure you are configuring your CXProvider and setting its delegate properly. If you do not set the CXProvider's delegate property, the delegate will not receive any actions to perform.
Also, if you see a "Call Failed" UI, this may indicate your app is crashing. I'd check for crash logs or run the app in the debugger.
As far as I can see, SpeakerBox demo does not perform the following provider method:
https://developer.apple.com/documentation/callkit/cxprovider/1930701-reportcall
func reportCall(with UUID: UUID,
endedAt dateEnded: Date?,
reason endedReason: CXCallEndedReason)
- (void)reportCallWithUUID:(NSUUID *)UUID endedAtDate:(nullable NSDate
*)dateEnded reason:(CXCallEndedReason)endedReason;
Which leads to the "Call failed" UI screen being displayed - as CallKit was not given a reason why the call has ended, and it seems that "
CXCallEndedReasonFailed" is assumed by default.
Call "reportCall endedAt" before requesting the CXEndCallAction transaction to remove "Call failed" screen.
Have you added the required permissions to your info.plist?
I'm trying to get some data from Application.Current.Properties storage. Unfortunately, any time I want to use this Dictionary, I see this error:
An exception of type 'System.AggregateException' occurred in mscorlib.ni.dll but was not handled in user code
Additional information: One or more errors occurred.
And in details I found this:
{"Error in line 1 position 206. Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data of the 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfstring' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'ArrayOfstring' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer."}
It seems like I tried to save some non-string data to Application.Current.Properties. Unfortunately I can't run .Clear() method to erease all data, bacause I receive this error any time I'm trying to access this property.
What should I do to make it work?
Well, as its name suggests AggregateException, is just a container for one or more exceptions which may be thrown when using PLINQ or TPL.
As such exceptions may be thrown on different threads and may also occur concurrently, the system automatically catches and rethrows them within an AggregateException wrapper to ensure that they all get reported in one place. The exceptions themselves are exposed via the InnerExceptions property.
You can catch an AggregateException and check which exceptions it actually contains with code such as the following:
try
{
// perform some parallel operation
}
catch (AggregateException aex)
{
string messages = "";
foreach(Exception ex in aex.InnerExceptions)
{
messages += ex.Message + "\r\n";
}
MessageBox.Show(messages);
}
So I suggest you do this to see what is causing the problem
Please, remove your app from your device, Settings - Applications- Uninstall, this works for me. The Auth Object was crash in debug mode.Clean and Rebuild can be Helpfull to.
This question already has answers here:
Am I right to ignore the compiler warning for lacking await for this async call?
(3 answers)
Closed 7 years ago.
Below is my code. Compiler gives warning because AddLog is not awaited. I do not want to await this call and want to continue executing next lines. I dont have any concern if the exception is consumed also. Is it fine to ignore the warning?
public async Task Add()
{
this.AddLog( "Add executing" );
// Logic to Add Customer
}
public async Task AddLog( string message )
{
// Write to DB
}
Assuming you truly want to call the AddLog method in a fire-and-forget way, then you have a few options.
If, by design, you want AddLog to always be invoked as a fire-and-forget method, then you could change the signature to not return a Task.
public async void AddLog( string message ) // change Task to void
{
// Write to DB
// WARNING: Make sure that exceptions are handled in here.
}
However, if you do this, you better make sure that exceptions are properly handled from within the AddLog method. If any exception goes unhandled, it will crash your process.
Another option is to change the way you invoke AddLog to clearly state your intent that you don't care about when the Task completes, or about any exceptions that may be raised. You can do this by defining an empty continuation (Well, almost empty. See my edit at the bottom of the post for why it's a good idea to read the Task.Exception property at the very least).
// see EDIT for why the Task.Exception property is read here.
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
With either option, unless you are awaiting on other code inside your Add method that you are not showing us, then there is no longer any point in defining your Add method as async. You can simply turn it into a regular synchronous method. Otherwise, you'll then get another warning telling you that This async method lacks 'await' operators and will run synchronously....
public void Add() // no need for "async Task"
{
// see EDIT for why the Task.Exception property is read here.
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
// Logic to Add Customer
}
In any case, I wouldn't simply ignore the warning. Much like sometimes we get the warning Use of unassigned local variable 'x' in cases where we know that our code is fine, we typically don't ignore the warning. Instead, we may explicitly initialize the variable to null just to make our intent clear, and make the warning go away. Similarly, you can make the warning go away by making your intentions more explicit to the compiler using one of the above options.
EDIT: Word of caution about unobserved exceptions
I should also mention that even with the ContinueWith option, you may have to be careful about unhandled exceptions that come from your AddLog method.
According to this article, the way unobserved exceptions from tasks are handled has changed between .NET 4.0 and .NET 4.5. So, if you are still running .NET 4.0, or if you forcing .NET 4.0 exception behavior via configuration, you run the risk that unhandled exceptions will crash your process whenever the task gets GC-collected and finalized.
To make sure that this is not a problem, you can adjust the continuation to explicitly observe the exception, if any is present. You don't actually need to do anything with it, you just need to read it. This is one way to do it safely:
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
I've updated my earlier examples above to use the safer version of the continuation.
I would make add() non async since it isn't...and then task.run on add log