项目总结:框架

本文详细介绍了一个iOS应用的整体布局方案,包括授权流程、版本检查、主框架搭建及子控制器的初始化过程。此外,还介绍了如何通过继承和封装来简化重复代码,提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 整体布局:
     if(未授权){
          加载授权WabView(保存授权信息到本地沙盒) —>授权完成显示主页
        //沙盒路径
        NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
        NSString *path = [doc stringByAppendingPathComponent:@"account.archive"];
//        NSLog(@"%@",path);
        //将返回的账号数据 --> 模型再存到沙盒
        MCAccountModel *account =  [MCAccountModelaccountWithDic:responseObject];
        //要想把对象写进沙盒就要用到 NSKeyedArchiver 这个类不能在使用writeToFile的方法
        [NSKeyedArchiverarchiveRootObject:account toFile:path];
//        [responseObject writeToFile:path atomically:YES];

}else{
          if(根据沙盒路径下保存的新版本信息判断是否是新版本){
    NSString *key = @"CFBundleVersion";
   
//1.获取上一次的软件版本(沙盒中)
    NSString *lastVersion = [[NSUserDefaultsstandardUserDefaults] objectForKey:key];
    //2.获取当前版本(info.plist文件中)
    NSString *currentVersion = [NSBundlemainBundle].infoDictionary[key];
    UIWindow *window = [UIApplicationsharedApplication].keyWindow ;
    if ([currentVersion isEqualToString:lastVersion]) {
        window.rootViewController = tabBar;
    }else{
        window.rootViewController = [[NewFeatureViewControlleralloc]init];
       
//3.将新版本号存入沙盒
        [[
NSUserDefaultsstandardUserDefaults] setObject:currentVersion forKey:key];
        [[
NSUserDefaultsstandardUserDefaults]synchronize];
    }
               显示“新特性界面”(更新沙盒路径下保存的新版本)—>主页
          }else{
               直接显示主页
          }
}
在这里,保存到沙盒路径下的模型类需要说明一下,涉及到对象的归档和解档
#import "MCAccountModel.h"
@implementation MCAccountModel
+(instancetype)accountWithDic:(NSDictionary *)dic{
    MCAccountModel *account = [[selfalloc]init];
    account.access_token = [dic objectForKey:@"access_token"];
    account.expires_in = [dic objectForKey:@"expires_in"];
    account.uid = [dic objectForKey:@"uid"];
    return account;
}
/**
 * 
当一个对象要归档到沙盒中时要调用到这个方法*
 * 
目的:在这个方法中说明对象的那些属性要存进沙盒
 */
-(void)encodeWithCoder:(NSCoder *)encoder{
    [encoder encodeObject:self.access_tokenforKey:@"access_token"];
    [encoder
encodeObject:self.expires_inforKey:@"expires_in"];
    [encoder encodeObject:self.uidforKey:@"uid"];
}
/**
 * 
当一个对象要从沙盒中解档时要调用到这个方法
 * 
目的:在这个方法中说明对象的那些属性要从沙盒中解档
 */
-(instancetype)initWithCoder:(NSCoder *)decoder{
    if (self = [superinit]) {
       
self.access_token = [decoder decodeObjectForKey:@"access_token"];
       
self.expires_in = [decoder decodeObjectForKey:@"expires_in"];
        self.uid = [decoder decodeObjectForKey:@"uid"];
    }
   
returnself;
}
@end
二 主框架 :

     主要的框架结构是 : 一个标签控制器下四个由导航控制器控制的ViewController,这里方法是将标签控制器子类化MCBaseTabBarController
     
- (void)viewDidLoad {
    [
superviewDidLoad];
   
//初始化子控制器
   
// 1.初始化子控制器
   
HomeViewController *home = [[HomeViewControlleralloc] init];
    [selfaddChildVc:home title:@"首页"image:@"tabbar_home"selectedImage:@"tabbar_home_selected"];
    MassageViewController *messageCenter = [[MassageViewControlleralloc] init];
    [selfaddChildVc:messageCenter title:@"消息"image:@"tabbar_message_center"selectedImage:@"tabbar_message_center_selected"];
    DiscoverViewController *discover = [[DiscoverViewControlleralloc] init];
    [selfaddChildVc:discover title:@"发现"image:@"tabbar_discover"selectedImage:@"tabbar_discover_selected"];
    MyinfoViewController *profile = [[MyinfoViewControlleralloc] init];
    [selfaddChildVc:profile title:@""image:@"tabbar_profile"selectedImage:@"tabbar_profile_selected"];
    MCTabBar *tabBar = [[MCTabBaralloc]init];
    tabBar.delegate = self;
   
//系统只读模式的属性我们可以用KVC赋值
    [
selfsetValue:tabBar forKeyPath:@"tabBar"];
}
-(void)viewWillAppear:(BOOL)animated{
    [superviewWillAppear:animated];
}
- (
void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage
{
   
// 设置子控制器的文字
    childVc.title = title; // 同时设置tabbarnavigationBar的文字
    // 设置子控制器的图片
    childVc.
tabBarItem.image = [UIImageimageNamed:image];
    childVc.tabBarItem.selectedImage = [[UIImageimageNamed:selectedImage]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    // 设置文字的样式
   
NSMutableDictionary *textAttrs = [NSMutableDictionarydictionary];
    textAttrs[
NSForegroundColorAttributeName] = MCColor(123, 123, 123);
   
NSMutableDictionary *selectTextAttrs = [NSMutableDictionarydictionary];
    selectTextAttrs[
NSForegroundColorAttributeName] = [UIColororangeColor];
    [childVc.
tabBarItemsetTitleTextAttributes:textAttrs forState:UIControlStateNormal];
    [childVc.tabBarItemsetTitleTextAttributes:selectTextAttrs forState:UIControlStateSelected];
    // 先给外面传进来的小控制器包装一个导航控制器
   
MCBaseNavigationController *nav = [[MCBaseNavigationControlleralloc] initWithRootViewController:childVc];
   
// 添加为子控制器
    [
selfaddChildViewController:nav];
}
     在上面过程中标签控制器的tabBar 是根据需求自定义的样式

- (instancetype)initWithFrame:(CGRect)frame
{
   
self = [superinitWithFrame:frame];
    if (self) {
        UIButton *plusBtn = [[UIButtonalloc]init];
        [plusBtn addTarget:selfaction:@selector(plusBtnClick:) forControlEvents:UIControlEventTouchUpInside];
        [plusBtn setBackgroundImage:[UIImageimageNamed:@"tabbar_compose_button"] forState:UIControlStateNormal];
        [plusBtn
setBackgroundImage:[UIImageimageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];
        [plusBtn
setImage:[UIImageimageNamed:@"tabbar_compose_icon_add"] forState:UIControlStateNormal];
        [plusBtn setImage:[UIImageimageNamed:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted];
        plusBtn.size = plusBtn.currentBackgroundImage.size;
        self.plusBtn = plusBtn;
        [selfaddSubview:plusBtn];
    }
   
returnself;
}
通常需要重新布局系统控件时,都要复写这个方法来给系统的控件重新布局
-(void)layoutSubviews{
    [superlayoutSubviews];
    //1.设置加号按钮的尺寸
   
self.plusBtn.centerX = self.width * 0.5;
    self.plusBtn.centerY = self.height * 0.5;
    //2.设置其他控件的尺寸
   
CGFloat tabBarItemWith = self.width/5;
   
int index = 0;
    for (UIView *view inself.subviews) {
        Class class = NSClassFromString(@"UITabBarButton");
        if ([view isKindOfClass:class]) {
            view.
width = tabBarItemWith;
            view.
x = tabBarItemWith * index;
            index ++;
            if (index == 2) {
                index ++;
            }
        }
    }   
}
三 模块共同属性和特点统一设置
     通常同一款应用不同的界面会有相似的属性,我们把这些属性统一设置在一个父类当中,也就是子类化一个公共的父类,这样就会减少很多代码量
比如:每个模块的导航栏左右两个按钮都是相同的,并且每个模块中pushi出来的视图的导航栏中的按钮也是相同的,并且每个模块pushi出来的VIewController的标签栏都是隐藏的,总结出这些共同属性接下来就着手在父类中去实现这些属性就可以了,当用到这些属性时只需要基于这个父类 (MCBaseNavigationController)创建类就可以了
     UIBarButtonItem 在创建时(不管以什么方式创建)都会实现这个类方法,所以复写这个类方法,并添加共有属性
+ (void)initialize
{
   
//设置整个项目中的item主题样式
    UIBarButtonItem *item = [UIBarButtonItemappearance];
    //设置普通状态
   
// keyNS****AttributeName
    NSMutableDictionary *textAttrs = [NSMutableDictionarydictionary];
    textAttrs[NSForegroundColorAttributeName] = [UIColororangeColor];
    textAttrs[NSFontAttributeName] = [UIFontsystemFontOfSize:13];
    [item setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
    //设置不可用状态
    NSMutableDictionary *disableTextAttrs = [NSMutableDictionarydictionary];
    disableTextAttrs[NSForegroundColorAttributeName] = [UIColorcolorWithRed:0.6green:0.6blue:0.6alpha:0.7];
    disableTextAttrs[NSFontAttributeName] = [UIFontsystemFontOfSize:13];
    [item setTitleTextAttributes:disableTextAttrs forState:UIControlStateDisabled];
}
/**
 *   * 
重写这个方法的目的:能够拦截所有Push进来的控制器
 *  @param viewController
即将push进来的控制器
 */
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    if (self.viewControllers.count > 0) {//这时pushi进来的控制器 viewController,不是第一个自控制器 (不是跟控制器)
       
/* 自动显示和隐藏tabbar */
        viewController.hidesBottomBarWhenPushed = YES;
        /* 设置导航栏上面的内容 */
        //设置左侧按钮
        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItemitemWithTarget:selfaction:@selector(back) image:@"navigationbar_back"highImage:@"navigationbar_back_highlighted"];
        //设置右侧按钮
        viewController.
navigationItem.rightBarButtonItem = [UIBarButtonItemitemWithTarget:selfaction:@selector(more) image:@"navigationbar_more"highImage:@"navigationbar_more_highlighted"];
    }
    [superpushViewController:viewController animated:animated];
}
-(void)back{
    [selfpopViewControllerAnimated:YES];
}
-(void)more{
    [selfpopToRootViewControllerAnimated:YES];
}
四 控件的封装
     项目中某些模块的控件需要实现复杂的功能,并且整个项目中有多个模块用到该控件,那么就要实现控件的封装,比如:首页(Home)的标题点击实现下拉菜单的功能,上述tabBar的封装,发现(Search)的搜索框都可以单独封装使用。
     下拉菜单
#import "MCTitleMenuView.h"

@interfaceMCTitleMenuView ()
{
   
UIImageView *_menuView;
}
@end
@implementation MCTitleMenuView
+(instancetype)menu{
    return [[selfalloc]init];
}
-(void)showSelf:(UIButton*)btn{
    //1.获取最上面的窗口
    UIWindow *window = [[UIApplicationsharedApplication].windowslastObject];
    //2.添加自己到窗口
    [window addSubview:self];
    //3.设置尺寸
    self.frame = window.bounds;
    self.backgroundColor = [UIColorclearColor];
    self.userInteractionEnabled = YES;
    _menuView = [[UIImageViewalloc]initWithFrame:CGRectMake(20, 80, 200, 300)];
    //调节下拉菜单的位置
   
CGRect newRect = [btn convertRect:btn.boundstoView:nil];
    _menuView.centerX = btn.centerX;
    _menuView.y = newRect.origin.y + btn.height;
    _menuView.userInteractionEnabled = YES;
    if (_content) {
       
self.content.frame = CGRectMake(15, 25, _menuView.width - 30, _menuView.height - 40);
        _content.layer.cornerRadius = 5;
        [_menuViewaddSubview:_content];
    }
    _menuView.image = [UIImageimageNamed:@"popover_background"];
    [selfaddSubview:_menuView];
}
-(void)dismis{
    [_menuViewremoveFromSuperview];
    [selfremoveFromSuperview];
}
-(
void)setContent:(UIView *)content{
   
_content = content;
}
-(void)setShowButton:(UIButton *)showButton{
    _showButton = showButton;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    for (UITouch *touch in touches) {
        if (_content) {
            if (touch.view !=  _content) {
                _showButton.selected = NO;
                [
selfdismis];
            }
        }
else{
           
if (touch.view !=  _menuView) {
                _showButton.selected = NO;
                [selfdismis];
            }
        }
    }
}
搜索框
#import "MCSearchTextField.h"

@implementation MCSearchTextField

- (
instancetype)initWithFrame:(CGRect)frame
{
   
self = [superinitWithFrame:frame];
   
if (self) {
        [
selfcreatSearchTextfield];
    }
   
returnself;
}
-(void)creatSearchTextfield{
    self.background = [UIImageimageNamed:@"searchbar_textfield_background"];
   
self.backgroundColor = [UIColorwhiteColor];
   
self.placeholder = @"搜索内容";
   
self.layer.cornerRadius = 5;
   
self.layer.borderWidth = 1;
   
self.layer.borderColor = [UIColorlightGrayColor].CGColor;
   
UIImageView *imageView= [[UIImageViewalloc]initWithImage:[UIImageimageNamed:@"searchbar_textfield_search_icon"]];
    imageView.
width = 30;
    imageView.
height = 30;
    imageView.contentMode = UIViewContentModeCenter;
    self.leftView = imageView;
    self.leftViewMode = UITextFieldViewModeAlways;
}
@end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值