上一篇博客 开源中国iOS客户端学习——(十一)AES加密中提到将用户名和密码保存到了本地沙盒之中,在从本地读取用户名和密码,这是一个怎样的过程?
1
2
3
4
5
6
7
8
9
10
|
-(
void
)saveUserNameAndPwd:(NSString *)userName andPwd:(NSString *)pwd
{
NSUserDefaults * settings = [NSUserDefaults standardUserDefaults];
[settings removeObjectForKey:@
"UserName"
];
[settings removeObjectForKey:@
"Password"
];
[settings setObject:userName forKey:@
"UserName"
];
pwd = [AESCrypt encrypt:pwd password:@
"pwd"
];
[settings setObject:pwd forKey:@
"Password"
];
[settings synchronize];
}
|
上面的方法使用了NSUserDefaults类,它也是以字典形式实现对数据功能,并将这些数据保存到本地应用程序沙盒之中,这种方法适合保存较小的数据,例如用户登陆配置信息;这段代码首先是定义了一个对象,进行初始化,移除键值为UseName和Password的对象,防止数据混乱造成干扰;然后就是重新设置键值信息; [settings synchronize];将键值信息同步道本地;
现在我们道沙盒中来看看这个用户配置信息
首先查看应用程序沙盒的路径 ,使用
NSString *homeDirectory = NSHomeDirectory(); NSLog(@"path:%@", homeDirectory);
打印结果: path:/Users/DolBy/Library/Application Support/iPhone Simulator/5.1/Applications/55C49712-AD95-49E0-B3B9-694DC7D26E94
但是在我的DolBy用户下并没有Library这个目录,这是因为系统隐藏了这些文件目录,现在需要显示这些隐藏的文件,打开终端输入 defaults write com.apple.finder AppleShowAllFiles -bool true 回车,然后重启Finder(不会?请看 查看iOS沙盒(SanBox)文件),找到55C49712-AD95-49E0-B3B9-694DC7D26E94目录下的Library/Preferences下的 net.oschina.iosapp.plist文件,将其打开
从中不难看出保存在本地沙盒中用户的一些基本信息,以及一些配置信息,还记录一些上次获取数据时间等等;
登陆类在Setting目录下的loginView类,先看看loginView.xib吧,界面比较简陋,可能是缺美工吧;
从头文件中声明部分
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
|
#import <UIKit/UIKit.h>
#import "Tool.h"
#import "ProfileBase.h"
#import "MessageView.h"
#import "Config.h"
#import "MBProgressHUD.h"
#import "MyThread.h"
@interface LoginView : UIViewController<UIWebViewDelegate>
{
// ASI类库,获取网络请求,进行登陆验证
ASIFormDataRequest *request;
}
//接受用户名输入
@property (strong, nonatomic) IBOutlet UITextField *txt_Name;
//接受用户属于密码
@property (strong, nonatomic) IBOutlet UITextField *txt_Pwd;
//开关按钮,设置用户是否要记住用户名和密码
@property (strong, nonatomic) IBOutlet UISwitch *switch_Remember;
//标记作用,用于记录请求数据返回异常或错误时是否弹出一个警告
@property
BOOL
isPopupByNotice;
//webView,布局一个手机上的web网页,显示说明信息,在这个web页面有富文本使用,直接可以跳转到url上
@property (strong, nonatomic) IBOutlet UIWebView *webView;
//登陆处理
- (IBAction)click_Login:(id)sender;
//取消两个textFile的第一响应对象
- (IBAction)textEnd:(id)sender;
//取消键盘第一响应对象,点击页面推出键盘
- (IBAction)backgrondTouch:(id)sender;
//根据返回的数据保存用户名和用户ID到本地
- (
void
)analyseUserInfo:(NSString *)xml;
@end
|
在实现文件里,粘贴上主要方法代码
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
|
- (
void
)viewDidLoad
{
[super viewDidLoad];
[Tool clearWebViewBackground:webView];
[self.webView setDelegate:self];
self.navigationItem.title = @
"登录"
;
//决定是否显示用户名以及密码
NSString *name = [Config Instance].getUserName;
NSString *pwd = [Config Instance].getPwd;
// 如果用户名和密码存在,且不为空,取出付给相应text
if
(name && ![name isEqualToString:@
""
]) {
self.txt_Name.text = name;
}
if
(pwd && ![pwd isEqualToString:@
""
]) {
self.txt_Pwd.text = pwd;
}
UIBarButtonItem *btnLogin = [[UIBarButtonItem alloc] initWithTitle:@
"登录"
style:UIBarButtonItemStyleBordered target:self action:@selector(click_Login:)];
self.navigationItem.rightBarButtonItem = btnLogin;
self.view.backgroundColor = [Tool getBackgroundColor];
self.webView.backgroundColor = [Tool getBackgroundColor];
// web控件上信息
NSString *html = @
"<body style='background-color:#EBEBF3'>1, 您可以在 <a href='http://www.oschina.net'>http://www.oschina.net</a> 上免费注册一个账号用来登陆<p />2, 如果您的账号是使用OpenID的方式注册的,那么建议您在网页上为账号设置密码<p />3, 您可以点击 <a href='http://www.oschina.net/question/12_52232'>这里</a> 了解更多关于手机客户端登录的问题</body>"
;
[self.webView loadHTMLString:html baseURL:nil];
self.webView.hidden = NO;
}
在 [Tool clearWebViewBackground:webView];作用描述不好,直接看方法
+ (
void
)clearWebViewBackground:(UIWebView *)webView
{
UIWebView *web = webView;
for
(id v in web.subviews) {
if
([v isKindOfClass:[UIScrollView
class
]]) {
[v setBounces:NO];
}
}
}
|
[v setBounces:NO]; 如果[v setBounces:YES]; 滚动上下滚动是出现空隙,不美观,为NO 时就不会;
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
|
- (IBAction)click_Login:(id)sender
{
// 获取用户名和密码
NSString *name = self.txt_Name.text;
NSString *pwd = self.txt_Pwd.text;
// 使用ASI类库请求登陆API,
request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:api_login_validate]];
[request setUseCookiePersistence:YES];
[request setPostValue:name forKey:@
"username"
];
[request setPostValue:pwd forKey:@
"pwd"
];
[request setPostValue:@
"1"
forKey:@
"keep_login"
];
[request setDelegate:self];
// 失败调用 requestFailed:
[request setDidFailSelector:@selector(requestFailed:)];
// 成功调用 equestLogin:
[request setDidFinishSelector:@selector(requestLogin:)];
// 开始请求
[request startAsynchronous];
// 动画提示用户等待
request.hud = [[MBProgressHUD alloc] initWithView:self.view];
[Tool showHUD:@
"正在登录"
andView:self.view andHUD:request.hud];
}
// 登陆失败,隐藏显示的动画
- (
void
)requestFailed:(ASIHTTPRequest *)request
{
if
(request.hud) {
[request.hud hide:YES];
}
}
|
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
59
60
61
62
63
64
|
- (
void
)requestLogin:(ASIHTTPRequest *)request
{
if
(request.hud) {
[request.hud hide:YES];
}
// 根据请求回来的xml进行解析数据,判断是否登陆成功
[Tool getOSCNotice:request];
// 将请求回来的信息保存在客户端
[request setUseCookiePersistence:YES];
ApiError *error = [Tool getApiError:request];
if
(error == nil) {
[Tool ToastNotification:request.responseString andView:self.view andLoading:NO andIsBottom:NO];
}
switch
(error.errorCode) {
case
1:
{
[[Config Instance] saveCookie:YES];
if
(isPopupByNotice == NO)
{
NSUserDefaults *d= [NSUserDefaults standardUserDefaults];
[self.navigationController popViewControllerAnimated:YES];
}
//处理是否记住用户名或者密码
if
(self.switch_Remember.isOn)
{
[[Config Instance] saveUserNameAndPwd:self.txt_Name.text andPwd:self.txt_Pwd.text];
}
//否则需要清空用户名于密码
else
{
[[Config Instance] saveUserNameAndPwd:@
""
andPwd:@
""
];
}
//返回的处理
if
([Config Instance].viewBeforeLogin)
{
if
([[Config Instance].viewNameBeforeLogin isEqualToString:@
"ProfileBase"
])
{
ProfileBase *_parent = (ProfileBase *)[Config Instance].viewBeforeLogin;
_parent.isLoginJustNow = YES;
}
}
//开始分析 uid 等等信息
[self analyseUserInfo:request.responseString];
//分析是否需要退回
if
(self.isPopupByNotice) {
[self.navigationController popViewControllerAnimated:YES];
}
// 查看startNotice方法可知是一个定时器,每隔60s刷新一下用户信息,是否有新的粉丝或几条评论
[[MyThread Instance] startNotice];
}
break
;
case
0:
case
-1:
{
// 返回 当error.errorCode =0 || 1的时候,显示相关错误信息
[Tool ToastNotification:[NSString stringWithFormat:@
"错误 %@"
,error.errorMessage] andView:self.view andLoading:NO andIsBottom:NO];
}
break
;
}
}
|
ApiError 这个类看起来可能很迷惑人,它并不完全像字面意思那样指的是错误的api信息,而是根据请求返回来的数字进行判断。如果error.errorCode = 1表示成功返回了用户的数据,0,-1就可能由于服务器网络等原因不能正确返回数据;
在ApiError *error = [Tool getApiError:request];中,打印 request.responseString如下,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
oschina
>
<
result
>
<
errorCode
>1</
errorCode
>
<
errorMessage
>
<![CDATA[登录成功]]>
</
errorMessage
>
</
result
>
<
user
>
<
uid
>112617</
uid
>
<
location
>
<![CDATA[河南 南阳]]>
</
location
>
<
name
>
<![CDATA[新风作浪]]>
</
name
>
<
followers
>1</
followers
>
<
fans
>0</
fans
>
<
score
>1</
score
>
<
portrait
>http://static.oschina.net/uploads/user/56/112617_100.jpg?t=1350377690000</
portrait
>
</
user
>
<
notice
>
<
atmeCount
>0</
atmeCount
>
<
msgCount
>0</
msgCount
>
<
reviewCount
>0</
reviewCount
>
<
newFansCount
>0</
newFansCount
>
</
notice
>
</
oschina
>
<!-- Generated by OsChina.NET (init:3[ms],page:3[ms],ip:61.163.231.198) -->
|
在 [self analyseUserInfo:request.responseString]方法中, 根据请求成功返回的xml,解析用户名和UID,保存用户的UID
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
- (
void
)analyseUserInfo:(NSString *)xml
{
@
try
{
TBXML *_xml = [[TBXML alloc] initWithXMLString:xml error:nil];
TBXMLElement *root = _xml.rootXMLElement;
TBXMLElement *user = [TBXML childElementNamed:@
"user"
parentElement:root];
TBXMLElement *uid = [TBXML childElementNamed:@
"uid"
parentElement:user];
//获取uid
[[Config Instance] saveUID:[[TBXML textForElement:uid] intValue]];
}
@
catch
(NSException *exception) {
[NdUncaughtExceptionHandler TakeException:exception];
}
@finally {
}
}
|
在后面也看到[[MyThread Instance] startNotice];看看startNotice方法,是一个定时器,每隔60s刷新一下用户信息,是否有新的粉丝或几条评论;
1
2
3
4
5
6
7
8
9
10
|
-(
void
)startNotice
{
if
(isRunning) {
return
;
}
else
{
timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
isRunning = YES;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
-(
void
)timerUpdate
{
NSString * url = [NSString stringWithFormat:@
"%@?uid=%d"
,api_user_notice,[Config Instance].getUID];
[[AFOSCClient sharedClient]getPath:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[Tool getOSCNotice2:operation.responseString];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
}
|
url请求获取返回的信息(已经登陆情开源中国社区网站的况下)
1
2
3
4
5
6
7
8
9
10
11
|
<
oschina
>
<
notice
>
<
atmeCount
>0</
atmeCount
>
<
msgCount
>0</
msgCount
>
<
reviewCount
>0</
reviewCount
>
<
newFansCount
>0</
newFansCount
>
</
notice
>
</
oschina
>
<!--
Generated by OsChina.NET (init:1[ms],page:1[ms],ip:61.163.231.198)
-->
|
关于本文提到的几个动画过渡显示效果请看
[Tool showHUD:@"正在登录" andView:self.view andHUD:request.hud]; MBProgressHUD特效
[Tool ToastNotification:[NSString stringWithFormat:@"错误 %@",error.errorMessage] andView:self.view andLoading:NO andIsBottom:NO]; GCDiscreetNotificationView提示视图
开源中国iOS客户端源码下载地址: http://git.oschina.net/oschina/iphone-app
本文转自新风作浪 51CTO博客,原文链接:http://blog.51cto.com/duxinfeng/1206850,如需转载请自行联系原作者