Parse LiveQuery not working - ios

I have a Parse server with a LiveQuery.
I can connect to the live query by the log info: Create new client: 1, and websocket.org confirms the connection, however none of the completion blocks are being called.
Here is the full code:
self.pfclient = [[PFLiveQueryClient alloc] init];
PFQuery* query = [PFQuery queryWithClassName:#"Reqs"];
[query whereKey:#"objectId" notEqualTo:#"asdfas"];
self.subscription = [self.pfclient subscribeToQuery:query];
[self.subscription addSubscribeHandler:^(PFQuery * _Nonnull query) {
NSLog(#"Subscribed");
}];
[self.subscription addUpdateHandler:^(PFQuery * _Nonnull query, PFObject * _Nonnull obj) {
NSLog(#"Update");
}];
[self.subscription addErrorHandler:^(PFQuery * _Nonnull query, NSError * _Nonnull error) {
NSLog(#"Error");
}];

Swift 3.0 Code that is working:
let liveQueryClient = ParseLiveQuery.Client(server: "...", applicationId: ..., clientKey: ..)
...
var subscription: Subscription<PFObject>?
let query: PFQuery<PFObject> = PFQuery(className: "className").whereKey("objectId", equalTo: "168sdf8438")
subscription = liveQueryClient.subscribe(query).handle(Event.created) { _, message in
print("Object created")
}

Related

Apple Health initHeartBeatSeries , how to get HKHeartbeatSeriesSample?

Trying to get HeartbeatSeries working but not sure how to get HkHeartbeatSeriesSample. Here's my code
I have this query which is gonna return the data from HeartbeatSeries but I'm not sure how to get the HKHeartbeatSeriesSample
built the query from here
https://developer.apple.com/documentation/healthkit/hkheartbeatseriesquery/3113764-initwithheartbeatseries?language=objc
-(void)fetchHeartSeries:(HKHeartbeatSeriesSample *)sample
timeSinceStart: (NSTimeInterval *)timeSinceStart
completion:(void (^)(NSArray *, NSError *))completionHandler API_AVAILABLE(ios(13.0)){
HKHeartbeatSeriesSample *sampleSeries = sample;
NSTimeInterval *timeSince = timeSinceStart;
if (#available(iOS 13.0, *)) {
HKHeartbeatSeriesQuery *query = [
[HKHeartbeatSeriesQuery alloc]
initWithHeartbeatSeries:(HKHeartbeatSeriesSample *)sampleSeries
dataHandler:^(HKHeartbeatSeriesQuery *query,
NSTimeInterval timeSince,
BOOL precededByGap,
BOOL done,
NSError * error){
if (error) {
// Perform proper error handling here
NSLog(#"*** An error occurred while getting the heart beat series: %# ***", error.localizedDescription);
completionHandler(nil, error);
}
if(done){
NSArray *data = query.accessibilityElements;
NSLog(#"Successfully retrieved heart beat data");
completionHandler(data, nil);
}
}];
[self.healthStore executeQuery:query];
} else {
// Fallback on earlier versions
}
}
This is how I did it. Note, you need to add HKSeriesType.heartbeat() as one of the read types in the requestAuthorization function to have permissions to get the Beat-to-Beat Measurements.
A simple, proof-of-concept to grab the HKHeartbeatSeriesSamples from the last 2 hours and use the first one to get the beat-to-beat measurements and print out the timestamp differences from the start.
I apologize for using Swift here. Let me know and I can provide an Objective-C version.
let last2hours = HKQuery.predicateForSamples(withStart: Date().addingTimeInterval(-60 * 60 * 24), end: Date(), options: [])
let hbSeriesSampleType = HKSeriesType.heartbeat()
let heartbeatSeriesSampleQuery = HKSampleQuery(sampleType: hbSeriesSampleType, predicate: last2hours, limit: 20, sortDescriptors: nil) { (sampleQuery, samples, error) in
if let heartbeatSeriesSample = samples?.first as? HKHeartbeatSeriesSample {
let query = HKHeartbeatSeriesQuery(heartbeatSeries: heartbeatSeriesSample) { (query, timeSinceSeriesStart, precededByGap, done, error) in
print(timeSinceSeriesStart)
}
self.healthStore.execute(query)
}
}
healthStore.execute(heartbeatSeriesSampleQuery)
For this HKHeartbeatSeriesSample:
count=23 F7D641F8-07AD-4543-84C8-126EA7B98B0F "Eric’s Apple Watch" (7.3.3), "Watch6,2" (7.3.3) "Apple Watch" (2021-04-13 17:18:59 -0500 - 2021-04-13 17:19:59 -0500)
Code above prints out to console:
0.78125
1.5390625
2.296875
3.08203125
3.87109375
4.61328125
5.37109375
6.10546875
6.86328125
7.7109375
9.3359375
10.94921875
11.76953125
12.5625
20.05078125
20.84765625
21.625
22.45703125
32.62109375
33.36328125
34.08203125
34.8046875
35.53515625

Not getting data from server with [FIRRemoteConfig remoteConfig]

In the iOS code below, the status of the fetch is FIRRemoteConfigFetchStatusSuccess. When activateFetched is applied in the handler, the result is true. It looks to me therefore as if it should be the case that you can access the remote config values from the server. However, it is only the local value that is obtained when do [FIRRemoteConfig remoteConfig][#"greeting"].stringValue;
On Firebase console have set a parameter called "greeting". What possible reasons are there to explain why it is not retrieving the server value for this parameter?
- (void)fetchFirebaseRemoteConfig {
long expirationDuration = 43200;
if ([FIRRemoteConfig remoteConfig].configSettings.isDeveloperModeEnabled) {
expirationDuration = 0;
}
[[FIRRemoteConfig remoteConfig] fetchWithExpirationDuration:expirationDuration completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
if (status == FIRRemoteConfigFetchStatusSuccess && error == nil) {
BOOL didApply = [[FIRRemoteConfig remoteConfig] activateFetched];
ALog("Did apply remote config OK: %d", didApply);
} else {
ALog(#"Error %#", error.localizedDescription);
}
NSString *greeting = [FIRRemoteConfig remoteConfig][#"greeting"].stringValue;
ALog(#"greeting: %#", greeting);
}];
}

Firestore iOS queryWhereField and queryOrderedByField is not returning specific data

In my iOS project, I'm using Firestore. I'm in need to use queryWhereField and queryOrderedByField, I've implemented as follows but it's not working:
defFirestore = [FIRFirestore firestore];
colRef = [defFirestore collectionWithPath:#"walks"];
[[[colRef queryWhereField:#"requestId" isEqualTo:#(self.requestId)] queryWhereField:#"taskId" isEqualTo:#(self.taskId)] queryOrderedByField:#"createdDate"];
[colRef getDocumentsWithCompletion:^(FIRQuerySnapshot * _Nullable snapshot, NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Error getting documents: %#", error);
} else {
for (FIRDocumentSnapshot *document in snapshot.documents) {
NSLog(#"%# => %#", document.documentID, document.data);
}
}
}];
Above query is not returning where specific record rather returning all records also not ordered by createdDate field. Firestore database screenshot as follows:
Okay, I've already figured that out. First of all need to create an index in Firestore for those fields we want to query from. then need to define a FIRQuery to run the query with those fields. So the query will look like as follows:
FIRQuery *walks = [[[colRef queryWhereField:#"requestId" isEqualTo:#(self.requestId)] queryWhereField:#"taskId" isEqualTo:#(self.taskId)] queryOrderedByField:#"createdDate"];
[walks addSnapshotListener:^(FIRQuerySnapshot *snapshot, NSError *error) {
if (snapshot == nil) {
NSLog(#"Error fetching documents: %#", error);
return;
}
if (error != nil) {
NSLog(#"Error getting documents: %#", error);
} else {
for (FIRDocumentChange *diff in snapshot.documentChanges) {
if (diff.type == FIRDocumentChangeTypeAdded) {
NSLog(#"%# => %#", diff.document.documentID, diff.document.data);
}
}
}
}];
I used snapshot because I want to get realtime update.

Retrieving data in firebase

I am a beginner in firebase and in iOS. I am trying to change a project from parse to firebase.I successfully created and updated the firebase database. But while trying to retrieve data from firebase its just not working for me.
Here's the code I used.
self.ref = [[FIRDatabase database] reference];
NSString *userID = [FIRAuth auth].currentUser.uid;
[[[ref child:#"users"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSLog(#"%#",snapshot.value);
// Get user value
}withCancelBlock:^(NSError * _Nonnull error) {
NSLog(#"%#", error.localizedDescription);
}];
The control just skips the whole block. I can't figure out the problem.
The firebase guide is very hard to understand. Please tell me how to get values to a dictionary from a firebase child.
DatabaseReference database =
FirebaseDatabase.getInstance().getReference();
database.child("notes").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List notes = new ArrayList<>();
for (DataSnapshot noteDataSnapshot : dataSnapshot.getChildren()) {
Note note = noteDataSnapshot.getValue(Note.class);
notes.add(note);
}
adapter.updateList(notes);
}
...
});

Prevent a closure from running until another has completed

Here is code for two closures in two different IBAction button presses. The desired outcome is for the button press to turn on/off an LED, then to access a light sensor and read the light value after the change in LED status.
What happens is a race condition where the function getVariable runs and returns before the callFunction has implemented the change. The result is that the value displayed in getLightLabel.text is that of the prior condition, not the current condition.
My question is how to rewrite the code below so that myPhoton!.getVariable does not execute until after the myPhoton!.callFunction has returned (completed its task).
I have tried placing getVariable inside callFunction, both before and after the } closing if (error == nil), but the result was identical to the code shown here.
#IBAction func lightOn(sender: AnyObject) {
let funcArgs = [1]
myPhoton!.callFunction("lightLed0", withArguments: funcArgs) { (resultCode : NSNumber!, error : NSError!) -> Void in
if (error == nil) {
self.lightStateLabel.text = "LED is on"
}
}
myPhoton!.getVariable("Light", completion: { (result:AnyObject!, error:NSError!) -> Void in
if let e = error {
self.getLightLabel.text = "Failed reading light"
}
else {
if let res = result as? Float {
self.getLightLabel.text = "Light level is \(res) lumens"
}
}
})
}
#IBAction func lightOff(sender: AnyObject) {
let funcArgs = [0]
myPhoton!.callFunction("lightLed0", withArguments: funcArgs) { (resultCode : NSNumber!, error : NSError!) -> Void in
if (error == nil) {
self.lightStateLabel.text = "LED is off"
}
}
myPhoton!.getVariable("Light", completion: { (result:AnyObject!, error:NSError!) -> Void in
if let e = error {
self.getLightLabel.text = "Failed reading light"
}
else {
if let res = result as? Float {
self.getLightLabel.text = "Light level is \(res) lumens"
}
}
})
}
Here is the callFunction comments and code from the .h file. This SDK is written in Objective C. I am using it in Swift with a bridging header file.
/**
* Call a function on the device
*
* #param functionName Function name
* #param args Array of arguments to pass to the function on the device. Arguments will be converted to string maximum length 63 chars.
* #param completion Completion block will be called when function was invoked on device. First argument of block is the integer return value of the function, second is NSError object in case of an error invoking the function
*/
-(void)callFunction:(NSString *)functionName withArguments:(NSArray *)args completion:(void (^)(NSNumber *, NSError *))completion;
/*
-(void)addEventHandler:(NSString *)eventName handler:(void(^)(void))handler;
-(void)removeEventHandler:(NSString *)eventName;
*/
Here is the .m file code
-(void)callFunction:(NSString *)functionName withArguments:(NSArray *)args completion:(void (^)(NSNumber *, NSError *))completion
{
// TODO: check function name exists in list
NSURL *url = [self.baseURL URLByAppendingPathComponent:[NSString stringWithFormat:#"v1/devices/%#/%#", self.id, functionName]];
NSMutableDictionary *params = [NSMutableDictionary new]; //[self defaultParams];
// TODO: check response of calling a non existant function
if (args) {
NSMutableArray *argsStr = [[NSMutableArray alloc] initWithCapacity:args.count];
for (id arg in args)
{
[argsStr addObject:[arg description]];
}
NSString *argsValue = [argsStr componentsJoinedByString:#","];
if (argsValue.length > MAX_SPARK_FUNCTION_ARG_LENGTH)
{
// TODO: arrange user error/codes in a list
NSError *err = [self makeErrorWithDescription:[NSString stringWithFormat:#"Maximum argument length cannot exceed %d",MAX_SPARK_FUNCTION_ARG_LENGTH] code:1000];
if (completion)
completion(nil,err);
return;
}
params[#"args"] = argsValue;
}
[self setAuthHeaderWithAccessToken];
[self.manager POST:[url description] parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completion)
{
NSDictionary *responseDict = responseObject;
if ([responseDict[#"connected"] boolValue]==NO)
{
NSError *err = [self makeErrorWithDescription:#"Device is not connected" code:1001];
completion(nil,err);
}
else
{
// check
NSNumber *result = responseDict[#"return_value"];
completion(result,nil);
}
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
if (completion)
completion(nil,error);
}];
}
One solution is to put the second closure inside the first, where the first returns and provides and Error value. If no error,then execuet the second closure. That is one way to tightly couple the two closures without resorting to semaphores or other messaging schemes.
In this application, the problem I was encountering cannot be solved on the IOS/Swift side of the stack. The cloud API and embedded uP are not tightly coupled, so the cloud returns to the IOS with a completion before the full function code has run on the Particle uP.
The solution to this overall problem actually lies in either modifying the cloud API or adding some additional code to the uP firmware to tightly couple the process to the IOS app with additional communication.

Resources