OC基础(三)—— 从方法到封装

目录


类方法
NSString
匿名对象
属性的封装(setter、getter)
对象之间的关系

类方法

  1. 在1个Target中无法访问另外1个Target中的类.

  2. OC中的方法分为两种.

    1).对象方法/实例方法:

    我们之前学习的方法 就叫做对象方法. 如果想要调用对象方法就必须要先创建对象 通过对象名来调用.

    2).类方法.

    类方法的调用不依赖于对象.如果要调用类方法 不需要去创建对象.而是直接通过类名来调用.

  3. 声明.

    1).对象方法的声明:

    对象方法声明使用 -

    - (返回值类型)方法名;
    - (void)sayHi;
    

    2).类方法的声明:

    类方法声明使用 +号.

    -(返回值类型)方法名;

    和对象方法的声明实现除了+-其他的都是一样的

  4. 调用.

    1). 对象方法: 先创建对象 再通过对象名来调用.

    2). 类方法: 不需要通过对象名来调用 所以如果要调用类方法不需要创建对象.而是直接使用类名来调用

    [类名 类方法名];

  5. 分析一下 类方法和对象方法的调用过程.

    类方法的特点
    1). 节约空间: 因为调用类方法不需要创建对象. 这样就节约了空间.

    2). 提高效率: 因为调用类方法不需要拐弯 直接找到类 直接执行类中的类方法.

  6. 在类方法中不能直接访问属性.

    1). 属性是在对象创建的时候.跟随着对象一起创建在对象之中.

    2). 类第1次被访问的时候,会做类加载. 是把类的代码存储在代码段

    因为属性只有在对象创建的时候才会创建在对象之中.

    而类方法在执行的时候.有可能还没有对象. 对象都没有 你访问个毛的属性.

    虽然不能直接访问属性. 但是我们可以在类方法中创建1个对象 访问这个对象的属性

  7. 在类方法中也不能通过self直接调用当前类的其他的对象方法

    因为对象方法只能通过对象来调用 而这个时候没有对象.

  8. 在对象方法中可以直接调用类方法.

  9. 什么时候我们可以将方法定义为类方法呢?

    如果方法不需要直接访问属性 也不需要直接调用其他的对象方法.
    那么我们就可以将这个方法定义为类方法

    这样就 节约空间 提高效率.

  10. 关于类方法的规范.

    1). 如果我们写1个类,那么就要求为这个类提供1个和类名同名的类方法.
    这个方法创建1个最纯洁的对象返回.

    因为苹果和高手写的类都遵守这个规范.

    2). 如果你希望创建的对象的属性的值由调用者指定 那么就为这个类方法带参数.

    类名+WithXXX: ……

NSString

  1. NSString是1个数据类型.用来保存OC字符串的.

  2. 其实NSString是Foundation框架中的1个类.
    作用: 存储OC字符串的
    所以.OC中的字符串本质上是用NSString对象来存储的.

  3. 其实完整的标准的创建NSString对象的方式是:

    NSString *str0 = [NSString new];
    
    NSString *str1 = [NSString string];
    
    这种方式创建的字符串是空字符串 @""
    
    但是.NSString是我们最常用的1个对象 所以OC使用了1种更为简单的方式来创建字符串对象.
    
    直接使用@来表示1个OC字符串.
    
    @"jack" 这个其实本质上是1个NSString对象.
    
    NSString *str = @"jack";
    
    @"jack" 是1个NSString对象  str的值是这个对象的地址.
    
    %p 打印的是指针变量的值
    
    %@ 打印的是指针变量指向的对象.
    
  4. NSString最常用的两个类方法.(到目前为止第二个用到的最多)

    1). + (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString;
    
    instanceType 作为返回值 代表返回的是当前这个类的对象.
    
    作用:将C语言的字符串转换为OC字符串对象.
    
    2). + (instancetype)stringWithFormat:(NSString *)format, ...  使用频率100分.
    (这里我想加一点自己的理解:这个就用到了上面所说的,用类方法创建对象,创建对象的时候由调用者来指定对象的属性,那就传入了参数format)
    
    作用: 拼接1个字符串对象.使用变量或者其他数据拼接成OC字符串.
    
    int age = 19;
    
    NSString *name = @"小明";
    
    //@"大家好我叫xx 我的年龄是xx"
    
    NSString *str =  [NSString stringWithFormat:@"大家好,我叫%@,我今年%d岁",name,age];
    
    NSLog(@"str = %@",str);
    
  5. 最常用的对象方法

    1). length方法 返回值为NSUInteger其实就是unsigned long.
    得到字符串的字符的个数 可以处理中文.中文长度是:一个汉字代表1
    2). 得到字符串中指定下标的字符.
    
    - (unichar)characterAtIndex:(NSUInteger)index;
    返回值是unichar 其实就是unsinged short 占据2个字节.
    
    如果要输出unichar变量的值使用%C 钛金眼睁大 这是大写的C
    
    3). 判断两个字符串的内容是否相同.
    
    a. 判断两个字符串的内容是否相同 不要用==去判断  因为这样有可能会出问题.
    
    b. 判断相等的方式.
    
    - (BOOL)isEqualToString:(NSString *)aString;
    
    所以,判断两个字符串是否相等 应该使用这个方法区判断 才会得到正确的结果.
    
    4).比较字符串的大小.
    
    - (NSComparisonResult)compare:(NSString *)string;
    
    完全可以使用int类接收结果. 因为返回值是1个枚举.
    
    返回值如果是 -1 说明 小于
                0     等于
                1     大于
    

匿名对象

(我在push控制器的时候经常用匿名对象,前提是这个需要push的控制器不需要定制什么属性)

  1. 我们之前创建对象的做法.
    Person *p1 = [Person new];
    让1个指针指向1个对象 这个指针就叫做这个对象的名字.

  2. 匿名对象.
    没有名字的对象,如果我们创建1个对象,没有用1个指针存储这个对象的地址.
    也就是没有任何指针指向这个对象 那么这个对象就叫做匿名对象。

  3. 如何去使用1个匿名对象呢?

    因为new实际上1个类方法. 这个方法做的事情创建对象(4个步骤). 返回值是创建的对象的地址.

    [Person new] 这句代码的结果实际上就是创建的那个对象的指针. 那我们可以直接使用.

    [Person new]->_name = @"jack";

    [[Person new] sayHi];

  4. 注意点.

    1). 匿名对象只能使用1次.

    2). 每次创建匿名对象都是不同的对象 。
    [Person new]->_name = @"jack";
    创建了1个对象

    [Person new]->_age = 18;
    又创建了1个对象
    [[Person new] sayHi];
    第3个对象.

  5. 有神马用?

    1). 如果某个对象的成员只会被我们使用1次.用完之后这个对象再也不需要了 那么就可以使用匿名对象.

    2). 如果方法的参数是1个对象,而调用者为这个参数赋值的对象 就是专门来给这个方法传递的
    并且这个对象调用者不会使用 那么这个时候就可以直接为方法传递1个匿名对象 。(简单点说,就是调用者用这个对象只是为了来调用某个方法的,并不会再使用它)

属性的封装

  1. 面向对象的三大特征是什么?

    封装
    类就是更高级别的封装.类将数据和行为封装为了1个整体.
    好处:
    -> 屏蔽内部的实现.外界不需要知道内部是如何实现的 只需要知道这个对象有什么用.
    -> 方便操作.
    -> 后期的维护十分的便利.

    继承

    多态

  2. 封装功能的时候可以引出一个问题.

    • 就是为对象的属性赋值的时候 语法上其实只要 数据的类型 是 属性的类型就是可以的.

      但是,情理上这么做是不合的.

      比如Person对象有1个int类型的属性_age 表示1个人的年龄.
      为这个对象的_age属性赋值的时候 其实只要是int类型的数据 语法上都是完全可以的.
      但是1个人的年龄 正常情况下是在 0-200之间的.

    • 如何解决:

      在为对象的属性赋值的时候,我希望将这个数据做1个逻辑验证.
      如果为属性赋的值在这个逻辑范围之内 那么我们就把这个值赋值给属性.否则我们就做默认处理.

      就像我们希望为Person对象的_age属性赋值的时候,要判断1下为_age属性赋的值是不是在0-200之内.
      否则我们就做默认处理.

  3. 如何实现这个需求(这就引出了赋值方法setter)

    • 将属性的@public去掉.因为一旦写上@public就意味着外界可以直接访问对象的这个属性.(这里再强调一下,默认情况下,写在@interface大括号内的属性外界是无法直接访问的,就是会出现一条划了线的属性名)

      外界一旦可以直接访问这个属性 那么外界就可以任意的为这个属性赋值 这个时候你拦都拦不住.

      去掉@public 外界就无法直接访问这个属性 也就无法赋值了.

    • 为类提供1个方法,这个方法专门为这个属性赋值.这个方法我们叫做setter

      a. 这个方法一定是1个对象方法 因为这个要为属性赋值.
      b. 这个方法没有返回值. 因为这个方法做的事情 仅仅是为属性赋值就可以了.
      c. 这个方法的名称必须以set开头. 跟上去掉下划线首字母大写的属性名.
      d. 这个方法一定是有参数的. 参数的类型和属性的类型一致.参数的名称和属性的名称一致(去掉下划线)
      e. 在方法的实现中,判断传入的数据是否符合逻辑.如果符合逻辑则赋值 否则做默认处理.
      f. 外界想要为对象的属性赋值 那么就调用这个对象的setter方法 将要赋值的数据传入给这个方法.
      方法会对这个数据进行验证 如果符合验证 就会把数据赋值给属性 否则就会做默认处理.

    • 这么一写,我们确实可以在为对象的属性赋值的时候做1个逻辑验证了.(这又引出了getter方法)

      但是问题就是 在外界无法取出属性的值了.
      那就再写1个方法,专门用来返回属性的值.这个方法我们叫做getter方法.

      a. 这个方法一定是1个对象方法 因为这个方法做的事情是拿到属性的值返回.
      b. 这个方法肯定有返回值 返回值的类型和属性的类型一致.
      c. 这个方法的名称直接就是属性的名称(去掉下划线的)
      d. 这个方法没有参数
      e. 这个方法的实现是直接将属性的值返回.
      f. 这个时候,如果外界希望得到属性的值.那么就只需要调用这个getter方法就可以了.

  4. 容易犯错的地方:

    1). 属性的@public修饰符没有去掉.如果没有去掉 就算你的getter setter封装的再牛X 也没有N用.

    2). 搞不清楚对象. 判断参数的值是否符合逻辑 将参数赋值给属性.

    3). getter setter 方法名极度不规范。

  5. 什么时候需要为属性封装setter和getter?

    1). 只要属性需要被外界访问.就要为这个属性封装setter和getter。

    哪怕在赋值或者取值的时候没有任何逻辑验证.

    2). 如果属性只在类的内部访问.那么就不需要为其封装getter setter

  6. 只读封装与只写封装.

    只读封装: 为属性封装的时候 只提供getter 不提供setter
    只写封装: 为属性封装的时候.只提供setter 不提供getter

对象之间的关系

组合关系
依赖关系
关联关系
继承关系

  1. 组合关系.
    1个对象是由多个对象组合起来的.

    比如.计算机对象. 是由主板对象、CPU对象、内存对象、硬盘对象...组合起来的.

    主板、内存、硬盘作为计算机对象的属性.

    那么这个时候,计算机对象和主板、内存、硬盘的关系为 组合关系.

  2. 依赖关系
    1个对象的方法的参数是另外1个对象.那么我们就说他们的关系是依赖关系.

    比如,B类是A类方法的参数,我们就说A类依赖于B类.

    美女打电话的例子.

    人类:
    callWithPhone:(Phone *)phone;
    我们就说人类依赖于电话类. 人要打电话 就必须要有电话对象.

    电话类:

    耦合度: 当修改1个对象的时候 对另外1个对象的影响程度.
    1个类修改了 另外1个类就玩完.
    低耦合: 当修改1个对象的时候 对另外1个对象的影响较小甚至没有影响.
    高内聚: 1个对象仅仅做自己相关的事情.
    单一职责原则. 1个类只做自己的事情.别人的事情给别人做.

  3. 关联关系
    关联体现的是两个类之间语义级别的一种强依赖关系,
    比如我和我的朋友,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性 的,
    而且双方的关系一般是平等的。关联可以是单向、双向的。
    表现在代码层面,
    为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。

    案例:人使用iPad听歌.(也就是缺一不可,缺少一个对象,这个方法就无法执行)

  4. 继承

你可能感兴趣的:(OC基础(三)—— 从方法到封装)