美文网首页
02.实战技术 父子控制器,常量Const,开发中常见问题

02.实战技术 父子控制器,常量Const,开发中常见问题

作者: Liwx | 来源:发表于2016-01-16 01:41 被阅读178次

    @(iOS Study)[实战技术]


    目录

    • 02.实战技术 父子控制器,常量Const,开发中常见问题
    • 开发中常见问题/常量Const/父子控制器
    • 1.super,superClass,class关键字
      • super,superClass,class介绍
      • super关键字
    • 2.项目奇怪的bug
      • bug1. 已添加文件到项目中,却提示未定义
      • bug2. 重复添加文件到项目中
      • bug3. 导入.m文件
    • 3.const的使用
      • const与宏的区别
      • const的简单使用
      • const开发中使用场景
      • static和extern使用
      • static和const联合使用
      • extern和const联合使用
    • 4.父子控制器
      • 父子控制器简介
      • 父子控制器相关知识点
      • 父子控制器的简单使用
    • 5.开发中常见问题
      • UIScrollView的自动布局
      • UIScrollView自动布局步骤(重要)
      • size和center设置注意点
      • bounds和frame简介
      • bounds和frame介绍

    开发中常见问题/常量Const/父子控制器


    1.super,superClass,class关键字

    super,superClass,class介绍

    • 关键字在方法中的意义
      • self: 方法调用者
      • class: 获取方法调用者的类对象
      • superclass:获取方法调用者的父类对象

    super关键字

    • super关键字的介绍

      • super:不是一个指针,编译指示器(标识符)
      • super的本质:其实还是当前对象去调用,只不过让当前对象去调用父类方法
      • super不是父类对象,指的是父类方法
    • 注意:[super class]表示用self调用父类方法,[super superclass]表示用self调用父类的方法(获取父类方法)

    • super的案例说明

    @implementation SubPerson
    
    - (void)test
    {
        // [super class]表示用self调用父类方法,[super superclass]表示用self调用父类的方法(获取父类方法)
        NSLog(@"%@ %@ %@ %@",[self class], [self superclass], [super class], [super superclass]);
        // 正确打印结果: SubPerson Person SubPerson Person √
        // 错误打印结果: SubPerson Person Person NSObject X
    }
    
    @end
    

    2.项目奇怪的bug

    bug1. 已添加文件到项目中,却提示未定义

    • 已添加文件到项目中,却提示未定义bug
    1.bug1.已添加文件到项目中,却提示未定义.png
    • 导致该bug的原因
      • 在创建文件/从其他地方拖进工程的时候,没有勾选以下选项
        创建的时候未勾选该选项,导致没添加到编译列表
    2.导致该bug的原因.png

    从其他地方拖进工程的时候,没有勾选Targets项,导致没添加到编译列表

    3.没有勾选Targets项.png
    • 解决方案: 在项目文件/Build Phases/Complie Sources将文件(.m文件)添加到编译列表
    4.解决方案.png

    bug2. 重复添加文件到项目中

    • 重复添加文件,提示错误
    5.bug2. 重复添加文件到项目中.png
    • 解决方案: 找出重复文件,将文件移除.

    bug3. 导入.m文件

    • 不小心导入了.m文件
    6.bug3. 导入.m文件.png

    3.const的使用

    const与宏的区别

    • const与宏的区别

      • 1.编译时刻: const:编译时期 宏:预编译时期
      • 2.编译检测: const有编译检测,宏没有编译检测.如#define WXKey @"123"488 ,这样宏不会提示错误.
      • 3.宏可以替换方法和函数,const不行
      • 4.大量使用宏,容易造成预编译时期过长.
      • 有博客提到:大量使用宏,会导致内存暴增,有异议.
    • 苹果使用const为了迎合swift

    • '#'号是预编译指令

    • 预编译时期:项目一打开的时候,有个自动读条时期,这个时期就是在做预编译操作,如果定义了大量的宏,可能会导致自动读条的时间变长,是开发效率变低,苹果官方建议尽量少使用宏.

    const的简单使用

    • const的作用

      • 1.用来修饰右边变量(基本变量,指针变量,对象等)
      • 2.只要被const修饰的变量,只读
    • const使用原则

      • 放在const右边被修饰的变量为只读.
    • const笔试题

        // 1.原因:const修饰的是p,所以p为只读;const在*之后,const没修饰*p,所以*p是变量.
        int * const p; // p:只读   *p:变量
        // 2.原因: const修饰的是*p1,所以*p1为只读;const没修饰p1,所以p1是变量.
        int const *p1; // p1:变量  *p1:只读 
        // 3.原因: const修饰*p2,所以*p2为只读;const没修饰p2,所以p2为变量
        const int *p2; // p2:变量  *p2:只读
        // 4.原因: 第一个const修饰*p3,所以*p3为只读;第二个const修饰p3,所以p3为只读
        int const * const p3; // p3:只读 *p3:只读
        // 5.原因: 第一个const修饰*p4,所以*p4为只读;第二个const修饰p4,所以p4为只读
        const int * const p4; // p4:只读  *p4:只读
    

    const开发中使用场景

    • 1.当代码多处(不同方法中)共用同一个只读(无需修改)的字符串,比如多处(不同方法中)用到setValue:forKey:时都需要用到同一个key时,可以使用以下方法定义const字符串常量.
    NSString * const key = @"key";
    

    static和extern使用

    • static和extern的作用

      • static作用:

      1.描述局部变量,局部变量被static修饰,生命周期延长(整个app运行过程中都在),作用域不变.
      2.局部变量被static修饰,只会分配一次内存,程序一启动就会分配.
      3.修饰全局变量,全局变量被static修饰,生命周期不变,作用域会变,只能在当前文件下使用.

      • extern作用:声明一个全局变量,不能定义变量.

    static和const联合使用

    • static和const联合使用场景
    // 用于KVC的key时,可以static和const联合使用
    static NSString * const ageKey = @"age";
    

    extern和const联合使用

    • 开发规范:全局变量不能在自己的文件下定义,搞一个专门文件,去管理所有全局变量

    • extern和const联合使用使用场景(声明全局常量的时候)

      • 创建Const.h和Const.m文件用来存放全局常量
      • 在Const.h中使用extern和const声明 NSString * const nameKey;注意:不能在.h文件中赋值.
      • 在Const.m中定义NSString * const nameKey = @"name";
    • 开发中存放常量的文件中,常量可以按功能模块划分.

    // Const.m
    #import "Const.h"
    /*********我的********/
    NSString * const nameKey = @"nameKey";
    
    /*********发现********/
    NSString * const discoveryKey = @"discoveryKey";
    
    
    // Const.h
    /*********我的********/
    extern NSString * const nameKey;
    
    /*********发现********/
    extern NSString * const discoveryKey;
    
    • 模仿系统实现extern
    // Const.h
    // WXKIT_EXTERN相当于extern
    #define WXKIT_EXTERN    extern __attribute__((visibility ("default")))
    WXKIT_EXTERN NSString * const nameKey;
    

    4.父子控制器

    父子控制器简介

    父子控制器应用场景-多控制器管理者:导航控制器,tabBarController,内部原理就是采取父子控制器去管理.
    任何控制器都可以成为父控制器
    父子控制器设计原则: 把A控制器的view添加到B控制器的view上,那么A控制器必须要成为B控制器子控制器.

    父子控制器相关知识点

    • 调试时已知问题可以先列出来,以防忘记,遗漏处理已经存在的问题
    /*
        问题:
        1.每次都创建控制器
        2.每次都添加view
        3.控制器被销毁
     */
    
    • 调用dismissViewControllerAnimated:completion:方法时,dismiss实现内部实现

      • 1.判断下当前控制器是不是modal,如果是,就会dismiss
      • 2.如果不是,判断下父控制器是不是modal,如果是,就会dismiss
      • 3.继续判断,直到没有
    • 只有导航控制器子控制器才能获取self.navigationController.

      • 使用self.navigationController时,会判断自己是不是导航控制器子控制器,如果不是,判断自己的父控制器是不是导航控制器子控制器,继续判断,直到没有父控制器.

    父子控制器的简单使用

    • 父子控制的简单使用
    #import "ViewController.h"
    #import "SocietyViewController.h"
    #import "TopLineViewController.h"
    #import "HotViewController.h"
    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UIView *topView;
    @property (nonatomic, weak) UIButton *selectedBtn;
    @property (weak, nonatomic) IBOutlet UIView *contentView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 1.添加所有子控制器
        [self setUpAllChildViewController];
        
        // 2.通过控制器标题,设置按钮显示的文字
        [self setupTopButton];
        
    }
    
    // ----------------------------------------------------------------------------------
    // 初始化
    #pragma mark - 初始化
    
    /** 初始化顶部button */
    - (void)setupTopButton
    {
        NSInteger count = self.topView.subviews.count;
        for (NSInteger i = 0; i < count; i++) {
            // 取出button
            UIButton *btn = self.topView.subviews[i];
            
            // 取出子控制器
            UIViewController *vc1 = self.childViewControllers[i];
            
            // 设置btn显示的文字
            [btn setTitle:vc1.title forState:UIControlStateNormal];
            
            // 设置btn选中状态的文字颜色,需在storyboard中将按钮Type修改为Custom,否则系统默认会把按钮渲染成蓝色
            [btn setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
            
            // 设置默认选中
            if (i == 0) {
                [self btnClick:btn];
            }
        }
    }
    
    /** 添加所有子控制器 */
    - (void)setUpAllChildViewController
    {
        // 1.添加社会控制器
        SocietyViewController *vc1 = [[SocietyViewController alloc] init];
        vc1.title = @"社会";
        [self addChildViewController:vc1];
        // 2.添加头条控制器
        TopLineViewController *vc2 = [[TopLineViewController alloc] init];
        vc2.title = @"头条";
        [self addChildViewController:vc2];
        // 3.添加热点控制器
        HotViewController *vc3 = [[HotViewController alloc] init];
        vc3.title = @"热点";
        [self addChildViewController:vc3];
        
    }
    
    // ----------------------------------------------------------------------------------
    // 添加顶部三个按钮的监听
    #pragma mark - 事件监听
    
    /** 监听顶部三个button的点击 */
    - (IBAction)btnClick:(UIButton *)btn {
        // 1.切换选中状态
        [self changeSelectedBtn:btn];
        
        // 2.设置子控制器view的属性
        // 2.1 根据button的tag值,取出对应的控制器
        UIViewController *vc = self.childViewControllers[btn.tag];
        // 2.2 设置控制器view的背景颜色和button的背景颜色一样
        vc.view.backgroundColor = btn.backgroundColor;
        
        // 2.3 设置子控制器的view的frame
        vc.view.frame = self.contentView.bounds;
        
        // 3.将子控制器的view添加到contentView
        // 3.1 先移除当前控制器view的所有子控件
        [self.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        // 3.2 添加子控件的view到当前控制器的contentView上
        [self.contentView addSubview:vc.view];
    }
    
    /** 切换按钮选中状态 */
    - (void)changeSelectedBtn:(UIButton *)btn
    {
        self.selectedBtn.selected = NO;
        self.selectedBtn = btn;
        self.selectedBtn.selected = YES;
    }
    
    @end
    
    • NSArray类的makeObjectsPerformSelector方法的使用
    // 数组调用该方法时,表示数组里每个元素会执行test方法
    [arr makeObjectsPerformSelector:@selector(test)];
    
    • UIButon的Type如果是System,系统默认会把按钮渲染成蓝色

    5.开发中常见问题

    UIScrollView的自动布局

    • UIScrollView的自动布局思考

      • 1.确定好UIScrollView的滚动范围contentSize
      • 2.怎么确定?搞一个view添加到UIScrollView上,这个view用来确定UIScrollView的滚动范围
      • 3.通过设置这个view约束.来告诉UIScrollView滚动范围
      • 4.如何计算contentSize呢?要计算contentSize必须清楚每个subviews的frame,而subviews的frame居然又要依赖scrollView
    • UIScrollView的自动布局原则

      • 1.UIScrollView的contentSize依赖于subviews.
      • 2.UIScrollView的contentSize必须根据其子控件如UIView的4条边来确定.
      • 3.注意:如果只设置UIScrollView子控件的上下左右间距为0,是不能确定contentSize的,必须设置其子控件UIView的尺寸才能确定4条边.

    UIScrollView自动布局步骤(重要)

    • UIScrollView自动布局实现步骤
      • 1.给UIScrollView添加一个UIView,作为UIScrollView的contentView.之后要添加其他子控件可以往contentView上添加,这样UIScrollView就只有contentView一个子控件,便于布局
      • 2.设置contentView的尺寸(宽,高),因为UIScrollView的contentSize是由它的子控件的frame决定的,contentView是UIScrollView的子控件,所以必须设置contentView的size才能确定contentSize.
      • 3.设置contentView的约束,比如设置约束上下左右间距都为0.

    size和center设置注意点

    • size和center如果一起使用时,如果设置的是frame的size,必须先设置尺寸frame.size,再设置center.如果设置的是bounds的size,就无需考虑先后顺序.因为center就是根据bounds中的size决定的.

    • 设置frame的size属性,先设置尺寸frame.size,再设置center.

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // 创建redView
        UIView *redView = [[UIView alloc] init];
        redView.backgroundColor = [UIColor redColor];
        [self.view addSubview:redView];
        
        // 先设置尺寸
        CGRect frame = redView.frame;
        frame.size = CGSizeMake(200, 200);
        redView.frame = frame;
        
        // 再设置center
        redView.center = CGPointMake(self.view.bounds.size.width * 0.5, self.view.bounds.size.height * 0.5);
    }
    
    • 设置bounds的size属性,无需先后顺序.
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // 创建redView
        UIView *redView = [[UIView alloc] init];
        redView.backgroundColor = [UIColor redColor];
        [self.view addSubview:redView];
        
        // 设置center
        redView.center = CGPointMake(self.view.bounds.size.width * 0.5, self.view.bounds.size.height * 0.5);
        
        // 设置尺寸
        CGRect bounds = redView.bounds;
        bounds.size = CGSizeMake(200, 200);
        redView.bounds = bounds;
    }
    

    bounds和frame简介

    bounds和frame介绍

    • frame和bounds的区别

      • frame:以父控件的左上角为原点
      • bounds:以自己左上角为原点,x,y = 0,(X)
    • frame和bounds描述一个矩形

      • frame:可视范围
      • bounds:描述 可视范围 在 内容范围 区域
    • bounds本质:修改内容原点位置

      • 子控件是相对于控件内容范围
      • frame:相对于父控件,位置永远不变
      • frame:相对于内容,就会改变

    相关文章

      网友评论

          本文标题:02.实战技术 父子控制器,常量Const,开发中常见问题

          本文链接:https://www.haomeiwen.com/subject/xkphkttx.html