Building a Jabber Client for iOS: XMPP Setup

Building a Jabber Client for iOS: XMPP Setup

Tutorial Details
  • Technology: iOS SDK
  • Difficulty: Advanced
  • Completion Time: 60 - 90 Minutes
This entry is part 3 of 4 in the series Building a Jabber Client for iOS

Welcome to the third installment of our series on building a Jabber client with the iOS SDK. In this tutorial, we will add XMPP functionalities to the Application Delegate. Placing the functionality in the App Delegate will enable us to access XMPP functionalities from anywhere in the application easily.

Integrating XMPP in the AppDelegate

As mentioned, inserting the XMPP functionality in the App Delegate is a great way to make the functionality easily available throughout the app. At any place in your application code, you can access the App Delegate with the following code snippet:

	[[UIApplication sharedApplication] delegate]

The XMPP class will dispatch events by means of protocols which we will define below. This is the list of events handled by this class:

  • The client connected with the server
  • The client authenticated with the server
  • The client received a notification of presence (e.g. a user logged in)
  • The client received a message

Let’s get started by adding the some property to the application delegate. First we need to import some XMPP stuff in the header:

#import "XMPP.h"

This is the minimal set of classes needed to build our application. If you want to digg into something more complex you can checkout the example bundled with the XMPP library repository. Here is our first implementation of this class:

@class SMBuddyListViewController;
@interface jabberClientAppDelegate : NSObject  {
    UIWindow *window;
    SMBuddyListViewController *viewController;
    XMPPStream *xmppStream;
    NSString *password;
    BOOL isOpen;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet SMBuddyListViewController *viewController;
@property (nonatomic, readonly) XMPPStream *xmppStream;
- (BOOL)connect;
- (void)disconnect;
@end

XMPPStream will be the barebone of our client-server communication system and all messages will be exchanged through it. We will also define the methods to manage connection and disconnection. The implementation of this class is pretty complex, so we will break it down into many steps. First, we need a few more accessory methods to handle client-server communications. These can be private, so we place them in the implementation of the class:

@interface JabberClientAppDelegate()
- (void)setupStream;
- (void)goOnline;
- (void)goOffline;
@end
@implementation JabberClientAppDelegate
@end

Here, the most important is setupStream, which creates the channel to manage the exchange of messages.

- (void)setupStream {
	xmppStream = [[XMPPStream alloc] init];
	[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}

Just two lines of code, but behind that many things happen. The dispatch_get_main_queue() is a function which returns a reference
to the system level asynchronous execution mechanism, to which we can sumbit tasks and receive notifications. Here we “simply” tell
that our class is the delegate for the notifications sent from the main queue, which is run in the main thread of our application. See here for more details about Grand Central Dispatch.

Offline and Online functions are able to notify other users when we are connected or not. They are defined by sending an XMPPPresence object through the socket. The server will dispatch the notification accordingly.

- (void)goOnline {
	XMPPPresence *presence = [XMPPPresence presence];
	[[self xmppStream] sendElement:presence];
}
- (void)goOffline {
	XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
	[[self xmppStream] sendElement:presence];
}

The connect method is the most important, for it manages the login operation. It returns a boolean representing whether the connection was successful or not. At first it sets up the stream, then it uses data stored in NSUserDefaults to decorate the stream and call a connect message. An alert view is displayed if the connection is not successful.

- (BOOL)connect {
	[self setupStream];
	NSString *jabberID = [[NSUserDefaults standardUserDefaults] stringForKey:@"userID"];
	NSString *myPassword = [[NSUserDefaults standardUserDefaults] stringForKey:@"userPassword"];
	if (![xmppStream isDisconnected]) {
		return YES;
	}
	if (jabberID == nil || myPassword == nil) {
		return NO;
	}
	[xmppStream setMyJID:[XMPPJID jidWithString:jabberID]];
	password = myPassword;
	NSError *error = nil;
	if (![xmppStream connect:&error])
	{
		UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
															message:[NSString stringWithFormat:@"Can't connect to server %@", [error localizedDescription]]
														   delegate:nil
												  cancelButtonTitle:@"Ok"
												  otherButtonTitles:nil];
		[alertView show];
		[alertView release];
		return NO;
	}
	return YES;
}

For sake of completeness, we also implement the disconnect method which is defined as follows:

- (void)disconnect {
	[self goOffline];
	[xmppStream disconnect];
}

Now that we have some of the basic functions we can use them in specific cases, for example, when the application becomes active or inactive.

- (void)applicationWillResignActive:(UIApplication *)application {
	[self disconnect];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
	[self connect];
}

We are left with the core of the system, the notifications of events and related behaviors, which we implement by means of protocols.

Defining Protocols

We will define two protocols, one for chat notifications like “a buddy went offline”, and one for dispatching messages received. The first protocol includes the description of three events:

@protocol SMChatDelegate
- (void)newBuddyOnline:(NSString *)buddyName;
- (void)buddyWentOffline:(NSString *)buddyName;
- (void)didDisconnect;
@end

The first two messages are related to the presences of a buddy. We will react to these by adding or removing elements to the online buddies table. The third just notifies the server when our client disconnects. The second protocol is simpler, for it manages just the event of message reception.

@protocol SMMessageDelegate
- (void)newMessageReceived:(NSDictionary *)messageContent;
@end

For the sake of simplicity, to represent the message we will use a dictionary with two keys, @”msg” and @”sender”, to represent the actual message and the actual sender.

Implementing Protocols

Both protocols dispatch messages from the UIApplicationDelegate. So we extend our main class by adding two properties (one for each delegate).

@interface JabberClientAppDelegate : NSObject  {
	...
	__weak NSObject  *_chatDelegate;
	__weak NSObject  *_messageDelegate;
}
@property (nonatomic, assign) id  _chatDelegate;
@property (nonatomic, assign) id  _messageDelegate;
@end

In the implementation we should remember to synthesize these properties.

@synthesize _chatDelegate, _messageDelegate;

Now our main class is ready to dispatch events to delegates. But which events? Those received from the Grand Central Dispatch. If you remember,
we have setup our UIApplicationDelegate as a delegate for stream messages. Such delegates have the following signatures. The names
are pretty self explanatory, but we added comments within to make it even clearer.

- (void)xmppStreamDidConnect:(XMPPStream *)sender {
	// connection to the server successful
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
	// authentication successful
}
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
	// message received
}
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
	// a buddy went offline/online
}

Let’s start by authentication when we connect to the server.

- (void)xmppStreamDidConnect:(XMPPStream *)sender {
	isOpen = YES;
	NSError *error = nil;
	[[self xmppStream] authenticateWithPassword:password error:&error];
}

When authentication is successful, we should notify the server that we are online.

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
	[self goOnline];
}

When we receive a presence notification, we can dispatch the message to the chat delegate.

- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
	NSString *presenceType = [presence type]; // online/offline
	NSString *myUsername = [[sender myJID] user];
	NSString *presenceFromUser = [[presence from] user];
	if (![presenceFromUser isEqualToString:myUsername]) {
		if ([presenceType isEqualToString:@"available"]) {
			[_chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"jerry.local"]];
		} else if ([presenceType isEqualToString:@"unavailable"]) {
			[_chatDelegate buddyWentOffline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"jerry.local"]];
		}
	}
}

The delegate will use these events to populate the online buddies table accordingly (see below). Finally, we are left with the message received notification.

- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
	NSString *msg = [[message elementForName:@"body"] stringValue];
	NSString *from = [[message attributeForName:@"from"] stringValue];
	NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
	[m setObject:msg forKey:@"msg"];
	[m setObject:from forKey:@"sender"];
	[_messageDelegate newMessageReceived:m];
	[m release];
}

In this case, we build a dictionary as requested by the protocol and we call the corresponding method. At this point the core of our system is ready. We just have to make the user interface components react accordingly.

Hooking Up Views and Controllers

We start by modifying the buddy list controller, which manages the first view displayed when the app is started. We add the chat delegate to the interface as follows:

@interface SMBuddyListViewController : UIViewController <..., SMChatDelegate>  {
@end

We add a few access methods to point to the application delegate and stream:

- (JabberClientAppDelegate *)appDelegate {
	return (JabberClientAppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (XMPPStream *)xmppStream {
	return [[self appDelegate] xmppStream];
}

We also have to extend the viewDidLoad message to set our view controller as a delegate for the chat protocol.

- (void)viewDidLoad {
	...
	JabberClientAppDelegate *del = [self appDelegate];
	del._chatDelegate = self;
}

When the view appears, if credentials have been entered already, we call the connect method of the application delegate:

- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];
	NSString *login = [[NSUserDefaults standardUserDefaults] objectForKey:@"userID"];
	if (login) {
		if ([[self appDelegate] connect]) {
			NSLog(@"show buddy list");
		}
	} else {
		[self showLogin];
	}
}

Finally, we have to add or remove objects from the array of online buddies according to the events dispatched by the application delegate.

- (void)newBuddyOnline:(NSString *)buddyName {
	[onlineBuddies addObject:buddyName];
	[self.tView reloadData];
}
- (void)buddyWentOffline:(NSString *)buddyName {
	[onlineBuddies removeObject:buddyName];
	[self.tView reloadData];
}

If you run the application now and a buddy comes online, the table view gets populated with his username as in the following figure:

Online buddies in the list view.

Important Note: Depending on the server settings, you might need to wait for some time in order to receive the “new buddy is online” notifications. This time tends to be from 20 to 60 seconds.

To start a chat with the user we have to show the chat view when the corresponding cell is tapped.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	NSString *userName = (NSString *) [onlineBuddies objectAtIndex:indexPath.row];
	SMChatViewController *chatController = [[SMChatViewController alloc] initWithUser:userName];
	[self presentModalViewController:chatController animated:YES];
}

To finalize the application we need to add the implementation of the message delegate to the chat view controller. The steps to do so are similar to those applied to the buddy list controller. We add the delegate in the interface file:

@interface SMChatViewController : UIViewController < ... , SMMessageDelegate>
@end

We add accessors to the implementation:

- (JabberClientAppDelegate *)appDelegate {
	return (JabberClientAppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (XMPPStream *)xmppStream {
	return [[self appDelegate] xmppStream];
}

We add the implementation of initWithUser:username:

- (id) initWithUser:(NSString *) userName {
	if (self = [super init]) {
		chatWithUser = userName;
	}
	return self;
}

We extend the viewDidLoad to declare the message delegate and we also set the text field as a first responder to keyboard input:

- (void)viewDidLoad {
	...
	JabberClientAppDelegate *del = [self appDelegate];
	del._messageDelegate = self;
	[self.messageField becomeFirstResponder];
}

To send a message, we need to create an xml element as required by the XMPP protocol and send it over the stream. Here is how we update the sendMessage method:

- (IBAction)sendMessage {
    NSString *messageStr = self.messageField.text;
    if([messageStr length] &gt; 0) {
	  NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
          [body setStringValue:messageStr];
          NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
          [message addAttributeWithName:@"type" stringValue:@"chat"];
          [message addAttributeWithName:@"to" stringValue:chatWithUser];
          [message addChild:body];
          [self.xmppStream sendElement:message];
	  self.messageField.text = @"";
	  NSString *m = [NSString stringWithFormat:@"%@:%@", messageStr, @"you"];
	  NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
	  [m setObject:messageStr forKey:@"msg"];
	  [m setObject:@"you" forKey:@"sender"];
	  [messages addObject:m];
	  [self.tView reloadData];
	  [m release];
    }
}

We are now done! You can test the final implementation of our iOS client. We start the server, iChat and our jabber client. After awhile, both clients should receive a presence notification and recognize each other as online. On the iPhone we tap on the online buddy and the chat view shows up. Now we are ready to chat. Here is a screenshot of the final application at work.

Final version at work

Source Code

The complete source code for this project can be found on GitHub here.

Series Navigation«Building a Jabber Client for iOS: Interface SetupBuilding a Jabber Client for iOS: Custom Chat View and Emoticons»

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • moosc

    Great tutorial! thanks.

    Can you post the full source code of the ios client?

    The series will continue? i have some sugestions like sending files, emoticons…

  • http://studiomagnolia.com Cesare Rocchi
    Author

    I posted the code on github here: https://github.com/funkyboy/Building-a-Jabber-client-for-iOS.
    I will also update the post.

  • http://enroyed.com enroyed

    Hi, Nice tut But I have a problem running the project. when I run The app in simulator Its shows The online buddies But when I want to send Them message It paused and and shows several Threads in Xcode and the app paused. xcode gives me 4 issuses
    1./xcode projects/funkyboy-Building-a-Jabber-client-for-iOS-b96c1b1/Classes/JabberClientAppDelegate.m:146: warning: ‘-newMessageReceived:’ not found in protocol(s)

    2. /xcode projects/funkyboy-Building-a-Jabber-client-for-iOS-b96c1b1/Classes/JabberClientAppDelegate.m:146: warning: ‘NSObject’ may not respond to ‘-newMessageReceived:’

    3. /xcode projects/funkyboy-Building-a-Jabber-client-for-iOS-b96c1b1/Classes/SMChatViewController.m:142: warning: incompatible Objective-C types initializing ‘struct NSString *’, expected ‘struct NSDictionary *’

    4. /xcode projects/funkyboy-Building-a-Jabber-client-for-iOS-b96c1b1/Classes/SMChatViewController.m:142: warning: incompatible Objective-C types initializing ‘struct NSString *’, expected ‘struct NSDictionary *’

    Please send me The solution.

    Thanks

  • Sarah Lowthorpe

    Hey, Im pretty new to iOS Development and am currently finding your tutorials very easy to read and well written. Thank you for them.

    I came across this list of books for iOS Developers: http://ios-blog.co.uk/resources/recommended-reading-ios/ – Can I please ask your help for which one you think I should buy? or suggest another one

    i’ve bookmarked this page and will also add you to my twitter followers

    Thanks again,

    Love Saz x

  • kanyal

    Hi,
    Facebook has updated his authentication way and XMPP framwork is also updated accordingly. Did you try latest XMPP framwork after 10 October to integrate facebook chat. Thanks any suggestions? thanks

  • imran

    Hi Thanks alot for the code …it works great. i successfully implemented send and recieve msgs application. But in my scenario i have to implement a chat room. for this i think i have to use XMPPRoom class but i dont have any idea how it will implement exactly, can you please share some example of XMPPRoom. Thank you.

  • mike

    First, the tutorial doesn’t work. The xmpp framework has changed and some of the frameworks that we’re told to link to no longer exist.

    Second, the code has errors.

    Third, for the parts that do work, the author should advise the user to download the project FIRST, b/c there are only code fragments that make no sense unless you have the entire source code right before you.

  • Lucas

    Oh, nevermind my comment above… u.u

  • hugo

    I cannot send messages from the app, I can only receive…
    After a couple of seconds I always get this…
    Can anyone help?

    2011-11-21 11:57:58.205 JabberClient[7969:fb03] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: msg)’
    *** First throw call stack:
    (0x1df1052 0x1c11d0a 0x1d99a78 0x1d999e9 0x1df030a 0x2a65 0x1d5751d 0x1d57437 0x1d8249a 0x7255e 0x1a8a445 0x1a8c4f0 0x1d28833 0x1d27db4 0x1d27ccb 0x209e879 0x209e93e 0x60fa9b 0x21ed 0×2165)
    terminate called throwing an exception

  • john

    When I select a contact I get

    TURN Connection failed

    …I can RECEIVE but I cannot send.
    Could you please help?

    Thanks.

  • john

    In the end it doesn’t matter if the TURN connection fails, turn is used for media, not for text exchange.
    The problem in my case was in the SMChatViewController.
    In particular this line
    [message addAttributeWithName:@"to" stringValue:chatWithUser];

    chatWithUser doesn’t seem to be set correctly…. just try with a constant value and it will work!

    I solved it pretty roughly by saving the receiver in the app delegate.
    There’s some bug in retrieving the value from the table.

  • marco

    The error is the App Delegate, the iphone app always tries to chat with the jerry.local server.
    Either replace it with your server name or put a variable instead of a constant!!!


    [_chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"jerry.local"]];

    } else if ([presenceType isEqualToString:@"unavailable"]) {

    [_chatDelegate buddyWentOffline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"jerry.local"]];

  • http://quickblox.com PHWizard

    You may also use QuickBlox chat – download iOS sample code here:
    http://quickblox.com/2011/12/supersample-ios/

    there is a free backend

  • Parhelion

    How can I connect to another server?

    It’s kinda crucial for me to know this. Please help.

  • sai

    Hi how to connect another server using this coding

  • obaid

    You can connect to other server by replacing
    [_chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"jerry.local"]];

    with

    [_chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@@%@", presenceFromUser, @"Yourservername"]];

  • William

    Hi everyone,

    I got an issue is:

    Application was crashed when call doWriteData method on GCDAsyncSocket Class at line code below:

    const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;

    how can i solve this issue ?

    Thanks

    • watsy0007

      i got too.
      how can i solve this issue ?

      • turo20203

        did you find the solution?

    • Sandi Hernandez Flores

      did you find any solution about doWriteData? I was trying for a week and nothing is clear.
      could you help me please?.

    • turo2020

      do u have the solution? of this?

    • walhalla

      have you found any way out of this? I too am stuck there.

    • Ankur

      in – (void)setupStream method add xmppStream = [[[XMPPStream alloc] init]autorelease]; instead of xmppStream = [[XMPPStream alloc] init];
      this will solve the problem.

    • PREMKUMAR K

      I have same issue Please help me.

  • Mariano

    There’s an error on init
    - (id) initWithUser:(NSString *) userName {

    if (self = [super init]) {

    chatWithUser = userName;
    turnSockets = [[NSMutableArray alloc] init];
    }

    return self;

    }

    chatWithUser should be self.chatWithUser=userName;

    • Awais

      Thanks
      I did but problem is there application was crashed when call doWriteData method on GCDAsyncSocket.
      Plz resolve this issue ASAP.

      • chuck

        You need to add -fobjc-arc on each of library classes to use ARC it will crash at runtime.

  • Denis

    Great tutorial! Thank you.
    I have some questions about auth mechanism.
    As I can see, when we call AppDelegate’s method “connect:” authenticating procedure happens too. Then delegate calls method “didAuthenticate:”. But what to do if we have authenticate error?
    And how will look connect-auth procedure, if we call connect method in one ViewController, but must switch to other ViewController only if authenticate will success?

  • Trieu

    Helpful for me,

    When I use Xcode 4, I get some errors. I upgrade to Xcode 4.2, it work perfectly.

    Many thanks Cesare,

    • obaid

      Because Xcode 4.2 uses ARC

  • http://csdn/ipromiseu gray

    How to recv/send files between 2 iphone device ? with xep-65 ?

    • http://csdn/ipromiseu gray

      If you can post a file transfer sample or add file transfer into your article.thanks you.

  • http://www.miquido.com Apan

    Thanks for tutorial, but there are few shortcomings. Finally after those steps I managed to run my Jabber Client :)

    1. If you have problems with adding xmpp framework, you would better take steps from this site :
    https://github.com/robbiehanson/XMPPFramework/wiki/GettingStarted_iOS

    2. If you don’t get buddies from the server, you should add following line of code in setupStream method:
    [xmppStream setHostName:@"YOURSERVER"];
    YOURSERVER might be localhost

    3. If you can send msg, but cannot get one (you will have an exception that msg is nil, while writing in iChat) add one if to the -(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message method. It should looks like this:

    -(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
    // message recived
    if([[message elementForName:@"body"]stringValue] != nil){
    NSString *msg = [[message elementForName:@"body"] stringValue];
    NSString *from = [[message attributeForName:@"from"] stringValue];
    NSLog(@”%@ %@”,msg,from);

    NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
    [m setObject:msg forKey:@"msg"];
    [m setObject:from forKey:@"sender"];

    [_messageDelegate newMessageRecived:m];
    }
    }

    This error happens because iChat is sending message that other user is typing.

    Also you should implement -(void)newMessageRecived:(NSDictionary *)messageContent in SMChatViewController:

    -(void)newMessageRecived:(NSDictionary *)messageContent{
    [messages addObject:messageContent];
    [self.tView reloadData];
    }

    4. Source code from GIT doesn’t work for me, even after adding XMPPFramework. But I didn’t bother to force it to run and put my efforts in developing own code.

    Thanks for tut, it was very helpful in understanding how does it work.

    • PREMKUMAR K

      Hi, Please send working Code. This code got error. Please… Help me..

    • PREMKUMAR K

      Hi For your Information I add my local URL:

      xmppStream = [[[XMPPStream alloc] init]autorelease];
      xmppStream setHostName:@”prem-apple.local”];

      But this is Crash with following Image: Please help me. Please

  • http://www.emobx.com Bharti Sharma

    I didn’t get the list of online buddies. As per the above comment if online buddies are not showing then add one line of code i.e

    [xmppStream setHostName:@"YOURSERVER"]; in xmppStream method in app Delegate.

    but the result is not in my favor, my app gets crashed after this single line of code. Kindly look into the matter.

    I have added my server name in following method:

    - (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence

    • crispin

      In facebook chat my all friends list display id
      (-669957651@chat.facebook.com)! . But i want display name what i do
      please help me….

    • jack

      did you find the sol?

  • Crispin

    In facebook chat my all friends list display id (-669957651@chat.facebook.com)! . But i want display name what i do please help me….

  • KIM

    Thanks for this useful Tutorial !! I got a lot of useful information in this tutorial..

    however I have a problem… when this program call didReceivePresence method in AppDelegate

    my presenceType`s value is not online or offline but subscribe…..

    as i known, this problem means that the requester is asking for permission to subscribe to target_user`s presence information…how can i permit other`s information…

    please save me…

  • jack

    if i set [xmppStream setHostName:@"localhost"];

    my app just crash , how to fix this issue ???

    i am testing locally

  • Viraj

    I have tried all things but tableview not displaying any entries..
    What should be the problem?

  • http://www.facebook.com/integrationtest.integration IntegrationTest Integration

    Hey I have done lot of things in my chat project with help of xmpp framework. Now i just want to remove my name (id) from the list (tableview). i remove it from core data but again it comes back. can anyone tell me that how to remove own user from tableview.

  • Guest

    Hey I have done lot of things in my chat project with help of xmpp framework. Now i just want to remove my name (id) from the list (tableview). i remove it from core data but again it comes back. can anyone tell me that how to remove own user from tableview.

  • JC

    hai, i following the step by step tutorial. and i fail to connect to my server. i got many threads.
    While i was using your source code given, i got the problem that only show the log, but in my ejabberd server did not show me “online”.

    your help is needed urgently.thanks in advance.