转:Jabber Client for iOS: Interface Setup
http://mobile.tutsplus.com/tutorials/iphone/building-a-jabber-client-for-ios-interface-setup/
In this tutorial we will build a Jabber Client for iOS. The application developed in this series will enable users to sign in, add buddies, and send messages. This tutorial will focus on setting up the user interface for the sample chat client.
Overview of the iOS Client
The core of our Jabber application is built around the XMPP capabilities. We will store these functionalities in the main application delegate, which will implement a custom protocol to dispatch events like logging in and sending messages. The application we are going to build is based around three views: login, buddy list, and chat.
The buddy list is the default view, which is shown when the application starts up. It shows the list of online buddies. The login view will appear only if there are no credentials previously stored on the device. A button named “Account” will show the login view from the buddy list, to enable changing login credentials when needed. The chat view is displayed when an online buddy is tapped, to initiate a chat. We will build a view controller for each of these views. Controllers will implement a simple protocol to receive notifications dispatched by the application delegate. To keep things simple, login and a chat view will appear as a modal view controller. If you like, you can rework the application to use a navigation controller instead.
Project Setup
Let’s open Xcode and start a new project. We will choose a simple view based application and we will name it “JabberClient”. To interact with the server, we will adopt a handy library for iOS which is called XMPP framework. This library is compatible with both Mac and iOS applications and will help us in implementing the low-level functionalities to connect with XMPP server and manage message exchanges through sockets. Since the repository does not feature any download link you need to have git installed (see here for more information). Once you have installed git, you can issue the following command in the console:
git clone https://code.google.com/p/xmppframework/ xmppframework
Once the download has completed we should end up with a folder like the following:
We need only the folders highlighted in the picture. Once selected, we drag them over the project to include them. Just remember to check “Copy items into destination group’s folder (if needed)”.
We don’t need the integration with Facebook, so in the “Extensions” group we can delete the “X-FACEBOOK-PLATFORM” folder.
Now let’s add the frameworks needed. We select the project in the navigator, then we select the target and we open “Link Binary With Libraries” as shown in the figure.
We have to add lots of framework as shown in the following figure:
Finally, to compile a project we have to tweak some build settings. Changes have to be added to both the project and the target. First, we find the “User Header Search Paths” and we specify the library needed to parse xml: ‘/usr/include/libxml2′
Then we select “Other Linker Flags” and the add the following flag: “-lxml2″.
The project is now set up correctly and you should be able to build it without errors or warnings.
Creating the Buddy List View
The buddy list contains a table view which shows a list of online contacts. When one is tapped it shows the corresponding chat view. The project wizard has already created a view controller, which we will rename “BuddyListViewController” for sake of consistency. This controller will have a UITableView
and an array to store online contacts. It will also have an IBAction
to show the login view, in case the user wants to switch account. Moreover it will implement table view delegates. So we update the implementation file as follows.
1
2
3
4
5
6
7
|
@interface
JabberClientViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { UITableView
*tView; NSMutableArray
*onlineBuddies; } @property
( nonatomic ,retain)
IBOutlet
UITableView *tView; -
( IBAction )
showLogin; @end |
In the implementation file we syntesize the property and we add the standard methods to manage
the table view.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
@implementation
JabberClientViewController @synthesize
tView; -
( void )viewDidLoad
{ [ super
viewDidLoad]; self .tView.delegate
= self ; self .tView.dataSource
= self ; onlineBuddies
= [[ NSMutableArray
alloc ] init]; } -
( void )
showLogin { //
show login view } #pragma
mark - #pragma
mark Table view delegates -
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath
*)indexPath { NSString
*s = ( NSString
*) [onlineBuddies objectAtIndex:indexPath.row]; static
NSString
*CellIdentifier = @"UserCellIdentifier" ; UITableViewCell
*cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if
(cell == nil )
{ cell
= [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.textLabel.text
= s; cell.accessoryType
= UITableViewCellAccessoryDisclosureIndicator; return
cell; } -
( NSInteger )tableView:(UITableView
*)tableView numberOfRowsInSection:( NSInteger )section
{ return
[onlineBuddies count]; } -
( NSInteger )numberOfSectionsInTableView:(UITableView
*)tableView { return
1; } -
( void )tableView:(UITableView
*)tableView didSelectRowAtIndexPath:( NSIndexPath
*)indexPath { //
start a chat } @end |
The corresponding xib file will have a table view, and a toolbar with a bar button item as in the following figure:
We should remember to link the table view and the showLogin
action to their corresponding outlets as shown below:
If we run the application we should see an empty table as in the following screenshot:
We can suspend the implementation of this class for awhile. We will integrate the XMPP features when ready. For now, let’s move to the login.
Building the Login User Interface
This view shows up when the user has not yet entered login credentials or when the “Account” button is tapped. It is made of two input fields and a button. An additional action will enable the user to hide the view without changes.
1
2
3
4
5
6
7
8
9
|
@interface
SMLoginViewController : UIViewController { UITextField
*loginField; UITextField
*passwordField; } @property
( nonatomic ,retain)
IBOutlet
UITextField *loginField; @property
( nonatomic ,retain)
IBOutlet
UITextField *passwordField; -
( IBAction )
login; -
( IBAction )
hideLogin; @end |
The implementation is pretty straightforward. When the login action is triggered data in the textfields is stored in NSUSerDefaults
with two keys “userID” and “userPassword”. This data will be used by the XMPP engine and sent to the server.
1
2
3
4
5
6
7
8
9
10
11
12
|
@implementation
SMLoginViewController @synthesize
loginField, passwordField; -
( IBAction )
login { [[ NSUserDefaults
standardUserDefaults] setObject: self .loginField.text
forKey: @"userID" ]; [[ NSUserDefaults
standardUserDefaults] setObject: self .passwordField.text
forKey: @"userPassword" ]; [[ NSUserDefaults
standardUserDefaults] synchronize]; [ self
dismissModalViewControllerAnimated: YES ]; } -
( IBAction )
hideLogin { [ self
dismissModalViewControllerAnimated: YES ]; } @end |
As above we should remember to link text fields and actions in the XIB file.
Now we can update the BuddyList controller to show the login view when needed. We import the corresponding class and we update the action as follows.
1
2
3
4
|
-
( IBAction )
showLogin { SMLoginViewController
*loginController = [[SMLoginViewController alloc] init]; [ self
presentModalViewController:loginController animated: YES ]; } |
We also implement the viewDidAppear
function so that it shows the login view when no data is stored.
1
2
3
4
5
6
7
|
-
( void )viewDidAppear:( BOOL )animated
{ [ super
viewDidAppear:animated]; NSString
*login = [[ NSUserDefaults
standardUserDefaults] objectForKey: @"userID" ]; if
(!login) { [ self
showLogin]; } } |
If we compile the application we should see that the login view appears as expected or when the user taps the button.
Creating the Chat View
The chat view features four visual elements:
- a toolbar with a button to close the view
- a textfield to type in messages
- a button to send messages
- a table view to display sent and received messages
The header file is the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@interface
SMChatViewController : UIViewController { UITextField
*messageField; NSString
*chatWithUser; UITableView
*tView; NSMutableArray
*messages; } @property
( nonatomic ,retain)
IBOutlet
UITextField *messageField; @property
( nonatomic ,retain)
NSString
*chatWithUser; @property
( nonatomic ,retain)
IBOutlet
UITableView *tView; -
( id )
initWithUser:( NSString
*) userName; -
( IBAction )
sendMessage; -
( IBAction )
closeChat; @end |
Like the buddy view this class implements table delegates. It keeps track of the received by means of the string variable chatWithUser
and features two actions, closeChat
and sendMessage
. The corresponding implementation is the following.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
@implementation
SMChatViewController @synthesize
messageField, chatWithUser, tView; -
( void )viewDidLoad
{ [ super
viewDidLoad]; self .tView.delegate
= self ; self .tView.dataSource
= self ; messages
= [[ NSMutableArray
alloc ] init]; [ self .messageField
becomeFirstResponder]; } #pragma
mark - #pragma
mark Actions -
( IBAction )
closeChat { [ self
dismissModalViewControllerAnimated: YES ]; } -
( IBAction )sendMessage
{ NSString
*messageStr = self .messageField.text; if ([messageStr
length] > 0) { //
send message through XMPP 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]; } } #pragma
mark - #pragma
mark Table view delegates -
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath
*)indexPath { NSDictionary
*s = ( NSDictionary
*) [messages objectAtIndex:indexPath.row]; static
NSString
*CellIdentifier = @"MessageCellIdentifier" ; UITableViewCell
*cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if
(cell == nil )
{ cell
= [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; } cell.textLabel.text
= [s objectForKey: @"msg" ]; cell.detailTextLabel.text
= [s objectForKey: @"sender" ]; cell.accessoryType
= UITableViewCellAccessoryNone; cell.userInteractionEnabled
= NO ; return
cell; } -
( NSInteger )tableView:(UITableView
*)tableView numberOfRowsInSection:( NSInteger )section
{ return
[messages count]; } -
( NSInteger )numberOfSectionsInTableView:(UITableView
*)tableView { return
1; } #pragma
mark - #pragma
mark Chat delegates //
react to the message received -
( void )dealloc
{ [messageField
dealloc]; [chatWithUser
dealloc]; [tView
dealloc]; [ super
dealloc]; } |
When the view has loaded we show the keyboard. The table part is pretty similar to the buddy view. Here we use a slightly different type of table cell to display both the message and the name. Below is the intended result when the application is ready:
We should remember to connect the IBAction
properties with the corresponding buttons as usual.
The visual part of out application is ready! Now we are left with the core functionality of messaging, and that will be covered in the next part of this series!
Source Code
The complete source code for this project can be found on GitHub here.