XMPP之ios即时通讯客户端开发-配置XMPP基本信息之工程代码(五)

登录功能完成以后包含以下代码文件:

 AppDelegate.h 

 AppDelegate.m

LoginViewController.h

LoginViewController.m

LoginUser.h

LoginUser.m

 

以下看代码:

//
//  AppDelegate.h
//  XMPP即时通讯
//
//  Created by Mac on 15/7/15.
//  Copyright (c) 2015年 聂小波. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "XMPPFramework.h"

#define xmppDelegate (AppDelegate *)[[UIApplication sharedApplication] delegate]

typedef void(^CompletionBlock)();

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

#pragma mark - XMPP属性及方法
/**
 *  全局的XMPPStream,只读属性
 */
@property (strong, nonatomic, readonly) XMPPStream *xmppStream;
/**
 *  全局的xmppvCard模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPvCardTempModule *xmppvCardModule;
/**
 *  全局的XMPPvCardAvatar模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPvCardAvatarModule *xmppvCardAvatarModule;
/**
 *  全局的xmppRoster模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPRoster *xmppRoster;
/**
 *  全局的XMPPRosterCoreDataStorage模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPRosterCoreDataStorage *xmppRosterStorage;

/**
 *  消息存档(归档)模块,只读属性
 */
@property (strong, nonatomic, readonly) XMPPMessageArchiving *xmppMessageArchiving;
@property (strong, nonatomic, readonly) XMPPMessageArchivingCoreDataStorage *xmppMessageArchivingCoreDataStorage;

/**
 *  传输文件socket数组
 */
@property (strong, nonatomic) NSMutableArray *socketList;

/**
 *  是否注册用户标示
 */
@property (assign, nonatomic) BOOL isRegisterUser;

/**
 *  连接到服务器
 *
 *  注释:用户信息保存在系统偏好中
 *
 *  @param completion 连接正确的块代码
 *  @param faild      连接错误的块代码
 */
- (void)connectWithCompletion:(CompletionBlock)completion failed:(CompletionBlock)faild;

/**
 *  注销用户登录
 */
- (void)logout;

@end

 

//
//  AppDelegate.m
//  XMPP即时通讯
//
//  Created by Mac on 15/7/15.
//  Copyright (c) 2015年 聂小波. All rights reserved.
//

#import "AppDelegate.h"
#import "LoginUser.h"
#import "NSString+Helper.h"
#import "NSData+XMPP.h"

#define kNotificationUserLogonState @"NotificationUserLogon"

@interface AppDelegate() <XMPPStreamDelegate, XMPPRosterDelegate, TURNSocketDelegate>
{
    CompletionBlock             _completionBlock;       // 成功的块代码
    CompletionBlock             _faildBlock;            // 失败的块代码
    
    XMPPReconnect               *_xmppReconnect;        // XMPP重新连接XMPPStream
    XMPPvCardCoreDataStorage    *_xmppvCardStorage;     // 电子名片的数据存储模块
    
    XMPPCapabilities            *_xmppCapabilities;     // 实体扩展模块
    XMPPCapabilitiesCoreDataStorage *_xmppCapabilitiesCoreDataStorage; // 数据存储模块
}

// 设置XMPPStream
- (void)setupStream;
// 销毁XMPPStream并注销已注册的扩展模块
- (void)teardownStream;
// 通知服务器器用户上线
- (void)goOnline;
// 通知服务器器用户下线
- (void)goOffline;
// 连接到服务器
- (void)connect;
// 与服务器断开连接
- (void)disconnect;

@end

@implementation AppDelegate

#pragma mark 根据用户登录状态加载对应的Storyboard显示
- (void)showStoryboardWithLogonState:(BOOL)isUserLogon
{
    UIStoryboard *storyboard = nil;
    
    if (isUserLogon) {
        // 显示Main.storyboard
        storyboard = [UIStoryboard storyboardWithName:@"LoginViewController" bundle:nil];
    } else {
        // 显示Login.sotryboard
        storyboard = [UIStoryboard storyboardWithName:@"LoginViewController" bundle:nil];
    }
    
    // 在主线程队列负责切换Storyboard,而不影响后台代理的数据处理
    dispatch_async(dispatch_get_main_queue(), ^{
        // 如果在项目属性中,没有指定主界面(启动的Storyboard,self.window不会被实例化)
        // 把Storyboard的初始视图控制器设置为window的rootViewController
        [self.window setRootViewController:storyboard.instantiateInitialViewController];
        
        if (!self.window.isKeyWindow) {
            [self.window makeKeyAndVisible];
        }
    });
}

#pragma mark - AppDelegate方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // 1. 实例化window
//    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    
    // 2. 设置XMPPStream
    [self setupStream];
    
    // 3. 实例化socket数组
    _socketList = [NSMutableArray array];
    
    return YES;
}

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

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // 应用程序被激活后,直接连接,使用系统偏好中的保存的用户记录登录
    // 从而实现自动登录的效果!
    [self connect];
}

- (void)dealloc
{
    // 释放XMPP相关对象及扩展模块
    [self teardownStream];
}

#pragma mark - XMPP相关方法
// 设置XMPPStream
- (void)setupStream
{
    // 0. 方法被调用时,要求_xmppStream必须为nil,否则通过断言提示程序员,并终止程序运行!
//    NSAssert(_xmppStream == nil, @"XMPPStream被多次实例化!");
    
    // 1. 实例化XMPPSteam
    _xmppStream = [[XMPPStream alloc] init];
//    _xmppStream.hostName = @"127.0.0.1";
//////    mysql://localhost:3306/openfire
//    _xmppStream.hostPort = 5222;
//    
//////    NSString *myJID=@"admin";
//    _xmppStream.myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"admin@127.0.0.1"]];
    
    
    // 让XMPP在真机运行时支持后台,在模拟器上是不支持后台服务运行的
#if !TARGET_IPHONE_SIMULATOR
    {
        // 允许XMPPStream在真机运行时,支持后台网络通讯!
        [_xmppStream setEnableBackgroundingOnSocket:YES];
    }
#endif
    
    // 2. 扩展模块
    // 2.1 重新连接模块
    _xmppReconnect = [[XMPPReconnect alloc] init];
    // 2.2 电子名片模块
    _xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
    _xmppvCardModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:_xmppvCardStorage];
    _xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardModule];
    
    // 2.4 花名册模块
    _xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
    _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppRosterStorage];
    // 设置自动接收好友订阅请求
    [_xmppRoster setAutoAcceptKnownPresenceSubscriptionRequests:YES];
    // 自动从服务器更新好友记录,例如:好友自己更改了名片
    [_xmppRoster setAutoFetchRoster:YES];
    
    // 2.5 实体扩展模块
    _xmppCapabilitiesCoreDataStorage = [[XMPPCapabilitiesCoreDataStorage alloc] init];
    _xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:_xmppCapabilitiesCoreDataStorage];
    
    // 2.6 消息归档模块
    _xmppMessageArchivingCoreDataStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init];
    _xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_xmppMessageArchivingCoreDataStorage];
    
    // 3. 将重新连接模块添加到XMPPStream
    [_xmppReconnect activate:_xmppStream];
    [_xmppvCardModule activate:_xmppStream];
    [_xmppvCardAvatarModule activate:_xmppStream];
    [_xmppRoster activate:_xmppStream];
    [_xmppCapabilities activate:_xmppStream];
    [_xmppMessageArchiving activate:_xmppStream];
    
    // 4. 添加代理
    // 由于所有网络请求都是做基于网络的数据处理,这些数据处理工作与界面UI无关。
    // 因此可以让代理方法在其他线城中运行,从而提高程序的运行性能,避免出现应用程序阻塞的情况
    [_xmppStream addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    [_xmppRoster addDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
}

// 销毁XMPPStream并注销已注册的扩展模块
- (void)teardownStream
{
    // 1. 删除代理
    [_xmppStream removeDelegate:self];
    [_xmppRoster removeDelegate:self];
    
    // 2. 取消激活在setupStream方法中激活的扩展模块
    [_xmppReconnect deactivate];
    [_xmppvCardModule deactivate];
    [_xmppvCardAvatarModule deactivate];
    [_xmppRoster deactivate];
    [_xmppCapabilities deactivate];
    [_xmppMessageArchiving deactivate];
    
    // 3. 断开XMPPStream的连接
    [_xmppStream disconnect];
    
    // 4. 内存清理
    _xmppStream = nil;
    _xmppReconnect = nil;
    _xmppvCardModule = nil;
    _xmppvCardAvatarModule = nil;
    _xmppvCardStorage = nil;
    _xmppRoster = nil;
    _xmppRosterStorage = nil;
    _xmppCapabilities = nil;
    _xmppCapabilitiesCoreDataStorage = nil;
    _xmppMessageArchiving = nil;
    _xmppMessageArchivingCoreDataStorage = nil;
}

// 通知服务器器用户上线
- (void)goOnline
{
    // 1. 实例化一个”展现“,上线的报告,默认类型为:available
    XMPPPresence *presence = [XMPPPresence presence];
    // 2. 发送Presence给服务器
    // 服务器知道“我”上线后,只需要通知我的好友,而无需通知我,因此,此方法没有回调
    [_xmppStream sendElement:presence];
}

// 通知服务器器用户下线
- (void)goOffline
{
    // 1. 实例化一个”展现“,下线的报告
    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
    // 2. 发送Presence给服务器,通知服务器客户端下线
    [_xmppStream sendElement:presence];
}

// 连接到服务器
- (void)connect
{
    
    // 1. 如果XMPPStream当前已经连接,直接返回
    if ([_xmppStream isConnected]) {
        return;
    }
    //    在C语言中if判断真假:非零即真,如果_xmppStream==nil下面这段代码,与上面的代码结果不同。
    //    if (![_xmppStream isDisconnected]) {
    //        return;
    //    }
    
    // 2. 指定用户名、主机(服务器),连接时不需要password
    NSString *hostName = [[LoginUser sharedLoginUser] hostName];
    NSString *userName = [[LoginUser sharedLoginUser] myJIDName];
    
    // 如果没有主机名或用户名(通常第一次运行时会出现),直接显示登录窗口
//    if ([hostName isEmptyString] || [userName isEmptyString]) {
//        [self showStoryboardWithLogonState:NO];
//        
//        return;
//    }
    
    // 3. 设置XMPPStream的JID和主机
    [_xmppStream setMyJID:[XMPPJID jidWithString:userName]];
    [_xmppStream setHostName:hostName];
    
    // 4. 开始连接
    NSError *error = nil;
    [_xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error];
    
    // 提示:如果没有指定JID和hostName,才会出错,其他都不出错。
    if (error) {
        NSLog(@"连接请求发送出错 - %@", error.localizedDescription);
    } else {
        NSLog(@"连接请求发送成功!");
    }
}

#pragma mark 连接到服务器
- (void)connectWithCompletion:(CompletionBlock)completion failed:(CompletionBlock)faild
{
    // 1. 记录块代码
    _completionBlock = completion;
    _faildBlock = faild;
    
    // 2. 如果已经存在连接,先断开连接,然后再次连接
    if ([_xmppStream isConnected]) {
        [_xmppStream disconnect];
    }
    
    // 3. 连接到服务器
    [self connect];
}

// 与服务器断开连接
- (void)disconnect
{
    // 1. 通知服务器下线
    [self goOffline];
    // 2. XMPPStream断开连接
    [_xmppStream disconnect];
}

- (void)logout
{
    // 1. 通知服务器下线,并断开连接
    [self disconnect];
    
    // 2. 显示用户登录Storyboard
    [self showStoryboardWithLogonState:NO];
}

#pragma mark - 代理方法
#pragma mark 连接完成(如果服务器地址不对,就不会调用此方法)
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
    // 从系统偏好读取用户密码
    NSString *password = [[LoginUser sharedLoginUser] password];
    
    if (_isRegisterUser) {
        // 用户注册,发送注册请求
        [_xmppStream registerWithPassword:password error:nil];
    } else {
        // 用户登录,发送身份验证请求
        [_xmppStream authenticateWithPassword:password error:nil];
    }
}

#pragma mark 注册成功
- (void)xmppStreamDidRegister:(XMPPStream *)sender
{
    _isRegisterUser = NO;
    
    // 注册成功,直接发送验证身份请求,从而触发后续的操作
    [_xmppStream authenticateWithPassword:[LoginUser sharedLoginUser].password error:nil];
}

#pragma mark 注册失败(用户名已经存在)
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
{
    _isRegisterUser = NO;
    if (_faildBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _faildBlock();
        });
    }
}

#pragma mark 身份验证通过
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
    if (_completionBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _completionBlock();
        });
    }
    
    // 通知服务器用户上线
    [self goOnline];
    
    // 显示主Storyboard
    [self showStoryboardWithLogonState:YES];
}

#pragma mark 密码错误,身份验证失败
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error
{
    if (_faildBlock != nil) {
        dispatch_async(dispatch_get_main_queue(), ^{
            _faildBlock();
        });
    }
    
    // 显示用户登录Storyboard
    [self showStoryboardWithLogonState:NO];
}

#pragma mark 用户展现变化
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
    NSLog(@"接收到用户展现数据 - %@", presence);
    
    // 1. 判断接收到的presence类型是否为subscribe
    if ([presence.type isEqualToString:@"subscribe"]) {
        // 2. 取出presence中的from的jid
        XMPPJID *from = [presence from];
        
        // 3. 接受来自from添加好友的订阅请求
        [_xmppRoster acceptPresenceSubscriptionRequestFrom:from andAddToRoster:YES];
    }
}

#pragma mark 判断IQ是否为SI请求
- (BOOL)isSIRequest:(XMPPIQ *)iq
{
    NSXMLElement *si = [iq elementForName:@"si" xmlns:@"http://jabber.org/protocol/si"];
    NSString *uuid = [[si attributeForName:@"id"]stringValue];
    
    if(si &&uuid ){
        return YES;
    }
    
    return NO;
}

#pragma mark 接收请求
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
    NSLog(@"接收到请求 - %@", iq);
    
    // 0. 判断IQ是否为SI请求
    if ([self isSIRequest:iq]) {
        TURNSocket *socket = [[TURNSocket alloc] initWithStream:_xmppStream toJID:iq.to];
        
        [_socketList addObject:socket];
        
        [socket startWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    } else if ([TURNSocket isNewStartTURNRequest:iq]) {
        // 1. 判断iq的类型是否为新的文件传输请求
        // 1) 实例化socket
        TURNSocket *socket = [[TURNSocket alloc] initWithStream:sender incomingTURNRequest:iq];
        
        // 2) 使用一个数组成员记录住所有传输文件使用的socket
        [_socketList addObject:socket];
        
        // 3)添加代理
        [socket startWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    
    return YES;
}

#pragma mark 接收消息
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
    NSLog(@"接收到用户消息 - %@", message);
    
    // 1. 针对图像数据单独处理,取出数据
    NSString *imageStr = [[message elementForName:@"imageData"] stringValue];
    
    if (imageStr) {
        // 2. 解码成图像
        NSData *data = [[NSData alloc] initWithBase64EncodedString:imageStr options:NSDataBase64DecodingIgnoreUnknownCharacters];
        
        // 3. 保存图像
        UIImage *image = [UIImage imageWithData:data];
        // 4. 将图像保存到相册
        // 1) target 通常用self
        // 2) 保存完图像调用的方法
        // 3) 上下文信息
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
    }
}

#pragma mark - XMPPRoster代理
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
    NSLog(@"接收到其他用户的请求 %@", presence);
}

#pragma mark - TURNSocket代理
- (void)turnSocket:(TURNSocket *)sender didSucceed:(GCDAsyncSocket *)socket
{
    NSLog(@"成功");
    
    // 保存或者发送文件
    // 写数据方法,向其他客户端发送文件
    //    socket writeData:<#(NSData *)#> withTimeout:<#(NSTimeInterval)#> tag:<#(long)#>
    // 读数据方法,接收来自其他客户端的文件
    //    socket readDataToData:<#(NSData *)#> withTimeout:<#(NSTimeInterval)#> tag:<#(long)#>
    
    // 读写操作完成之后断开网络连接
    [socket disconnectAfterReadingAndWriting];
    
    [_socketList removeObject:sender];
}

- (void)turnSocketDidFail:(TURNSocket *)sender
{
    NSLog(@"失败");
    
    [_socketList removeObject:sender];
}

@end
//  LoginViewController.h
//  02.用户登录&注册
//


#import <UIKit/UIKit.h>

@interface LoginViewController : UIViewController

@end
//
//  LoginViewController.m
//  02.用户登录&注册
//


#import "LoginViewController.h"
#import "NSString+Helper.h"
#import "AppDelegate.h"
#import "LoginUser.h"

@interface LoginViewController () <UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet UITextField *userNameText;
@property (weak, nonatomic) IBOutlet UITextField *passwordText;
@property (weak, nonatomic) IBOutlet UITextField *hostNameText;

@property (weak, nonatomic) IBOutlet UIButton *registerButton;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;

@end

@implementation LoginViewController

#pragma mark - AppDelegate 的助手方法
- (AppDelegate *)appDelegate
{
    return [[UIApplication sharedApplication] delegate];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1. 拉伸按钮背景图片
    // 1) 登录按钮
    UIImage *loginImage = [UIImage imageNamed:@"LoginGreenBigBtn"];
  loginImage = [loginImage stretchableImageWithLeftCapWidth:loginImage.size.width * 0.5 topCapHeight:loginImage.size.height * 0.5];
    [_loginButton setBackgroundImage:loginImage forState:UIControlStateNormal];
  
    // 2) 注册按钮
    UIImage *registerImage = [UIImage imageNamed:@"LoginwhiteBtn"];
    registerImage = [registerImage stretchableImageWithLeftCapWidth:registerImage.size.width * 0.5 topCapHeight:registerImage.size.height * 0.5];
    [_registerButton setBackgroundImage:registerImage forState:UIControlStateNormal];
    
    // 2. 设置界面文本的初始值
    _userNameText.text = [[LoginUser sharedLoginUser] userName];
    _passwordText.text = [[LoginUser sharedLoginUser] password];
    _hostNameText.text = [[LoginUser sharedLoginUser] hostName];
    
    // 3. 设置文本焦点
    if ([_userNameText.text isEmptyString]) {
        [_userNameText becomeFirstResponder];
    } else {
        [_passwordText becomeFirstResponder];
    }
}

#pragma mark UITextField代理方法
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if (textField == _userNameText) {
        [_passwordText becomeFirstResponder];
    } else if (textField == _passwordText && [_hostNameText.text isEmptyString]) {
        [_hostNameText becomeFirstResponder];
    } else {
        [self userLoginAndRegister:nil];
    }
    
    return YES;
}

#pragma mark - Actions
#pragma mark 用户登录
- (IBAction)userLoginAndRegister:(UIButton *)button
{
    // 1. 检查用户输入是否完整,在商业软件中,处理用户输入时
    // 通常会截断字符串前后的空格(密码除外),从而可以最大程度地降低用户输入错误
    NSString *userName = [_userNameText.text trimString];
    // 用些用户会使用空格做密码,因此密码不能去除空白字符
    NSString *password = _passwordText.text;
    NSString *hostName = [_hostNameText.text trimString];
    
    if ([userName isEmptyString] ||
        [password isEmptyString] ||
        [hostName isEmptyString]) {
        
        UIAlertView *alter = [[UIAlertView alloc] initWithTitle:@"提示" message:@"登录信息不完整" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
        
        [alter show];
        
        return;
    }
    
    // 2. 将用户登录信息写入系统偏好
    [[LoginUser sharedLoginUser] setUserName:userName];
    [[LoginUser sharedLoginUser] setPassword:password];
    [[LoginUser sharedLoginUser] setHostName:hostName];
    
    // 3. 让AppDelegate开始连接
    // 告诉AppDelegate,当前是注册用户
    NSString *errorMessage = nil;
    
    if (button.tag == 1) {
        [self appDelegate].isRegisterUser = YES;
        errorMessage = @"注册用户失败!";
    } else {
        errorMessage = @"用户登录失败!";
    }
    
    [[self appDelegate] connectWithCompletion:nil failed:^{
        UIAlertView *alter = [[UIAlertView alloc] initWithTitle:@"提示" message:errorMessage delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
        
        [alter show];
        
        if (button.tag == 1) {
            // 注册用户失败通常是因为用户名重复
            [_userNameText becomeFirstResponder];
        } else {
            // 登录失败通常是密码输入错误
            [_passwordText setText:@""];
            [_passwordText becomeFirstResponder];
        }
    }];
}

@end
//  LoginUser.h


#import <Foundation/Foundation.h>
#import "Singleton.h"

@interface LoginUser : NSObject
single_interface(LoginUser)

@property (strong, nonatomic) NSString *userName;
@property (strong, nonatomic) NSString *password;
@property (strong, nonatomic) NSString *hostName;

@property (strong, nonatomic, readonly) NSString *myJIDName;

@end
//
//  LoginUser.m


#import "LoginUser.h"
#import "NSString+Helper.h"

#define kXMPPUserNameKey    @"admin"
#define kXMPPPasswordKey    @"admin"
#define kXMPPHostNameKey    @"127.0.0.1"

@implementation LoginUser
single_implementation(LoginUser)

#pragma mark - 私有方法
- (NSString *)loadStringFromDefaultsWithKey:(NSString *)key
{
    NSString *str = [[NSUserDefaults standardUserDefaults] stringForKey:key];
    
    return (str) ? str : @"";
}

#pragma mark - getter & setter
- (NSString *)userName
{
    return [self loadStringFromDefaultsWithKey:kXMPPUserNameKey];
}

- (void)setUserName:(NSString *)userName
{
    [userName saveToNSDefaultsWithKey:kXMPPUserNameKey];
}

- (NSString *)password
{
    return [self loadStringFromDefaultsWithKey:kXMPPPasswordKey];
}

- (void)setPassword:(NSString *)password
{
    [password saveToNSDefaultsWithKey:kXMPPPasswordKey];
}

- (NSString *)hostName
{
    return [self loadStringFromDefaultsWithKey:kXMPPHostNameKey];
}

- (void)setHostName:(NSString *)hostName
{
    [hostName saveToNSDefaultsWithKey:kXMPPHostNameKey];
}

- (NSString *)myJIDName
{
    return [NSString stringWithFormat:@"%@@%@", self.userName, self.hostName];
}

@end

 

posted @ 2015-07-16 17:02  穿山甲随笔-iOS开发  阅读(690)  评论(0编辑  收藏  举报