从0到1---“保多多”APP的开发(一)

时间:2022-11-09 21:16:14

2015年8月份,我正式接手了公司保多多APP的开发(和另一个同事一起)。

我之前并没有过从0开始创建一款APP,这次能有这样的机会,实在让我感到兴奋。因为我相信,作为这款APP的主要开发人员,在这一过程中我一定能学到太多我之前没有接触过的技术。而且从目前的进度来看,我的想法没有错。今天我主要想记录一些开发这款APP的心得,虽然APP尚未完成,但确实感触颇多。
以下内容均为最新版xcode6.4上的

首先,我们创建一个程序的启动界面,就是你点击一个APP后看到的一个界面,这个界面一般是一张关于APP的背景图,APP的名称以及版权所属公司。我们可以在LaunchScreen.xib中用UIImageView和一些label完成这个界面。

启动界面之后,我们便可以进入Main.storyboard,这是程序的主入口,一般这个里面是写用户登录的信息。在保多多中,这个界面是让用户填写登录名和密码的(也有忘记密码的按钮)。可以在stroyboard里面添加多个视图控制器,并实现它们之间的跳转关系,但是在保多多中我们没有这么做。我们只在其中添加了一个视图控制器,命名为SignInViewController。注意这里要同时在工程中创建一个同名的类,在这个类中实现逻辑代码,要注意的是,在stroyboard中要将该视图控制器与SignInViewController这个类相关联。在SignInViewController类中,我们要实现用户输入用户名和密码后的登录,核心代码:

- (void) signInAction {
    if ([self.userNameText.text isEqualToString:@""]) {
        [self showAlertView:@"用户名不能为空"];
        return;
    }

    if ([self.passwordText.text isEqualToString:@""]) {
        [self showAlertView:@"密码不能为空"];
        return;
    }

    [NetworkUtil signInApplicationWithUsername:self.userNameText.text andPassword:self.passwordText.text onSuccess:^(BOOL successful, NSDictionary *message) {
        //NSLog(@"message:%@",message);
        NSDictionary *resultMes = message[@"resultMessage"];
        NSString *errorMes = resultMes[@"errorMessage"];
        ) {
            [self showAlertView:errorMes];
            return ;
        }
        NSDictionary *data = message[@"data"];
        NSString *ID = data[@"UserID"];
        User *user;
        if (ID) {
            user = [[User alloc] initWithID:ID];
        }

        //属性设置
        [user setValuesForKeysWithDictionary:data];

        self.easeInsurance.user = user;

        NSUserDefaults *uds = [NSUserDefaults standardUserDefaults];
        [uds setObject:self.userNameText.text forKey:UserDefaults_USERNAME];
        [uds setObject:self.passwordText.text forKey:UserDefaults_PASSWORD];
        [uds synchronize];

        [self.navigationController pushViewController:self.easeInsurance.mainTabBarController animated:YES];

    } onFailure:^(NSError *error) {
    }];
}

填写完用户名和密码之后,我们用一个网络请求来判断二者是否一致,如果不一致就返回错误信息,如果一致就登录成功,跳转到mainTabBarController。那么问题来了,这个mainTabBarController在哪里在什么时候初始化的?

原来,在项目中有一个AppDelegate类,程序执行时这里面的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

rerurn YES;
}方法会最先执行,在保多多中,我们在这个类里面加了个方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [[EaseInsurance instance] launchService];
    return YES;
}

这里的EaseInsurance又是什么?这个EaseInsurance类,我们称它为公共服务类,并将它设计为单例,里面放一些全局的变量并进行一些初始化工作。全局的变量有:

@property (retain) User *user;//User类,代表着用户,里面有用户所有的信息
@property (retain) UITabBarController *mainTabBarController;//分栏控制器
@property (retain) UIColor *mainColor;//APP中用到的主要的颜色
@property (assign) CGSize kScreenSize;//动态获取设备尺寸
@property (retain) NSMutableDictionary* htmlDict;//存放程序中所有的h5接口

这样,我们就明白了,我们是在AppDelegate类中,调用EaseInsurance的launchService方法,从而完成程序的一些初始化工作,而具体的初始化方法分为两个:

- (void)initializeAppearance {
    self.mainColor = [UIColor colorWithRed:];
    [[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor whiteColor]}];
    [UINavigationBar appearance].backgroundColor = self.mainColor;
    [[UINavigationBar appearance] setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    self.kScreenSize = [UIScreen mainScreen].bounds.size;
}
- (void)initializeMainTabBarController {

    NSDictionary *selectedTitleAttributes = @{NSForegroundColorAttributeName: self.mainColor};
    QuotationViewController *quotation = [[QuotationViewController alloc] initWithNibName:@"QuotationViewController" bundle:[NSBundle mainBundle]];
    quotation.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"报价" image:[[UIImage imageNamed:@"HomepageIcon"]     imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]selectedImage:[[UIImage imageNamed:@"HomepageSelectedIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
    [quotation.tabBarItem setTitleTextAttributes:selectedTitleAttributes forState:UIControlStateSelected];
    CarsManagementViewController *carsManagement = [[CarsManagementViewController alloc] initWithNibName:@"CarsManagementViewController" bundle:[NSBundle mainBundle]];
    carsManagement.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"车辆" image:[[UIImage imageNamed:@"CarsIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] selectedImage:[[UIImage imageNamed:@"CarsSelectedIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
    [carsManagement.tabBarItem setTitleTextAttributes:selectedTitleAttributes forState:UIControlStateSelected];
    ActivityViewController *activity = [[ActivityViewController alloc] initWithNibName:@"ActivityViewController" bundle:[NSBundle mainBundle]];
    activity.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"活动" image:[[UIImage imageNamed:@"ActivityIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] selectedImage:[[UIImage imageNamed:@"ActivitySelectedIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
    [activity.tabBarItem setTitleTextAttributes:selectedTitleAttributes forState:UIControlStateSelected];
    MineViewController *mine = [[MineViewController alloc] initWithNibName:@"MineViewController" bundle:[NSBundle mainBundle]];
    mine.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"我" image:[[UIImage imageNamed:@"MineIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] selectedImage:[[UIImage imageNamed:@"MineSelectedIcon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
    [mine.tabBarItem setTitleTextAttributes:selectedTitleAttributes forState:UIControlStateSelected];
    self.mainTabBarController = [[UITabBarController alloc] init];
    self.mainTabBarController.tabBar.tintColor = [UIColor clearColor];
    self.mainTabBarController.viewControllers = @[quotation, carsManagement, activity, mine];
}

我们可以很清楚的看到,第一个方法主要设置一些颜色和大小,第二个方法是用来创建mainTabBarController。这一切都完成之后,我们点击SignInViewController类的登录按钮,便可以进入mainTabBarController,进入后展现在我们面前的就是mainTabBarController的第一个视图控制器QuotationViewController(首页)。

进入保多多APP后主要分为4个板块:QuotationViewController(首页),CarsManagementViewController(车辆),ActivityViewController(活动),MineViewController(我)

这四个类都是继承与一个ViewController类,这样它们就都有了一个easeInsurance属性,这个属性是整个程序中唯一的,公用的。现在ViewController类中暂时没有其他的,就这一个属性,继承了这个类后都可以获得这个属性。以后我们可能加一些其他的属性或方法进去,看需要吧。

说到APP的登录,还有一点要补充,我们都知道,现在很多APP都有快速登录的功能,就是说只要你没有点击退出登录或者注销什么的按钮,你退出程序后,再次进入就不用再次输入用户名密码了,可以直接进入APP。我们的保多多也做了这样的功能。用法很简单,在用户第一次登录时,我们用 NSUserDefaults将用户名和密码保存,当用户再次打开APP时,我们先从 NSUserDefaults中取用户名和密码,然后判断:if(userName&&userPassword),如果不为空,再做类似于SignInViewController中的网络请求,没有错误的话那么直接进入,否则就无法进入。这个方法也是写在EaseInsurance的launchService方法中,因为这里是整个程序最先执行的,如果能直接进入,那么Main.storyboard便不再加载出来。

接下来我还想说说点击退出登录按钮会执行哪些方法:

-(void) clickLogout{
    self.easeInsurance.user = nil;
    NSUserDefaults *uds = [NSUserDefaults standardUserDefaults];
    [uds removeObjectForKey:UserDefaults_USERNAME];//删除本地用户的信息
    [uds removeObjectForKey:UserDefaults_PASSWORD];
    [uds synchronize];
    [self.navigationController popToRootViewControllerAnimated:NO];
    self.easeInsurance.mainTabBarController.selectedIndex = ;//这个细节也要注意
}

可以看到每次退出登录都会将self.easeInsurance.user赋空,所以我们每次无论是普通登录还是快速登录都要在进入之前(登录的网络请求成功之后)创建一个新的User对象,并将网络请求返回的用户的信息赋给它,在将这个User赋给EaseInsurance的user属性。

好了,今天的保多多APP心得就告一段落了,项目还在进行中,以后有了新的想法还会继续更新,敬请期待!