QBChatDelegate -chatDidReceiveMessage: getting called but dialogID is NULL - ios

I'm utilising QB for awhile now and everything was working perfectly.
Something came up today and I'm not being able to receive QBChatMessages with a proper dialogID anymore.
I send the message with:
[self.dialog sendMessage:message completionBlock:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"error! %#", error);
} else {
NSLog(#"success!");
/*locally adding message to tableview*/
}
}
And the callback always results a success, the other end receives the message through:
- (void)chatDidReceiveMessage:(QBChatMessage *)message
{
NSLog(#"chatDidReceiveMessage %#", message.dialogID);
}
But the dialogID I'm getting is (null), which doesn't make any sense. The variable self.dialog.ID is not null upon sending the message, the message gets to its destination with all the text I sent, but the dialogID is (null). I verified in the Chat admin panel inside my account and the dialog does not show the new messages. I'm using v2.6.0.1 btw.

Okay, I found my problem.
Seems when I changed some sending messages methods I commented out the important part of
message.customParameters[#"save_to_history"] = #"1";
Never forget to set save_to_history custom parameter or your message will get to its recipient without a dialogID...

Related

Seems impossible to delete a subscription in CloudKit? `-deleteSubscriptionWithID` always returns true

I'm hoping there's an experienced CloudKit guru out there, but based off my google search queries, I'm not sure if you exist. I think this may be a bug with Apple, but I can't be sure :\
I can save a subscription to my CKDatabase fine, no problems at all.
[publicDatabase saveSubscription:subscription completionHandler:^(CKSubscription *subscription, NSError *error) {
if (error)
{
//No big deal, don't do anything.
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:[subscription subscriptionID] forKey:#"SUBSCRIPTION"];
}
}];
Whenever I change a field in my record, I get a push notification, and everything is happy.
My problem is removing this subscription.
I have tried calling -deleteSubscriptionWithID:completionHandler:
As you can see in the above code snippet, I save off the subscription ID (Have also confirmed it to be the correct subscription ID by calling -fetchAllSubscriptionsWithCompletionHandler:
I passed the subscriptionID in that message, like so:
[publicDatabase deleteSubscriptionWithID:[[NSUserDefaults standardUserDefaults] objectForKey:#"SUBSCRIPTION"] completionHandler:^(NSString * _Nullable subscriptionID, NSError * _Nullable error) {
if( error ) {
NSLog(#"ERROR: %#", [error description] );
}
else
{
NSLog(#"SUCCESS: %#", subscriptionID);
}
}];
But it doesn't delete my subscription:
And no matter what I pass as the subscriptionID, there is no error and I see "SUCCESS" upon "deleting".
...so yeah. Clearly that isn't going to work.
If I manually delete the subscription through the Cloudkit Dashboard, my -fetch call properly notices that and returns an empty array:
So at this point I'm certain that I'm either deleting a subscription incorrectly in code, or it's broken and (not likely) nobody has asked on SO or any other forum that I can find?
I have also tried using a CKModifySubscriptionsOperation
CKModifySubscriptionsOperation *deleteSub = [[CKModifySubscriptionsOperation alloc] initWithSubscriptionsToSave:nil subscriptionIDsToDelete:#[[[NSUserDefaults standardUserDefaults] objectForKey:#"SUBSCRIPTION"]]];
[publicDatabase addOperation:deleteSub];
No results :(
I delete subscriptions using the database.deleteSubscriptionWithID function.
If you want to make sure that the ID is correct you could also first fetch all of them using database.fetchAllSubscriptionsWithCompletionHandler({subscriptions, error in
Then in the completion handler check if it's a valid subscription using: if let subscription: CKSubscription = subscriptionObject
And then delete one or more using: database.deleteSubscriptionWithID(subscription.subscriptionID, completionHandler: {subscriptionId, error in
Here you can see code how I delete all subscriptions:
https://github.com/evermeer/EVCloudKitDao/blob/1bfa936cb46c5a2ca75f080d90a3c02e925b7e56/AppMessage/AppMessage/CloudKit/EVCloudKitDao.swift#L897-897

Parse iOS: PFUser saveInBackgroundWithBlock does not return error when the save does not succeed

I am using anonymous users in parse and if they are not saved, I issue a network call to save them. The code for saving the user is as follows
PFUser* current = [PFUser currentUser];
if (!current.objectId) {
// The user is newly created, don't run any queries for them until they are saved.
[current saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// We need a saved user to do stuff.
if (!succeeded) {
NSLog(#"Error saving user: %#", error);
} else {
NSLog(#"Saved anonymous user");
// ... load data
}
}];
return;
}
If I run this in the simulator with no internet connection, the save fails (clearly), but succeeded is true and error is nil, so my code goes into loading data even though the user was not saved. In fact the error gets logged in logs but isn't returned in the callback:
Error: Error
Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to
be offline." UserInfo=0x17aa1220
{NSErrorFailingURLStringKey=https://api.parse.com/2/user_signup_or_login,
NSErrorFailingURLKey=https://api.parse.com/2/user_signup_or_login,
NSLocalizedDescription=The Internet connection appears to be offline.,
NSUnderlyingError=0x1792c880 "The Internet connection appears to be
offline."} (Code: 100, Version: 1.2.20)
Is this a bug in the Parse API or am I not using something correctly?
It is not enough to just check the succeeded flag, you should also check the error.
If you are only going to check one of them, check the error.
The following is the pattern I would use:
if (succeeded && !error) {
// success!
} else {
// uh oh :(
}
You can handle the error in the else block by using kPFErrorConnectionFailed which checks for connection.
Example
else {
if(error.code == kPFErrorConnectionFailed)
{
// handle error
}
}
This was a bug which has now been fixed in the latest release of parse.

Unable to obtain origin of NSLog in a Parse block?

I am using the following code to log in a user to my application using parse.com
[PFUser logInWithUsernameInBackground:usernameString password:passwordString
block:^(PFUser *user, NSError *error) {
if (user) {
// Do stuff after successful login.
NSLog(#"The user has logged in");
} else {
// The login failed. Check error to see why.
}
}];
The code works great and is documented on the Parse.com API Documentation HERE
My problem however is that I want to be able to show an alert to users when their login credentials come back with with an error, currently I get the following error on my console when I try to sign in with invalid credentials: Error: invalid login credentials (Code: 101, Version: 1.2.19)
Thats great, but I have looked everywhere and cant seem to find where that code, is being created... I am looking for it so that I can add different error messages for to my users: i.e.
if ([errorString rangeOfString:#"username"].location == NSNotFound) {
//the issue is not username related
} else
{
NSLog= (#"The username has been taken");
}
Any idea how I can find the string that contains the error and examine it so that I may act accordingly to the error?
the parse error codes are all documented here:
https://parse.com/docs/ios/api/Classes/PFConstants.html
101 is kPFErrorObjectNotFound
and means 'Object doesn't exist, or has an incorrect password.'
during a login it is likely more the later ;)
so:
if(error.code == kPFErrorObjectNotFound) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"parse login error" message:#"Invalid credentials" delegate:nil cancelButtonTitle:#"ok"];
[alert show];
}
dont use the error string of an NSError as you can't really tell if it is suitable for display.
still it is likely in localizedDescription or some other userInfo field
If you look at the documentation for NSError you will see that its userInfo property is a dictionary. From your NSLog you can see that the error key contains the string you are after, so you can access it with
NSString *errorMessage=[error.userInfo objectForKey:#"error"];
Although, rather than parsing strings it is safer to check the error.code value for 101, possibly displaying the error message for more detail. Checking the error code rather than the string will ensure that a change in the string by Parse won't break your code

Why am I not getting an error when sending data through the Game Center without internet?

-(BOOL)sendMessage:(NSMutableDictionary *)_message {
//*** Process _message and convert it to NSData here ***//
NSError *error;
BOOL success = [currentMatch sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error];
if (error != nil) {
NSLog(#"Sending data ERROR");
}
return success;
}
I started a match (stored in currentMatch) with another player and continuously sent data using the above method. Then I turned off the wifi.
However, I am not getting the "Sending data ERROR" log message at all.
Why? I turned off the internet connection, so why is there no error here? What could possibly lead to this scenario?
I've also confirmed that the dictionary I am sending is properly encoded into an NSData object, and success is returning YES.
As per the documentation
Return Value
YES if the data was successfully queued for transmission; NO if the match was unable to queue the data.
The method only enqueues the data for transmission, which happens asynchronously.
If you want to monitor the state of the transmission, implement the proper GKMatchDelegate delegate methods, such as match:didFailWithError:.
However, as stated in the documentation:
The match queues the data and transmits it when the network becomes available.
so if you try to perform the method with no network, the transfer just won't happen until the network is back, meaning that you won't see it failing.
By the way you should check the return value, instead of the error, since the error might be nil despite the operation being unsuccessful.
NSError *error;
BOOL success = [currentMatch sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error];
if (!success) {
NSLog(#"Sending data ERROR\n%#", error);
}
return success;
You need to check the return value of the method to know whether or not an error occurred. You cannot test the error parameter directly.
if (!success) {
NSLog(#"Sending data ERROR -- %#", error);
}
return success;
As to why you don't get an error, that send method is asynchronous. It simply enqueues the data for transmission and immediately returns. You have to catch the error through some other means (I'm not steeped in GameKit to know what that other means might be).

Fetching Current User Profile using Objective C Google Plus Client Library

I am using the Google CLient Libraries for Objective C available here..
I have successfully been able to Authorize the user and get refresh token. (Using the GTMOAuthenticaion api embedded within).
In the Selector called after successful authorization I make the Get User Profile request as follows.. (I need the id of currently loggedin/authenticated user)
-(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error != nil) {
NSLog(#"Stop");
} else {
if ([auth canAuthorize]){
[Mediator plusService].authorizer = auth;
// Problematic Line
GTLQueryPlus *profileQuery = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"]; // Notice the UserId Param
profileQuery.completionBlock = ^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
self.mediator.gProfile = object;
} else {
NSLog(#"GPlus Service Error %#", error);
}
};
[[Mediator plusService] executeQuery:profileQuery completionHandler:
^(GTLServiceTicket *ticket, id result, NSError *error) {
if (error)
NSLog(#"Some Service Error %#", error);
}];
}
}
}
If I put "me" as parameter, I get invalid user ID error string in jSON response.
However, If I provide some userId like my own 113632923069489732066 it works perfectly fine and returns the appropriate jSON response..!!
The Example for Google Plus inside Examples folder also fails to get current user profile ending with following error.
Error Domain=com.google.GTLJSONRPCErrorDomain Code=400 "The operation couldn’t be completed. (Invalid user ID: {0})" UserInfo=0x7a670fa0 {NSLocalizedFailureReason=(Invalid user ID: {0}), GTLStructuredError=GTLErrorObject 0x7a67b130: {message:"Invalid user ID: {0}" code:400 data:[2]}, error=Invalid user ID: {0}}
P.S. My API Console application doesn't work with iOS option under installed app but needs be configured with "Other" option. When configured with iOS option, the oAuth fails with invalid_client error response.
My Mistake .. !! And a very silly one .. !!
I was signing in using a Gmail Account that was yet not associated with GPlus .. !! =/

Resources