——————————————————————————————
super 可以用来调用方法, 但是不能和 self 一样打印出来
从面向对象的观点中, 可以得到, 万物皆对象
创建对象所用的类, 也是一个对象
就是描述类的类 Class
例如:
@interface Person:NSObject
...
Person *p = [Person new];
此时, p 所指向的时一个对象, 而 Person 就是这个对象的类
Person 也是一个对象, 描述这个类的类就是 Class
Class 就是一个具有指向自己类型的指针的结构体
类比:
struct CZClass {
struct CZClass *isa;
};
对象由类描述, 类也是对象, 由元类描述, 元类也是由另一个元类描述...
最后全部归于 NSObject
——————————————————————————————
// 既然类对象就是类本身, 那么应该可以使用类对象创建实例
Person *p1 = [Person new];
Class obj = [Person class];
Person *p2 = [obj new];
[p2 method];
// 在源代码中不使用类名, 来创建对象, 动态创建对象的过程
——————————————————————————————
OC 是对 C 的一个扩展
SEL 数据类型, 就是 OC 引入的新的数据类型
SEL 数据类型, 存储的就是方法的地址, 类似于函数指针
语法:
SEL 变量名 = @selector(方法名);
// 创建 SEL 类型的变量, 并将其指向 method 方法
SEL s = @selector(method); // 选择器
// 方法如果需要调用, 那么就需要提供对象了
Person *p = [Person new];
[p performSelector:s];
[[Person class] performSelector:@selector(classMethod)];
[p method];
——————————————————————————————
之前写属性, 使用的是 set 方法和 get 方法, 来操作我们实例变量
set 方法和 get 方法的严格名字是 设置器 和 读取器
在 OC 中提供了一种特定的语法来表示属性, 就是 @property 语法
以前编写一个类, 每提供一个实例变量, 就需要对应的提供两个方法, 一个 set 一个 get
现在只需要使用 @property 就可以了
——————————————————————————————
// 就是帮助我们实现 get 和 set 方法
@synthesize name;
@synthesize age;
@synthesize gender;
// 从 Xcode 4.4 以后, 就被 @property 取代
@synthesize name, age, gender;
// @synthesize 自动生成的变量的名字是 不带下划线的
// @synthesize name;
// - (void)setName:(NSString *)name { self->name = name; }
// - (NSString *)name { return self->name; }
// 如果想要 @synthesize 使用指定的实力变量, 可以在后面赋值
* 在 Xcode 4.4 以前
* 使用 @property 只是声明了两个方法, 一个 set 一个是 get,
* 需要手动的在 .m 文件中实现方法体, 如果手动实现方法体
* 需要定义实例变量
* 使用 @synthesize 可以让编译器自动的帮忙提供 set 和 get 的方法体
* 使用这个方法, 不需要提供实例变量, @synthesize 会自动的生成
* 实例变量, 是不带下划线开头的名字. 属性写成什么名字, 就生成什么
* 名字的实例变量
* 如果使用 @synthesize 可以指定默认的变量名
*
* 在 Xcode 4.4 以后
* 只需要 @property 一个关键字就可以了
——————————————————————————————
编译型程序, 程序的生命周期, 需要经过
编写源码 -> 编译 -> 目标文件 -> 链接 -> 可执行文件
脚本语言, 不需要编译, 程序的运行需要一个解释器
解释器读取一个数据, 执行一行
OC 是一个具有动态特征的语言
编译时不会严格的做类型检查, 只有运行时才会检查
最典型的结论, interface 中声明了方法, 但是在 implementation 中没有实现
函数的编译是编译时检查
OC 的编译是运行时检查
*/
——————————————————————————————
/ 父类 Person(name, age, gender)
// 子类 Student(score):Person
// 创造子类的对象: Student *stu = [Student new];
// 内存应该怎么分配?
// 1, 根据子类和父类中所有的实例变量的大小, 得到一个内存大小的数字
// 2, 会向操作系统申请内存, 类似于 malloc
// 3, 将内存中的垃圾数据清零
// 4, 应该调用父类的构造方法, 将继承下来的数据初始化
// 5, 再调用子类的构造方法初始化子类对象中应有的实例变量
——————————————————————————————
// OC 开发当中有一个推荐
// 在类的里面使用实例成员,
// 如果取值, 建议直接访问实例变量
// 如果赋值, 建议使用属性
——————————————————————————————
// 1, 第一种初始化方法
// if(self = [super init]) {
// super.name = name;
// self.age = age;
// self.gender = gender;
// self.score = score;
//
// }
// return self;
// 2, 第二种方法
if(self = [super initWithName:name andWithAge:age andWithGender:gender]) {
self.score = score;
}
return self;
}
——————————————————————————————
// id 类型一般使用在通用参数,通用返回值的方法中, 以及存储所有数据类型的数据的时候
// 正因为不检查, 或检查不严格, 容易引起一些漏洞问题
// instancetype 专门用在构造方法的返回值上
——————————————————————————————
——————————————————————————————
——————————————————————————————
——————————————————————————————
——————————————————————————————
——————————————————————————————