代码重构

1. 单例

+ (instancetype)sharedNetworkTools {
    static id instance;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });

    return instance;
}

2. 代码重构

1> 复制主方法

- (void)userLogin {
    NSString *pwd = [self timePassword];

    NSLog(@"发送的密码是 %@", pwd);

    NSURL *url = [NSURL URLWithString:@"http://localhost/loginhmac.php"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    request.HTTPMethod = @"POST";
    NSString *bodyStr = [NSString stringWithFormat:@"username=%@&password=%@", self.username, pwd];
    request.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

        id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
        NSLog(@"%@ - %@", response, result);

        if ([result[@"userId"] intValue] > 0) {
            [self saveUserInfo];
        }
    }];
}

2> 添加属性

///  用户名
@property (nonatomic, copy) NSString *username;
///  用户密码
@property (nonatomic, copy) NSString *pwd;

3> 复制相关方法

#pragma mark - 私有方法
- (NSString *)timePassword {
    // 1. 生成key
    NSString *key = @"itheima".md5String;
    NSLog(@"HMAC Key - %@", key);

    // 2. 对密码进行 hmac 加密
    NSString *pwd = [self.pwd hmacMD5StringWithKey:key];

    // 3. 获取服务器系统时间
    NSURL *url = [NSURL URLWithString:@"http://localhost/hmackey.php"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
    NSString *dateStr = dict[@"key"];
    NSLog(@"%@", dateStr);

    // 4. 将系统时间拼接在第一次加密密码的末尾
    pwd = [pwd stringByAppendingString:dateStr];

    // 5. 返回拼接结果的再次 hmac
    return [pwd hmacMD5StringWithKey:key];
}

#pragma mark - save & load user info
#define HMUsernameKey @"HMUsernameKey"
#define HMUserPasswordKey @"HMUserPasswordKey"
///  保存用户信息
- (void)saveUserInfo {

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    // iOS 8.0 会直接写入沙盒,无需再使用 `[defaults synchronize];`
    [defaults setObject:self.username forKey:HMUsernameKey];

    // 将用户密码保存在钥匙串
    NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
    [SSKeychain setPassword:self.pwd forService:bundleId account:self.username];
}

4> 开放主方法

/// 用户登录
- (void)userLogin;

5> 在 AppDelegate 中调用用户登录

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 用户登录
    [[NetworkTools sharedNetworktools] userLogin];

    return YES;
}

运行测试,发现没有加载用户信息

6> 复制加载用户信息方法

///  加载用户下信息
- (void)loadUserInfo {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    self.username = [defaults stringForKey:HMUsernameKey];

    NSLog(@"%@", [SSKeychain allAccounts]);
    NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
    self.pwd = [SSKeychain passwordForService:bundleId account:self.username];
}

7> 在 单例 方法中加载用户信息

+ (instancetype)sharedNetwrokTools {
    static id instance;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        [instance loadUserInfo];
    });
    return instance;
}

8> 增加判断,如果没有用户信息直接返回

- (void)userLogin {

    if (self.pwd == nil || self.username == nil) {
        return;
    }

9> 切换界面

  • 定义通知字符串
#define HMUserLoginStatusChangedNotification @"HMUserLoginStatusChangedNotification"
  • 登录成功发布通知
// 发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:HMUserLoginStatusChangedNotification object:@"Main"];
  • 注册通知
// 注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginStatusChanged:) name:HMUserLoginStatusChangedNotification object:nil];
  • 登录状态变化更改界面
- (void)loginStatusChanged:(NSNotification *)n {
    UIStoryboard *sb = [UIStoryboard storyboardWithName:n.object bundle:nil];
    self.window.rootViewController = sb.instantiateInitialViewController;
}
  • 用户注销
- (IBAction)logout:(id)sender {
    [[NSNotificationCenter defaultCenter] postNotificationName:HMUserLoginStatusChangedNotification object:@"Login"];
}

10> 调整登录视图控制器

#import "NetworkTools.h"

@interface ViewController () <UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet UITextField *usernameText;
@property (weak, nonatomic) IBOutlet UITextField *pwdText;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self loadUserInfo];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if (textField == self.usernameText) {
        [self.pwdText becomeFirstResponder];
    } else {
        [self userLogin];
    }
    return YES;
}

- (IBAction)userLogin {
    NetworkTools *tools = [NetworkTools sharedNetwrokTools];

    tools.username = self.usernameText.text;
    tools.pwd = self.pwdText.text;

    [tools userLogin];
}

#pragma mark - save & load user info
///  加载用户下信息
- (void)loadUserInfo {
    NetworkTools *tools = [NetworkTools sharedNetwrokTools];

    self.usernameText.text = tools.username;
    self.pwdText.text = tools.pwd;
}

11> 失败回调

  • 修改登录方法
///  用户登录
- (void)userLoginFailed:(void (^)())failed;
  • 增加回调代码
if (failed) {
    failed();
}
  • 修改调用代码
[tools userLoginFailed:^{
    [[[UIAlertView alloc] initWithTitle:@"提示" message:@"用户名或密码错误" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
}];

12> 取消默认启动控制器

  • 实例化 windows
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
  • 修改登录方法
[[NetworkTools sharedNetwrokTools] userLoginFailed:^{
    NSNotification *n = [NSNotification notificationWithName:HMUserLoginStatusChangedNotification object:@"Login"];
    [self loginStatusChanged:n];
}];

其他

  • 通知方法执行所在线程与发布通知的线程一致
  • extern 定义字符串常量更安全,是绝大多数 C 语言程序采用的解决方案
///  用户状态变化通知
extern NSString * const HMUserLoginStatusChangedNotification;

NSString * const HMUserLoginStatusChangedNotification = @"HMUserLoginStatusChangedNotification";

results matching ""

    No results matching ""