百思不得姐第1天

一:项目环境的搭建:

项目环境的搭建包括:1:新建类的前缀   2:项目支持的旋转方向,版本   3:项目名称,软件名称 4:APP的icon,启动图片的设置 5:项目的文件夹分层 6:根控制器的设置 等  

具体详情请参照新浪微博的项目环境配置

二:cocoaPods的安装与使用

1:具体参照新浪微博项目cocoaPods的安装与使用:安装并导入所需要的依赖库

三:百思不得姐主框架的搭建

1:删除storyBoard,重新定义窗口的根视图控制器

#import "AppDelegate.h"
#import "CQTabBarViewController.h"
@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 
    self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    
    //1:添加窗口的根视图控制器
    
    CQTabBarViewController *tab = [[CQTabBarViewController alloc]init];
    self.window.rootViewController = tab;
    

    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end

2:构建窗口的根视图控制器:

//
//  CQTabBarViewController.h
//  百思不得姐
//
//  Created by cqb on 16/8/25.
//  Copyright © 2016年 cqb. All rights reserved.
//窗口的根视图控制器:CQTabBarViewController

#import <UIKit/UIKit.h>

@interface CQTabBarViewController : UITabBarController


@end
#import "CQTabBarViewController.h"
#import "CQFollowViewController.h"
#import "CQMeViewController.h"
#import "CQNewViewController.h"
#import "CQEsencesViewController.h"
#import "CQCustomTabBar.h"
#import "CQCustomNavViewcontrollerViewController.h"
@interface CQTabBarViewController ()<CQCustomTabBarDelegate>

@end

@implementation CQTabBarViewController



- (void)viewDidLoad {
    [super viewDidLoad];
    
    //1:设置tabBarItem的属性
    [self setupTabBarItemAttribute];
    
    //2:添加子控制器
    [self addChildViewControllers];
    
    //3:添加自定义的tabBar
    [self addCustomTabbar];

 
}

/**
 *    设置tabBarItem的属性
 */

- (void)setupTabBarItemAttribute {
    
    UITabBarItem *tabItem = [UITabBarItem appearance];
    
    //1:设置Normal状态下的文字属性
    NSMutableDictionary *itemNormalTitleDic = [NSMutableDictionary dictionary];
    itemNormalTitleDic[NSFontAttributeName] = Font(13);
    itemNormalTitleDic[NSForegroundColorAttributeName] = [UIColor grayColor];
    [tabItem setTitleTextAttributes:itemNormalTitleDic forState:UIControlStateNormal];
    
    //2:设置select状态下的文字属性
    NSMutableDictionary *itemSelectTitleDic = [NSMutableDictionary dictionary];
    itemSelectTitleDic[NSFontAttributeName] = Font(13);
    itemSelectTitleDic[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
    [tabItem setTitleTextAttributes:itemSelectTitleDic forState:UIControlStateSelected];
    
}

/**
 *    添加子控制器
 */

- (void)addChildViewControllers {
    
    /**
     *    精华
     */
    [self addChildViewController: [[CQCustomNavViewcontrollerViewController alloc]initWithRootViewController:[[CQEsencesViewController  alloc]init]] title:@"精华"  image:@"tabBar_essence_icon"  selectedImage:@"tabBar_essence_click_icon"];
    
    /**
     *    新帖
     */
    [self addChildViewController: [[CQCustomNavViewcontrollerViewController alloc]initWithRootViewController:[[CQNewViewController  alloc]init]] title:@"新帖"  image:@"tabBar_new_icon"  selectedImage:@"tabBar_new_click_icon"];
    
    
    /**
     *    关注
     */
    [self addChildViewController: [[CQCustomNavViewcontrollerViewController alloc]initWithRootViewController:[[CQFollowViewController  alloc]init]] title:@"关注"  image:@"tabBar_friendTrends_icon"  selectedImage:@"tabBar_friendTrends_click_icon"];
    
    /**
     *    我
     */
    [self addChildViewController: [[CQCustomNavViewcontrollerViewController alloc]initWithRootViewController:[[CQMeViewController  alloc]init]] title:@""  image:@"tabBar_me_icon"  selectedImage:@"tabBar_me_click_icon"];
}


- (void)addChildViewController:(UIViewController*)vc  title:(NSString*)title  image:(NSString*)imageName  selectedImage:(NSString*)selectedImageName  {
    
    //1:设置标题
    vc.tabBarItem.title = title;
    
    //2:设置图片
    //  normal
    vc.tabBarItem.image = [UIImage imageNamed:imageName];
    
    //select
    vc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImageName];
    
    [self addChildViewController:vc];
    
}
/**
 *    添加自定义的tabBar
 */

- (void)addCustomTabbar {
    
     CQCustomTabBar *tab =  [CQCustomTabBar customTabBar];
     tab.delegate = self;
    [self setValue:tab forKeyPath:@"tabBar"];
}

/**
 *CQCustomTabBarDelegate 代理方法
 */

- (void)customTabBar:(CQCustomTabBar *)customTabBar didSelecteCenterButton:(UIButton *)btn {
    
    CQBFUNC
}
@end

3:重新自定义导航控制器:

#import <UIKit/UIKit.h>

@interface CQCustomNavViewcontrollerViewController : UINavigationController

@end
#import "CQCustomNavViewcontrollerViewController.h"

@interface CQCustomNavViewcontrollerViewController ()<UIGestureRecognizerDelegate>

@end

@implementation CQCustomNavViewcontrollerViewController

/**
 *    1:设置导航栏的标题,item属性
 */
+(void)initialize {
    
    //1:设置导航栏的主题
    [self setupNavBarTheme];
    
    //2:设置导航栏上的item属性
    [self setupNavBarItem];
}

//1:设置导航栏的主题
+(void)setupNavBarTheme {
    
    UINavigationBar *appearance = [UINavigationBar appearance];
    //1:设置导航栏的背景图片,背景色:tintColor
    [appearance setBackgroundImage:[UIImage imageNamed:@"navigationbarBackgroundWhite"] forBarMetrics:UIBarMetricsDefault];
    
    //2:设置导航标题属性
    NSMutableDictionary *titleAttribute = [NSMutableDictionary dictionary];
    titleAttribute[NSForegroundColorAttributeName] = [UIColor blackColor];
    titleAttribute[NSFontAttributeName] = [UIFont boldSystemFontOfSize:18];
    [appearance setTitleTextAttributes:titleAttribute];
    
}

//2:设置导航栏上的item属性
+(void)setupNavBarItem {
    
    UIBarButtonItem *appearance = [UIBarButtonItem appearance];
    
    //设置文字属性
    
    //1:normal
    NSMutableDictionary *normalAttribute = [NSMutableDictionary dictionary];
    normalAttribute[NSFontAttributeName] = Font(15);
    normalAttribute[NSForegroundColorAttributeName] = [UIColor blackColor];
    [appearance setTitleTextAttributes:normalAttribute forState:UIControlStateNormal];
 
    //2:高亮
    NSMutableDictionary *selectedAttribute = [NSMutableDictionary dictionary];
    selectedAttribute[NSFontAttributeName] = Font(15);
    selectedAttribute[NSForegroundColorAttributeName] = [UIColor grayColor];
    [appearance setTitleTextAttributes:selectedAttribute forState:UIControlStateHighlighted];
    
}



- (void)viewDidLoad {
    [super viewDidLoad];
  
    //1:当自定义导航控制器的时候,系统的左滑手势会失效
    self.interactivePopGestureRecognizer.delegate = self;
    
}
/**
 *    拦截push请求设置每个push控制器的左右item按钮
 *
 *    @param viewController    即将被压栈的kongzjqi
 *    @param animated            是否动画
 */
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {

    if (self.viewControllers.count > 0) {
       
        //1:设置即将压栈控制器的左右item
        
        //左侧返回按钮
        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithTitle:@"返回" image:@"navigationButtonReturn" HighlightImage:@"navigationButtonReturnClick" target:self action:@selector(pop)];

        
        //右侧按钮
        viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithTitle:nil image:@"MainTagSubIcon" HighlightImage:@"MainTagSubIconClick" target:self action:@selector(popRoot)];
        
        //2:push的时候隐藏tabBar
        viewController.hidesBottomBarWhenPushed = YES;
        
    }
    
    
    [super pushViewController:viewController animated:animated];
    
}

/**
  左右按钮的点击方法
 */

//左侧返回按钮
- (void)pop {
    
    [self popViewControllerAnimated:YES];
}

//右侧按钮

- (void)popRoot {
    
    [self popToRootViewControllerAnimated:YES];
}


/**
 *UIGestureRecognizerDelegate:代理方法:
 */
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    
    return self.childViewControllers.count > 1;
//    return self.viewControllers.count > 1;
}

@end

4:自定义tabBar取代系统的tabBar

#import <UIKit/UIKit.h>

@class CQCustomTabBar;
@protocol CQCustomTabBarDelegate <NSObject>

@optional

- (void)customTabBar:(CQCustomTabBar*)customTabBar didSelecteCenterButton:(UIButton*)btn;

@end


@interface CQCustomTabBar : UITabBar

+(instancetype)customTabBar;

@property (nonatomic,weak)id <CQCustomTabBarDelegate>Delegate;
@end
#import "CQCustomTabBar.h"
@interface CQCustomTabBar ()
/*中间的按钮*/
@property (nonatomic,weak)UIButton *centerButton;

@end
@implementation CQCustomTabBar

- (UIButton*)centerButton {
    
    if (!_centerButton) {
        
        UIButton *btn = [[UIButton alloc]init];
        [btn setBackgroundColor:[UIColor clearColor]];
        [btn setImage:[UIImage imageNamed:@"tabBar_publish_icon"] forState:UIControlStateNormal];
        [btn setImage:[UIImage imageNamed:@"tabBar_publish_click_icon"] forState:UIControlStateHighlighted];
        [btn addTarget:self action:@selector(clickCenterBtn:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:btn];
        self.centerButton = btn;
    
    }
    
    return _centerButton;
}

+(instancetype)customTabBar {
    
    return [[self alloc]init];
}

- (instancetype)initWithFrame:(CGRect)frame {
    
    if (self = [super initWithFrame:frame]) {
        
        //1:设置自身的属性
        [self setupAtrtribute];
        
    }
    
    return self;
}

/**
 *    1:设置自身的属性
 */

- (void)setupAtrtribute {
    
    [self setBackgroundImage:[UIImage imageNamed:@"tabbar-light"]];

}

/**
 *    2:布局子控件
 */
- (void)layoutSubviews {
  
    [super layoutSubviews];
   //1:先布局已经添加的四个子控件
    
    CGFloat btnWidth = self.CQ_Width / (self.items.count +1);
    CGFloat btnHeight = self.CQ_Height;
    CGFloat btnY = 0;//为0时可以不写
    
    NSUInteger index = 0;
    
    for (UIView *tabBarButton in self.subviews) {
        
    if (![tabBarButton isKindOfClass:[NSClassFromString(@"UITabBarButton") class]])   continue;//return;
       
        if (index >= 2) {
            /*也可以:
             
             if (index == 2) {
             
             //布局中间钮
             self.centerButton.CQ_Width = btnWidth;
             self.centerButton.CQ_Height = btnHeight;
             self.centerButton.CQ_X = index *btnWidth;
             self.centerButton.CQ_Y = btnY;
             }
             */
         
            tabBarButton.CQ_X = (index + 1) *btnWidth;
            
        }else {
            
            tabBarButton.CQ_X = index *btnWidth;
        }
        tabBarButton.CQ_Y = btnY;
        tabBarButton.CQ_Height = btnHeight;
        tabBarButton.CQ_Width = btnWidth;

        index ++ ;
        
    }
    
    self.centerButton.CQ_Width = btnWidth;
    self.centerButton.CQ_Height = btnHeight;
    self.centerButton.CQ_CenterX = self.CQ_Width *0.5;
    self.centerButton.CQ_CenterY = self.CQ_Height *0.5;
    
}
/**
 *    中间按钮的点击回调
 */

- (void)clickCenterBtn:(UIButton*)btn {
    
    if (self.Delegate && [self.Delegate respondsToSelector:@selector(customTabBar:didSelecteCenterButton:)]) {
        
        [self.Delegate customTabBar:self didSelecteCenterButton:btn];
    }
}
@end

5:项目中的分类文件:

 1:UIBarButtonItem分类:设置导航栏上的左右按钮

//
//  UIBarButtonItem+CQBarButtonItem.h
//  百思不得姐
//
//  Created by cqb on 16/8/25.
//  Copyright © 2016年 cqb. All rights reserved.
//UIBarButtonItem分类:设置导航栏上的左右按钮

#import <UIKit/UIKit.h>

@interface UIBarButtonItem (CQBarButtonItem)

+(instancetype)itemWithTitle:(NSString*)title image:(NSString*)imageName HighlightImage:(NSString*)highlightImageName target:(id)target action:(SEL)action;

@end
#import "UIBarButtonItem+CQBarButtonItem.h"

@implementation UIBarButtonItem (CQBarButtonItem)

+(instancetype)itemWithTitle:(NSString*)title image:(NSString*)imageName HighlightImage:(NSString*)highlightImageName target:(id)target action:(SEL)action {
    
    UIButton *btn = [[UIButton alloc]init];
    if (title.length){
       [btn setTitle:title forState:UIControlStateNormal];
       [btn setTitleColor:RGB(46, 46, 47) forState:UIControlStateNormal];
       [btn setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
    }
    [btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
    [btn setImage:[UIImage imageNamed:highlightImageName] forState:UIControlStateHighlighted];
    btn.titleLabel.font = Font(15);
    [btn addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    [btn sizeToFit];
#pragma mark -- 此句代码是调整左右按钮距离边框的位置,前提是必须有btn已经有了size
    btn.contentEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0);
    return [[UIBarButtonItem alloc]initWithCustomView:btn];
}
@end

2:UIView的分类

//  UIView+CQView.h
//  百思不得姐
//
//  Created by cqb on 16/8/25.
//  Copyright © 2016年 cqb. All rights reserved.
//分类不生成带下划线的成员变量,所以重写set不用下划线赋值

#import <UIKit/UIKit.h>

@interface UIView (CQView)
@property (nonatomic,assign)CGFloat CQ_X;
@property (nonatomic,assign)CGFloat CQ_Y;
@property (nonatomic,assign)CGFloat CQ_Width;
@property (nonatomic,assign)CGFloat CQ_Height;
@property (nonatomic,assign)CGFloat CQ_CenterX;
@property (nonatomic,assign)CGFloat CQ_CenterY;
@property (nonatomic,assign)CGSize CQ_Size;

@end
//
//  UIView+CQView.m
//  百思不得姐
//
//  Created by cqb on 16/8/25.
//  Copyright © 2016年 cqb. All rights reserved.
//

#import "UIView+CQView.h"

@implementation UIView (CQView)

- (void)setCQ_X:(CGFloat)CQ_X {
    
    CGRect frame = self.frame;
    frame.origin.x = CQ_X;
    self.frame = frame;
}

- (CGFloat)CQ_X {
    
    return self.frame.origin.x;
}


- (void)setCQ_Y:(CGFloat)CQ_Y {
    
    CGRect frame = self.frame;
    frame.origin.y = CQ_Y;
    self.frame = frame;

}

- (CGFloat)CQ_Y {
    
    return self.frame.origin.y;
}


- (void)setCQ_Width:(CGFloat)CQ_Width {
    
    CGRect frame = self.frame;
    frame.size.width = CQ_Width;
    self.frame = frame;

}

- (CGFloat)CQ_Width {
    
    return self.frame.size.width;
}

- (void)setCQ_Height:(CGFloat)CQ_Height {
    
    CGRect frame = self.frame;
    frame.size.height = CQ_Height;
    self.frame = frame;

}

- (CGFloat)CQ_Height {
    
    return self.frame.size.height;
}

- (void)setCQ_Size:(CGSize)CQ_Size {
    
    CGRect frame = self.frame;
    frame.size = CQ_Size;
    self.frame = frame;

    
}

- (CGSize)CQ_Size {
    
    return self.frame.size;
}

- (void)setCQ_CenterX:(CGFloat)CQ_CenterX {
    
    CGPoint center = self.center;
    center.x = CQ_CenterX;
    self.center = center;

}

- (CGFloat)CQ_CenterX {
    
    return self.center.x;
}


- (void)setCQ_CenterY:(CGFloat)CQ_CenterY {
    
    CGPoint center = self.center;
    center.y = CQ_CenterY;
    self.center = center;
}

- (CGFloat)CQ_CenterY {
    
    return self.center.y;
}

@end

6:项目中的pch文件宏定义:

#ifndef PrefixHeader_pch
#define PrefixHeader_pch

#import "UIBarButtonItem+CQBarButtonItem.h"
#import "UIView+CQView.h"
/**
 *    1:配置颜色的宏
 */

#define  RGBCOLOR(a,b,c,d) [UIColor colorWithRed:(a)/255.0 green:(b)/255.0 blue:(c)/255.0 alpha:d]

#define RGB(a,b,c)  RGBCOLOR(a,b,c,1)

#define RGBRANDOM   RGB(arc4random_uniform(255),arc4random_uniform(255),  arc4random_uniform(255))


/**
 *    2:打印的相关配置
 */


#ifdef DEBUG

#define CQLog(...)   NSLog(__VA_ARGS__)

#else

#define CQLog(...)

#endif



/**
 *    3:调试配置
 */

#define CQBFUNC  CQLog (@"+++++++++++%s+++++++++++++",__func__);


/**
 *    4:单例宏配置:注意小括号最好不要留有空格
 */

//.h文件

#define CQSingletonInterface(Class)    +(instancetype)shared##Class

//.m文件

#define CQSingletonImplementation(Class)

static  id  _instance;
+(instancetype)shared##Class {


    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        _instance = [[self alloc]init];

    });

    return _instance;
}

+(instancetype)allocWithZone:(struct _NSZone *)zone {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        _instance = [super allocWithZone:zone];
    });

    return _instance;
}

- (instancetype)copyWithZone:(NSZone *)zone
{
    return _instance;
}

/**
 *    字体的宏配置
 */

#define Font(a)  [UIFont systemFontOfSize:a]

/**
 *    屏幕宽高
 */

#define SCREENWIDTH  [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT  [UIScreen mainScreen].bounds.size.height 

/**
 *    全局背景色
 */

#define AllBackgroundColor  RGB(187,187,187)



#endif /* PrefixHeader_pch */

总结:

1:窗口的根控制器继承UITabBarController,在自定义的CQTabBarViewController中的viewDidload方法里抽方法封装调用,需要做3件事:1:设置tabBarItem的不同状态下的文字属性 :拿到全局tabBarItem,再利用setTitleTextAttributes  forState,设置不同状态下的文字属性  2:添加所有子控制器:因为需要添加tabBar上的四个子控制器,有大量重复的代码,要想到抽代码封装,将相同的部分抽成方法,不同的部分作为参数调用:所以抽成方法,传子控制器VC,title,Image,selectImage(传入子控制器为导航控制器),在方法中设置tabBaritem的标题不同状态下的图片,vc.tabBarItem.title  vc.tabBarItem.Image  vc.tabBarItem.selecteImage,最后调用addChildViewcontroller,添加子控制器 3:需要利用自定义tabBar利用kvc,setValue forKeyPath,替换掉系统的tabBar。

2:自定义导航控制器:在自定义导航控制器中需要做三件事:1:在+(void)initialize方法中设置全局的导航栏UINavigationBar

的外观:背景图片,背景色:tintColor,并设置导航栏上标题文字属性,setTitleTextAttributes  。还需要在此方法中设置导航栏上的全局左右按钮UIBarButtonItem,设置不同状态下的文字属性,常态,选中,高亮。 2:在viewDidLoad中设置手势代理:因为只要是自定义导航栏系统自带的左滑效果就会消失,所以要重新回复左滑手势,就要设置手势代理。self.interactivePopGestureRecognizer.delegate = self;并实现手势的代理方法:- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer,当导航控制器的栈里的控制器个数大于1的时候才让其恢复左滑效果。

   return self.childViewControllers.count > 1;

//    return self.viewControllers.count > 1;

两种方法都可以拿到导航控制器的子控制器的数组。

3:需要拦截push方法:拦截push的目的是:为每一个push到栈里的控制器,除了首页的控制器,设置统一的返回按钮,并且push的时候隐藏底部的tabBar。并实现左右按钮的点击方法

4:自定义底部的tabBar:继承系统的tabBar,参照view的封装方法:1:类方法快速返回对象,内部调用alloc init ,alloc init内部调用alloc initWithFrame 方法,在初始化方法中设置自身的属性或是一次性设置代码  2:懒加载控件(属性定义strong和weak修饰都可以),在懒加载方法中设置控件的属性。并添加到其父控件上 3:重写layoutSubView方法,不要忘记调用super,且此方法配合setNeedsLayout和layoutIfneed配合使用:在此方法内设置控件的frame,如何拿到控件?1:属性,成员变量,枚举tag值(直接取,或是遍历父控件的子控件数组,通过tag值取出,tag值一般不要设为0,不安全,因为所有控件默认的tag值都为0,通过self.subviews,count 也可以设置tag值),或是继承父类直接从父类属性获取 2:将创建的控件放在一个属性定义的大数组中,若是含有不同类的控件则两两放在大数组中,在layoutSubView里从数组中取出 3:遍历父控件的子控件数组:1:self.subViews(UIView和scroll隐藏掉两个滚动条后是最纯洁的view,除了自己添加的不含有任何子控件),需要index就采用int i 遍历,不需要就可以采用for in快速遍历,并在外部定义index,内部index++,来记录索引值。在遍历时,先要做条件过滤(1:continue 2:return过滤,不执行return下面的代码,3:break,跳出循环,不再循环)找到后设置值,并停止遍历 2:若是遍历父控件的self.subViews子控件数组,有时候系统父控件没有直接提供属性使用,这时,可以打印子控件数组或是通过ViewUI来调试查看所需要的子控件是什么,这样就可以拿到子控件从字符串转化为类,NSClassFromString();4:设置frame完毕后:每一个封装view都要对应一个model,所以封装的view提供model接口,在内部重写setmodel,为view设置数据  5:对于封装view接口的设计:1:把与外界无关的业务逻辑全部封装在类的内部,类再提供接口供外界访问,保证外界调用时最简洁的 2:对于接口的设计:一般用属性接口通过重写代替方法接口,是否就提供BOOL属性接口,不同类型,就提供枚举type接口,外界想访问类内部的什么方法,变量就给外部提供属性接口。6:对于封装类内部的回调:1:层级较浅时,用协议代理(1:仿照tableView的代理方法设计协议代理 2:有时需要重写setDelegate方法来,也就是成为代理之后才可以去做某些设置)block,两者都可以,当两个类需要相互回调时,可以给协议代理或是block设置返回值,就可以实现两个类相互回调 2:层级较深的时候:可以利用通知回调,传值,其中通知可以在当前线程或是子线程中执行(只看post通知的时候在哪个线程里,注册观察者后,执行通知方法就在哪个线程),其中注册观察者也可以用block方式注册观察者,并指定收到通知后的block任务在哪个线程中执行(也可实现一次性的通知,在block中执行完任务后,就取消观察者),如果采用block的方式注册的观察者,要以熟悉定义id类型返回值类接受block通知的返回值,以便在dealloc中注销观察者。一般项目中的通知名都写在配置常量的类里   7:在封装类的内部监听系统类或是属性:1:查看子类有没有系统代理方法,通知方法,或是继承UIControl的可以addTarget都可以实现监听,若是子类没有还可以查看父类有没有上述的方法,在查看系统的API时,可以查看其其英文注释该方法的使用说明,也可以按住option键点击某个方法来查看使用说明 2:在开发中遇到问题首先考虑重写,重写非常好用,通过重写父类的方法也可以对父类行为进行拦截,覆盖或是监听父类的行为。但是不要忘记调用super,否则父类的行为就不会响应。

5:1:若是设置某个控件在中间的位置,就可以考虑用center属性去设置,设置tabBar中间按钮的frame时,先设置按钮的宽高,在设置center,防止出错,center的x值就为宽度的一半,center的y值就为高度的一半 2:如果设置的是tabBar的中心点等于按钮的中心点就会出错,tabBar的中心点是相对整个屏幕来计算的,所以如此设置,按钮就会找不到了,因为按钮是添加到tabBar上的,所以就要设置相对tabBar的中心点 2:在封装UIBarButtonItem时,在分类里,自定义按钮,调用sizeTofit方法,系统会自动根据按钮的内容的大小来计算按钮的宽高,还有一种方法,(1:若是想让图片不变形,就设置按钮大小和图片大小相等(图片的大小按像素计算,按钮的大小等于图片的大小,就用图片像素的宽高分别乘以2)2:设置按钮中imageView的内容模式:center,等比fit,等比fill,fill属性,center图片内容居中,等比fit会先使图片顶部对齐,直到整个图片在imageView中完全显示出来 ,等比fill,保持图片原来的宽高比伸缩,最后有可能只看到图片的一部分,fill图片的默认方式,默认填充整个imageView。)先为btn设置图片,在通过btn取出图片btn.currentImage,title,backgroundImage取出,在设置btn的size。3:设置导航栏上的按钮距离左右边框的距离:1:设置btn的内容的edge属性,btn.contentEdgeInset,左侧设置为负数,则btn的整体内容content就会向左移动,缩短与屏幕的距离,设置正数content就会往右移动,增加了距离 2:自定义NavBar继承系统的NavBar,重写layoutsubView方法,遍历子控件根据条件判断左右按钮,拿到左右按钮的子控件,若是不能拿到,则打印子控件数组,NSClassFromstring(),做条件过滤拿到最后真正的子控件,再调整距离,利用kvc替换系统的NavBar 3:btn的重要的属性:继承UIControl都有的contentHorizan内容的对齐方式,btn.contentEdgeInset,btn.titleEdgeInset,btn.imageEdgeInset,当按钮内部需要要调整title和image的相对位置时:1:自定义UIButton,重写button的title,iamge重新布局的方法 2:自定义button,重写layoutsubview,直接拿到子控件title,iamge去调整frame(1:若是不能直接拿到则遍历子控件数组,打印或是viewUI查看其所属的类,NSClassFromstring去做条件过滤拿到 2:利用润time拿到父类所有私有属性,利用kvc赋值设置)3:利用btn的对其方式:四个对其方式配合使用,例如,先整体内容左对齐,在设置title或是image,或是content的edge属性。4:再给UIView或是其他类写分类时,最好加上前缀,像sd_iamge,或是mj_refresh,避免与系统定义的变量冲突,分类以属性定义变量的时候,不会自动生成下划线的成员变量,所以不用下划线变量赋值。 5:pch文件一般存放项目中的头文件,一些打印调试颜色单例或是基本数据的宏定义。在buildsetting中配置pch的路径,需要删除的是当前桌面的路径,保留的是此项目的当前路径并加上$(SRCROOT).像项目一些通知名,或是一些常量字符串就新建类特意存储这些全局常量UIKIT_EXTERN 来引用。在配置打印和单例的宏定义时,最好涉及到变量后有小括号时,最好不要留有空格要紧挨着。6:单例的完整写法:1:在pch文件中配置的单例宏定义就是完整的写法1:考虑到了线程安全,dispatch_once默认有一把线程锁 2:当调用share 或是 alloc,或是copy的时候保证得到的都是同一个对象。alloc内部会调用 allocWithZoon方法,开辟内存空间。调用copy的时候已经保证了两个方法已经执行完了,若是想重写-(id)copyWithzoon方法,必须先要遵守NSCopying协议才可以重写。

6:如何写代码:1:先要整理好逻辑,把逻辑理顺了,再去下手去写代码 2:对于控制器或是view:要想到分层封装的思想,将控制器或是view的UI模块化切分成一个个模块,分析模块内都由哪些控件组成,将零散的控件都封装一个整体的模块内(参照新浪微博cell的封装结构),若是项目中很多地方都会用到此模块,则考虑将此模块抽成父类,让子类去继承,并扩展不同于父类的内容。具体的封装方法参照view的封装方法。3:控制器或是封装view中代码的编写:1:在控制器中实现+(void)load,做一些常用配置(例如配置MJExtension字典转模型的配置),该方法只执行一次,并且不用导入头文件就可以调用,也就是该类被加载进内存就会调用 +(void)initalize方法改方法也会调用一次,当类被使用的时候也就是第一个方法被调用的时候有且只会调用一次,在该方法中可以初始化一些配置的设置或是只需要一次性设置的(自定义导航控制器设置全局导航主题,或是数据库建表)重写控制器的init方法,可以在控制器创建初始化时传递参数或是初始化时做一些固定的一次性设置。+(void)loadView方法,重写此方法可以更改控制器的self.view  viewDidLoad方法view加载完毕后调用,viewWillAppear 或是viewWillDidAppear 这两个方法会调用不止一次,只要是界面出现即将出现就会调用pop,dissmiss都会调用,一般在viewWillDidAppear方法中打印控件的信息,因为此时控件已经完全显示出来,viewWillDisappear,viewDiddisappear页面即将消失或是已经消失 的时候调用,dealloc控制器销毁的时候调用,在此方法中可以移除通知或是在控制器销毁的时候传递给爱他控制器一些数据信息。2:我们一般在viewDidLoad方法中采取封装方法调用 1:当控制器中某个方法含有大量重复的代码时要考虑抽方法封装,将相同的代码抽到方法的内部,不同的部分作为参数传递 2:若是代码中涉及某些业务逻辑的处理或是项目中各个地方都可以用到,则也应考虑到封装:1:分类封装:1:当此段业务逻辑与系统某个类有关系时,要想到给系统类写分类,而且能写分类尽量写分类,因为分类会少创建类,减少内存 2:分类的接口设计:对象方法或是类方法,类方法较对象方法简餐粗暴,但是当需要传递两个参数的时候可以考虑利用对象方法,分类中的self指的就是传递的参数 2:管理类Tool封装:单例或是类方法,在类方法中要是想获得单例一样的成员变量,就用static定义全局变量,该成员变量也可以采用懒加载模式,只让其初始化一次,外界若是想访问该成员变量,则该类可以提供接口get方法接口,供外界调用(get方法接口也可以用点语法去调用)3:考虑继承:将相同的部分抽到父类,不同的部分分别在子类中去实现,父类可在.h中暴露方法供子类去重写(父类可提供标识属性,供子类去重写,以便于在父类中区分不同子类),子类重写父类的方法后,也就相当于间接修改了父类的属性,父类中也就可以拿到子类修改的属性。3:控制器或是view中每一行代码的编写,都要力求使最简洁的,要反复推敲,提炼,直到代码是最简洁不能再抽为止。1:像是hidden或是返回bool值的方法中一句代码解决 或是利用三目运算简化ifelse 2:赋值散三部,最上面定位nil,中间赋值,最后赋值 3:有两个返回值时,只用一个if,分别返回,不用if else 4:当遍历的时候,先做条件过滤(continue,braek,或是return条件过滤),找到赋值,并停止遍历。

原文地址:https://www.cnblogs.com/cqb-learner/p/5808744.html