「Objective-C」类和方法

1. 类方法和对象方法

对象方法

  • 减号 – 开头
  • 只能由对象来调用
  • 对象方法中能访问当前对象的成员变量(实例变量)

类方法

  • 加号 + 开头
  • 只能由类(名)来调用
  • 类方法中不能访问成员变量(实例变量)

类方法的好处和使用场合

  • 不依赖于对象,执行效率高
  • 能用类方法,尽量用类方法
  • 场合:当方法内部不需要使用到成员变量时,就可以改为类方法

可以允许类方法和对象方法同名

2. self 关键字

self 的用途

  • 谁调用了当前方法,self就代表谁
  • self出现在 对象/类 方法中,self就代表 对象/类
  • 成员变量和局部变量重名

当成员变量和局部变量同名时,采取就近原则,访问的是局部变量
用self访问成员变量,区分同名的局部变量

使用细节

  • 出现的地方:所有的OC方法中(对象方法\类方法),不能出现在函数
  • 作用
    使用 “self->成员变量名” 访问当前 对象\类 方法调用的成员变量
    使用 “[self 方法名];” 来调用方法(对象方法\类方法)

3. 继承

好处:

  • 抽取重复代码
  • 建立类之间的关系
  • 子类可以拥有父类中 所有的 成员变量 和 方法

坏处:增强了代码的耦合性
重写:子类 重新实现 父类的某个方法,覆盖父类以前的方法

使用情境:

  • A是B,则A继承B
  • A拥有B,则A组合B「即B为A内部的一个成员变量」

super 关键字

  • 直接调用父类的 成员变量 和 对象方法
  • 使用情景:子类重写父类方法时想保留父类的一些行为

注意

  • Objective-C 是 单继承
  • 基本上所有类的根类是NSObject
  • 不允许子类和父类拥有相同名称的成员变量
  • 父类必须声明在子类前面「实现不用在子类前」
  • 调用某个对象/类的方法时,优先去当前 对象/类 中找,若找不到去父类中找
  • 子类会继承父类所有的变量「不管是否是私有,只是能不能直接访问的问题」
  • 父类只在 implementation 里定义的变量,子类也会继承

4. 多态「多种形态」

定义:父类指针 指向 子类对象
作用:若参数中使用的父类类型,则可以传入父类、子类对象
注意

  • 编译时 编译器会检查当前类型对应的类中有没有调用方法「因为OC是弱语法」
  • 运行时 系统会动态检测对象的真实类型
  • 局限性:父类型变量不能直接调用子类的方法「可以通过强制转换来实现」

5. 对象和对象的关系

组合关系:类型相同 或 实现同一接口 的对象组合到一起
依赖关系:A对象 做 B对象的 形参 或 方法的局部变量,B 依赖 A
关联关系:A对象 做 B对象的 一个成员变量,A 和 B 有关联关系

6. 构造方法

完整的创建一个对象「new 方法的步骤」

  1. 调用 +alloc 方法,分配存储空间,返回一个对象 Cat *c = [Cat alloc];
  2. 调用 -init 方法,进行初始化,把成员变量的值初始化为 0,返回初始化的原来对象 c = [c init];
    [Cat new] == [[Cat alloc] init]

目的:对象创建出来,成员变量就有一些固定的值
方法:

  • 重写 – init 方法
// implementation 中
- (instancetype)init {
    // 1.调用 父类「super」 的 init 方法:初始化父类中声明的 成员变量属性 和 其他属性
    self = [super init]; // 得到当前对象 self
    if (self != nil) { // 初始化成功,nil 是空 == 0
        _min = 10; // 2. 进行子类内部成员的初始化
    }
    return self;// 返回已经初始化完毕的对象
}
  • 自定义构造方法
// implementation 中
- (instancetype)initWithAge : (int)age {
    // 简化写法

    if (self = [super init]) { 
        _age = age;
    }
    return self;
}

7. 类的声明可以不写「仅仅警告」

  • 有类的声明
// 声明
@interface Sample : NSObject {
    // 可以有成员变量
    int a; // 默认@protected}

- (void)test;
@end

// 实现
@implementation Sample {
    // 也可以有成员变量「这种做法很少见」
    int b; // 默认 @private
    //注意:interface 和 implementation 不能声明同名的成员变量
}

- (void)test{
    NSLog(@"有类的声明");
}
@end
  • 没有类的声明「实现 必须写在main函数之前」
// 实现
@implementation Sample : NSObject
- (void)test{
    NSLog(@"没有类的声明");
}
@end

8. id 和 instancetype 数据类型

实质:id 和 instancetype 都是 万能指针类型,能 指向/操作 任何 objc 对象
区别:

  • id 在编译时,不能 判断对象的真实类型
    可以 定义变量,作为返回值,作为形参
  • id 不能用点语法,id可以调用任何对象的方法「这样不利于编译器检查错误」
  • instancetype 编译时,判断对象的真实类型
    只能用于返回值

注意:自定义构造方法 返回值 尽量使用 instancetype 而不是 id
用法:

id  d = [Person new]; // d为指针,id 类似于 NSObject *
NSObject *o =  [Person new];

9. @class 关键字

  • 格式:@class 类名1, 类名2 「注:为了可读性,一般一个@class 对应一个类名」
  • 仅仅告诉编译器 类名 是个类,防止两个类互相调用.h文件 编译器报错
  • 开发中引用的 类规范:
    1. 在 .h 文件中用 @class 来声明
    2. 在 .m 文件中用 #import 来包含类所有的东西
  • @class 优点:
    多个头文件 #import 了同一个头文件 a时,若 a 稍有改动,则这多个头文件就都要重新编译,为了减轻编译器的负担 使用 @class

10. 类的本质

类对象:类本身也是个对象,是 Class 类型对象
Class 类型定义:<code>typedef struct objc_class *Class;</code>
为了调用类方法,获取类对象「对象的类」:<code>Class n = [对象名 class];</code> 或 <code>Class n = [类名 class];</code>

11. 分类 Category

作用:在不改变原来类内容的基础上,为类添加方法「继承也有这样的作用」
好处:一个庞大的类可以分模块开发,由多人编写,更有利于团队合作
用法:分类可以定义在 单独的 .m文件和 .h文件中,也可以定义在原来类中

  • 一般情况下,都定义在单独文件中
  • 定义在原来类中的分类,只要能看懂语法就好

格式:

  • 在 原类名+分类名.h 文件中「文件名是规范」
#import "原类名.h"
@interface 类名 (分类名)
    // 方法声明;
@end
  • 在 原类名+分类名.m 文件中
#import "原类名+分类名.h"
@implementation 类名 (分类名)
    // 方法实现
@end;

注意:

  • 分类只能增加 方法,不能增加 成员变量
  • 分类方法可以访问原来类的成员变量
  • 分类可以覆盖原来类同名的方法,会使类中原来的方法失效
  • 方法调用优先级:1.分类「最后参与编译的分类优先」→ 2.原来类 → 3.父类

12. Class Extension 类扩展

定义:匿名的 Category,写在 .m/.h 文件中
作用:为某个类扩充一些私有的 成员变量 和 方法 的声明
格式:

#import "A.h" // 在 .m 文件中
// 类扩展
@interface A(){
    int _a; // 私有的成员变量 _a
}
- (void)sum(int) :a addWith :(int)b; // 是声明
@end

@implementation A {
    int _b;
}
- (void)function{
    // 实现
}
@end
    原文作者:_凉风_
    原文地址: https://www.jianshu.com/p/e58e5a0f67eb
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞