1.单继承:继承是单向的(不能相互继承)、继承也是单点的(子类只能由一个父类)。
在类的.h文件中,@interface后的冒号表示继承关系,冒号左边的类继承自冒号右边的类(没有特殊说明,一般式NSObject,所有的类最终都继承自该类)
2.传递性:子类具备父类的所有实例变量和方法(不包括私有的变量和方法),并且能通过父类继承到父父类的实例变量和方法
3.实例变量:实例变量的书写规则:实例变量的名字遵循驼峰法命名,在实例变量前使用下划线开头。
实例变量的可见度:
@public实例变量的可见度的修饰词,public表示公共的,使用public修饰实例变量可以在类的外部随意访问。
@protected表示受保护的可见度,可以在类及其子类中访问,不能在main中访问
@private私有的可见度,只能在本类中访问,不能在其他地方访问
4.类的方法:
-:减号是方法的类型修饰符,减号表示这个方法只能由对象来调用 (这个消息只能发送给对象)
如果是+号表示这个方法只能由类来调用(这个消息只能发送给类)
[super 方法名]去父类中执行方法的实现
description方法是由系统提供的一种描述对象的是一个实例方法,默认打印一个对象时,会调用该方法,返回类名+对象地址,我们可以重写这个方法,将若干实例变量拼接为一个字符串返回,这样我们就可以打印想要的信息
5.方法的返回值:
基本数据类型:int、float、double...
对象类型:类名+*
id或者nstancetype:含义和void 含义一样,由谁调用这个方法,那么该方法执行完后的返回值类型和调用者的类型一致
6.OC中方法没有实现时,程序不会马上崩溃,首先在其继承树查找这个方法有没有实现,然后通过相应代码在整个工程中查找这个方法有没有实现,最后再在错误处理机制中查找这个方法有没有实现,要是没有实现则程序崩溃。
7.#include和@class的区别
#include是C中导入头文件的指令,#import是OC中导入头文件的指令,#import可以自动检测是否产生了循环导入,如果有,则自动断开其中一条链路,而#include本身并不具备这种检测、规避功能。
@class:@class可以解决循环引入后,断开某条线路的情况。在声明文件中,使用@class将类名声明出来,并不导入该类,在实现文件中,使用#import导入类的头文件。这样不仅仅避免了循环引入,而且互相把对类声明为自己的实例
8.便利构造器:
便利构造器是将创建对象时的alloc、init这两步操作封装在一个方法里,以后再创建对象时,只要调用便利构造器即可。便利构造器是一个类方法,由类名调用。便利构造器方法名的命名规则:首字母小写的类名+参数形容词、参数类型、参数名。便利构造器可以携带0到多个参数(根据具体需求选择参数个数)。
9.block语法:
在C语言中,我们可以使用函数指针指向一个函数,这样我们就可以通过函数指针来调用这个函数(将函数名交给函数指针)。
如果函数没有函数名,也就是匿名函数,匿名函数在C中是不合法的,也无法直接调用或通过指针调用。但是在OC中,我们可以通过block变量来保存这个匿名函数,在之后合适的地方通过block变量名来调用这个函数
定义block变量的方法和定义函数指针的方法一样,唯一不同的是函数指针使用,block变量使用^将后边的字符声明为block变量名
int (^myBlock)(int,int);
将同类型的函数(匿名函数)赋值给block变量:
^int (int a, int b)匿名函数
1."^"将函数声明为block变量的值,如果没有托字符,则这个函数无法赋给block变量
2.匿名函数的返回值类型可以省略,但是参数类型和参数的名字不可以省略
myBlock = ^int (int a, int b)
{
return a + b;
};
在block内部可以访问局部变量和全局变量,但是只能修改全局变量,如果想修改局部变量则需要在局部变量前使用__block来修饰。
10.类的管理:
分类(Category):常用来给拿不到源代码的类添加新方法或用来管理一个类的方法列表,将功能相似的方法声明、实现在一个分类中。在分类中只能添加新的方法,不能添加新实例变量
在能拿到源代码的类中(自定义类),我们可以使用分类来管理功能相似的方法,也可以在分类中给该类添加新方法。对于在分类中声明的新方法,我们既可以在本类的实现中添加实现方法,也可以新建一个Category的实现标签,在这个实现标签中实现新方法
延展(Extension):是用来给类添加私有实例变量、方法的一种管理方式。
我们可以通过延展来给类添加私有的实例变量,该实例变量不管可见度是什么,在类的外部都不能被访问到,只能在类的内部访问。
延展和分类的区别:
1.分类中只能添加新方法,不能添加实例变量,延展中可以添加私有方法和私有变量
2.使用分类添加的方法可以在类的外部访问,使用延展添加的实例变量和方法,只能在类的内部使用,在外部访问不到
3.分类可以使用一对.h.m文件来管理,延展一般直接在类的.m中添加延展标签,在延展标签中写代码
协议(Protocol):协议是一套标准(一堆法的声明),只有.h 件,接受该协议的对象实现协议中定义的方法。
协议就像一张任务清单(或便利贴),上面写了一堆需要处理的事。清单交给谁,谁就要去完成清单上规定的任务。协议定义好之后,需要有类去遵守这个协议,实现协议中的方法。遵守协议即在.h 件的父类名后写上<协议名>。实现协议中的方法即在.m 件中实现协议中的方法。相当于给这个类添加了若干个方法。这个类的实例就可以调用这些方法。
@required //使用@required修饰的方法是必须实现的方法
@optional//使用@optional修饰的方法可以选择性实现
10.代理(delegate):使用场景:凡是某些任务自己不去实现,想让别人去实现的时候,就可以指定一个代理,让代理帮你去做。你只需要通知代理去做某某事。声明一个代理实例变量 id<协议名> _delegated;
11.属性:属性是OC2.0之后的新语法,使用属性编译器会帮我们生成对应的实例变量和getter和setter方法。使用@propety来声明属性。
声明一个name属性,编译器会自动帮我们生成一个在前边加了下划线的实例变量:@property NSString *name;
@synthesize在较早的编译器中,需要使用@synthesize来让编译器自动生成属性所对应实例变量的setter和getter方法的实现部分
使用@dynamic + 属性名 表示组织编译器生成属性(实例变量)的setter和getter方法,此时我们需要手动实现这对儿方法。当我们希望自己手动实现getter、setter方法时,需要先在头文件中声明该属性所对应的实例变量,或者使用@synthesize来将属性名和实例变量名关联起来,如果使用@dynamic来强制阻止编译器自动合成方法实现,则必须手动在头文件中声明相关实例变量。如果程序员手动实现了属性对应实例变量的getter和setter方法,则方法调用时会调用手动实现的方法。
12.属性的属性(特征):
第一类:读写控制
readonly:只生成getter方法
readwrite:生成getter和setter方法
setter:用来指定setter方法的名字
getter:用来指定getter方法的名字
第二类:原子性控制
atomic:原子安全设置,在多线程环境中,一次只能有一条线程访问。默认是安全性设置,但是这种设置会降低程序的性能,一般不会考虑
nonatomic:非原子安全设置,setter和getter方法中,并不像atomic一样添加线程安全控制代码,而是大大提高程序的性能,但是在多线程环境中,需要考虑线程安全问题
第三类:语义设置
assign:使用assign声明的属性对应的实例变量存取器方法的实现,是在方法里直接赋值、取值,并没有操作内存的引用计数。一般用来将基本数据类型的属性特征声明为assign
reatin:使用reatin声明的属性对应实例变量存取器的方法的实现,内部会做内存优化处理:修改对象的引用计数。
copy:使用copy声明的属性对应的实例变量存取器方法的实现,内部也会做内存优化处理:将对象拷贝一份,然后修改新对象的引用计数(区分深拷贝和浅拷贝)。
一般情况下,将OC中的对象声明为reatin或copy特征
12.点语法:
点语法:我们可以使用点语法来调用对应实例变量的setter和getter方法。使用点语法,并不是直接访问了实例变量,而是通过实例变量的存取器方法来给实例变量取值、赋值。
-
KVC:键值编码,一种给对象的实例变量赋值的方法
KVC是一种间接的给实例变量赋值的方法,K表示key表示实例变量(属性),V表示value是赋给实例变量的值。
kVC常用赋值(修改值)方法:
setValue:forKey:
setValue:forKeyPath:
setValue:forUndefinedKey:
setValuesForKeysWithDictionary:
KVC常用获取值方法:
valueForKey:
valueForKeyPath:
valueForUndefinedKey:
在使用KVC给一个未知的属性赋值时会调用setValue:forUndefinedKey:方法,该方法默认实现是抛出一个异常(程序崩溃)。我们可以重写该方法,避免程序崩溃
14.OC中的内存管理:
OC作为一门编程语言,具备垃圾回收机制,但是在iOS平台使用引用计数机制
内存管理方式:
1.GC(垃圾回收机制):由系统判断内存是否需要回收,不需要显式的去写内存释放代码。
2.MRC(手动管理引用计数):程序员自己手动去写代码来记录引用计数的值,并且控制值的增减。
3.ARC(自动管理引用计数):编译器在它认为合适的地方为我们添加记录引用计数增减的代码,ARC是iOS5之后编译器的特性,并不是OC的语法特性。
注意:在iOS中有ARC和MRC这两种内存管理机制,但MAC OS里可以有GC这种机制。
iOS中采用引用计数的机制去管理内存,当你向持有某个对象的时候(拥有对象所有权),你需要使该对象的引用计数+1,当你不再需要持有该对象时,你要把刚刚加上的1再减回去。
当这个对象的引用计数变为0时,表示没有任何对象持有该对象,则这个时候系统会自动调用该对象的dealloc方法来回收该对象所占用的内存。
我们不能过度释放对象,因为对象的引用计数变为0时,该对象所在的内存就已经可能被其他数据覆盖,该指针变成了野指针,向一个野指针发送消息,可能造成程序崩溃,也肯能不崩溃,难以调试。此时我们就可以开启“僵尸对象”来调试这种错,开启该模式后,凡是向已释放的对象发送消息,程序必然崩溃。僵尸模式下,一个已释放的对象所占用的内存不会被覆盖,而且这片内存空间不能被访问,所以向一个僵尸发送消息,程序一定会崩溃。僵尸模式在app上线时一定要关闭,否则app会被审核拒绝上线。
+alloc:创建出对象,并且把对象的引用计数值加1
-retain:将对象的引用计数加1.不管该对象之前的引用计数是几,它都l只加1。
-release:将对象的引用计数减1,使用release将person计数减1,变为0,打印时不会显示0,会直接回收。
-copy操作是将源对象拷贝一份副本,并将副本的引用计数加1,源对象的引用计数保持不变。
-autoreless:在出了自动释放池之后,将对象的引用计数减1。
如何创建一个自动释放池
第一种:@autoreleasepool {} 第二种:创建一个自动释放池对象,从这里开始就是自动释放池的起始位置 NSAutoreleasePool *autoreleassPool = [[NSAutoreleasePool alloc] init]; 中间是自动释放池的空间。 释放自动释放池对象,也就是设置自动释放池的结束位置 [autoreleassPool release];