Automatic chatroomDidLeave after chatDidFail. Why? Oh why? [Quickblox] - quickblox

Every time we try to reconnect after a chatDidFail event, we:
login in chat
enter room
automatically get kicked out of the the room (chatRoomDidLeave event)
when we try to re-join the room, we get kicked out again (chatRoomDidLeave)
and it loops
why, oh why?
Why does Quickblox kicks us out of any room after we try to reconnect following a chatDidFail event?
All we do is:
-(void)chatDidFailWithError:(int)code
{
[[QBChat instance] loginWithUser:currentUser];
}
- (void)chatRoomDidLeave:(NSString *)roomName
{
[[QBChat instance] createOrJoinRoomWithName:#"roomName" membersOnly:NO persistent:YES];
}
We're running out of ideas on this one...

I managed to resolve this. It seems that Quickblox chat implementation isn't able to recover on it's own, when the application goes background and you don't leave the chat room.
This can be solved by having the ChatManager (your own singleton class used to manage chat connections) to store the currently shown room (self.currentRoom) and automatically leave the room, and log out when application resigns active. And when the application will enter foreground, you log in and rejoin the room.
Add these to the singleton class (id)init:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleApplicationWillResignActiveNotification:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleApplicationEnterForegroundNotification:) name:UIApplicationWillEnterForegroundNotification object:nil];
And the property implementation for the current room:
#property (nonatomic, strong) QBChatRoom *currentRoom;
And then implement the corresponding handlers (you can also invalidate the presence timer here):
- (void)handleApplicationWillResignActiveNotification:(NSNotification *)notification
{
lg(#"Application resigning active");
if (self.currentRoom) {
if (self.presenceTimer) {
[self.presenceTimer invalidate];
self.presenceTimer = nil;
}
[self leaveRoom:self.currentRoom clearRoom:NO];
[[QBChat instance] logout];
}
}
- (void)handleApplicationEnterForegroundNotification:(NSNotification *)notification
{
lg(#"Application entering foreground.");
if (![[QBChat instance] loginWithUser:self.currentUser]) {
lg(#"Logging in failed for some reason.");
}
}
Then in chatDidLogin you do the following:
- (void)chatDidLogin
{
...
if (self.currentRoom) {
lg(#"Auto-joining current room.");
[self joinRoom:self.currentRoom completionBlock:nil];
}
...
}
Store the room reference when you enter a room:
- (void)chatRoomDidEnter:(QBChatRoom *)room
{
...
self.currentRoom = room;
...
}
Make sure that you don't clear self.currentRoom when you leave the room on UIApplicationWillResignActiveNotification, so that there's a reference for the current room when the application comes foreground.

Related

OCMock notification observer - verifying the object

I've recently started working with OCMock framework and trying to figure out how to use the notification observer. So in my source code I'm observing some notification:
typedef enum {
OperationStatusCompleted,
// Some other statuses
} SomeOperationStatus;
- (void)addObserverForSomeNotification {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(someOperationStatusDidChange:)
name:#"someOperationStatusDidChange"
object:nil];
- (void)backgroundOperationStatusDidChange:(NSNotification *)notification {
id<SomeOperationProtocol> operation = [notification object];
if (operation.status == OperationStatusCompleted) {
// Do something.
}
}
Now I want to add the expectation for that notification in my test:
- (void)testNotification {
id observerMock = OCMObserverMock();
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:#"someOperationStatusChanged" object:nil];
[[observerMock expect] notificationWithName:#"someOperationStatusChanged" object:[OCMArg any]];
// run the test ...
}
That by itself works fine and I'm receiving the notification in the test but what I actually want to check is the status of the object of the notification (meaning that I've received a notification with specific object with specific status). Is it possible?
I finally figured out how to do it:
[[observerMock expect] notificationWithName:#"someOperationStatusChanged" object:[OCMArg checkWithBlock:^BOOL(id<IMBBackgroundOperation> param) {
return param.status == OperationStatusCompleted;
}]];

libPusher not receiving pushes (obj c)

I am trying to implement a OS X (10.10) client for the real time bitcoin exchange rate from bitstamp.com. They offer a great api, unfortunately I can't get the websocket api (https://www.bitstamp.net/websocket/) to work in an OS X Objective C app.
Everyone is pointing me to the libPusher Github project (https://github.com/lukeredpath/libPusher) but I tried literally everything I can think of, I can't get it to receive any pushes on 10.10.
Following the wiki page I downloaded the pre-compiled static library and dragged all files into my projects (I also made sure the "copy" checkbox was checked) and my sample applications compiles. Unfortunately, I never see either the "event through block" or "event through delegate" on the console. However I know that trades happened in the mean time, so that can't be the issue. Any ideas?
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
PTPusher* client = [PTPusher pusherWithKey:#"de504dc5763aeef9ff52" delegate:self encrypted:YES];
[client connect];
PTPusherChannel *channel = [client subscribeToChannelNamed:#"live_trades"];
[channel bindToEventNamed:#"trade" handleWithBlock:^(PTPusherEvent *channelEvent) {
// channelEvent.data is a NSDictionary of the JSON object received
NSLog(#"event through block"); // <-- never called
}];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(didReceiveEventNotification:)
name:PTPusherEventReceivedNotification
object:client];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(didReceiveChannelEventNotification:)
name:PTPusherEventReceivedNotification
object:channel];
}
- (void)didReceiveEventNotification:(NSNotification *)notification // <-- never called
{
NSLog(#"event through delegate");
PTPusherEvent *event = [notification.userInfo objectForKey:PTPusherEventUserInfoKey];
}
After talking to the developer I found the problem:
In my code, the PTPusher instance is a local variable defined in the .m file.
However, it needs to be a strong variable defined in the .h file:
#property (strong) PTPusher* client;
Then in the .m file, you can easily use it (don't forget to synthesize it!):
self.client = [PTPusher pusherWithKey:#"de504dc5763aeef9ff52" delegate:self encrypted:YES];
[self.client connect];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(didReceiveEventNotification:)
name:PTPusherEventReceivedNotification
object:self.client];
PTPusherChannel *channel = [client subscribeToChannelNamed:#"live_trades"];

How to send a string along with NSNotification?

I'm trying to write a plugin for phonegap/cordova that allows audio to resume when interrupted by a phone call. I'm using AVAudioSesionInterruptionNotification and it is working well. However, I need to be able to send a string to my event handler, but I can't figure out how.
I'm setting up an event listener here and calling it from the javascript layer:
- (void) startListeningForAudioSessionEvent:(CDVInvokedUrlCommand*)command{
NSString* myImportantString = [command.arguments objectAtIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onAudioSessionEvent:) name:AVAudioSessionInterruptionNotification object:nil];
}
and I'm handling the event here:
- (void) onAudioSessionEvent:(NSNotification *)notification
{
if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
//do stuff using myImportantString
}
}
can't figure out how to pass myImportantString over to onAudioSessionEvent. I know very little Objective-C (hence my use of cordova), so please respond as if you're talking to a child. Thanks!
By the way, I'm simply trying to add a couple of methods on top of cordova's media plugin found here: https://github.com/apache/cordova-plugin-media/tree/master/src/ios
so the code above is the entirety of my .m file minus this part
#implementation CDVSound (extendedCDVSound)
It's probably easier to use the block-based API for adding an observer:
- (void) startListeningForAudioSessionEvent:(CDVInvokedUrlCommand*)command{
NSString* myImportantString = [command.arguments objectAtIndex:0];
id observer = [[NSNotificationCenter defaultCenter] addObserverForName:AVAudioSessionInterruptionNotification
object:nil
queue:nil
usingBlock:^(NSNotification *notification){
if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
//do stuff using myImportantString; you could even skip the use of that
//temporary variable and directly use [command.arguments objectAtIndex:0],
//assuming that command and command.arguments are immutable so that you
//can rely on them still being the same
}
}];
}
By using the block-based API, you can directly reference any variables that are in scope at the time the observer is added in the code which is invoked when the notification is posted.
When you're done observing, you need to remove observer as an observer of the notification.
Like this:
// near the top of MyController.m (above #implementation)
#interface MyController ()
#property NSString *myImportantString;
#end
// inside the implementation
- (void) startListeningForAudioSessionEvent:(CDVInvokedUrlCommand*)command{
self.myImportantString = [command.arguments objectAtIndex:0];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onAudioSessionEvent:) name:AVAudioSessionInterruptionNotification object:nil];
}
- (void) onAudioSessionEvent:(NSNotification *)notification
{
if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){
//do stuff using self.myImportantString
}
}

Use Block in Objective C to find out if a BOOL has been set?

I'm new to Obj-c. I've got a class which sets a var boolean to YES if it's successful (Game Center login = successful), what it would be great to do, is somehow have a listener to that var that listens to when it is YES and then executes some code. Do I use a block for that? I'm also using the Sparrow framework.
Here's my code in my GameCenter.m file
-(void) setup
{
gameCenterAuthenticationComplete = NO;
if (!isGameCenterAPIAvailable()) {
// Game Center is not available.
NSLog(#"Game Center is not available.");
} else {
NSLog(#"Game Center is available.");
__weak typeof(self) weakSelf = self; // removes retain cycle error
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer]; // localPlayer is the public GKLocalPlayer
__weak GKLocalPlayer *weakPlayer = localPlayer; // removes retain cycle error
weakPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error)
{
if (viewController != nil)
{
[weakSelf showAuthenticationDialogWhenReasonable:viewController];
}
else if (weakPlayer.isAuthenticated)
{
[weakSelf authenticatedPlayer:weakPlayer];
}
else
{
[weakSelf disableGameCenter];
}
};
}
}
-(void)showAuthenticationDialogWhenReasonable:(UIViewController *)controller
{
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:controller animated:YES completion:nil];
}
-(void)authenticatedPlayer:(GKLocalPlayer *)player
{
NSLog(#"%#,%#,%#",player.playerID,player.displayName, player.alias);
gameCenterAuthenticationComplete = YES;
}
-(void)disableGameCenter
{
}
But I need to know from a different object if that gameCenterAuthenticationComplete equals YES.
You can use a delegate pattern. It's far easier to use than KVO or local notifications and it's used a lot in Obj-C.
Notifications should be used only in specific situations (e.g. when you don't know who wants to listen or when there are more than 1 listeners).
A block would work here but the delegate does exactly the same.
You could use KVO (Key-Value Observing) to watch a property of your object, but I'd rather post a NSNotification in your case.
You'll need to have the objects interested in knowing when Game Center login happened register themselves to NSNotificationCenter, then post the NSNotification in your Game Center handler. Read the Notification Programming Topics for more details !
If there is a single method to execute on a single delegate object, you can simply call it in the setter. Let me give a name to this property:
#property(nonatomic,assign, getter=isLogged) BOOL logged;
It's enough that you implement the setter:
- (void) setLogged: (BOOL) logged
{
_logged=logged;
if(logged)
[_delegate someMethod];
}
Another (suggested) way is to use NSNotificationCenter. With NSNotificationCenter you can notify multiple objects. All objects that want to execute a method when the property is changes to YES have to register:
NSNotificationCenter* center=[NSNotificationCenter defaultCenter];
[center addObserver: self selector: #selector(handleEvent:) name: #"Logged" object: nil];
The handleEvent: selector will be executed every time that logged changes to YES. So post a notification whenever the property changes:
- (void) setLogged: (BOOL) logged
{
_logged=logged;
if(logged)
{
NSNotificationCenter* center=[NSNotificationCenter defaultCenter];
[center postNotificationName: #"Logged" object: self];
}
}

Objective-C Mac OS X Distributed notifications iTunes

i need a little help, i currently have a method; updateTrackInfo in my Mac OS X application which gets the artist name, the track name and duration of the track currently being played in iTunes
However i want the app to listen for the distributed iTunes notification; com.apple.iTunes.playerInfo then call the method updateTrackInfo when ever the notification is distributed by iTunes. Please could someone help me, on what i would need to write in both the header and implementation file.
Thanks, Sami.
You're looking for -[NSDistributedNotificationCenter addObserver:selector:name:object:]:
NSDistributedNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter];
[dnc addObserver:self selector:#selector(updateTrackInfo:) name:#"com.apple.iTunes.playerInfo" object:nil];
Elsewhere in the same class...
- (void) updateTrackInfo:(NSNotification *)notification {
NSDictionary *information = [notification userInfo];
NSLog(#"track information: %#", information);
}
It even gives you a whole bunch of track information in the notification. Isn't that nice?
Thanks for your help, you helped me correct my code, I had this written up:
- (id) init {
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"com.apple.iTunes.playerInfo"
object:nil];
return self;}
- (void) receiveNotification:(NSNotification *) notification {
if ([#"com.apple.iTunes.playerInfo" isEqualToString:#"com.apple.iTunes.playerInfo"]) {
NSLog (#"Successfully received the test notification!");
}}
But it used NSNotificationCenter instead of NSDistributedNotificationCenter. Which is where I was going wrong.
Thanks, Sami.