OC课程笔记总结9-核心语法4:分类

课程:核心语法

category :分类,类目,类别,在oc中经常使用。分类是依赖于类的,先有类再有分类。类和分类都是同一种类,而分类可以在这种类的基础上进行一些方法的扩充,而不用通过继承创建一个新的类再进行扩充。注意的是分类只能扩充类的方法(类方法和对象方法都可以),不能扩充类的属性。一个类可以有多个分类,每个分类都有自己的名称。但是要记住,分类和类都是同一种类。

定义分类的格式:

@interface 类名 (分类名)

分类方法声明

@end

@implementation 类名 (分类名)

分类方法实现

@end

在实际开发中如果遇上某些类十分庞大,一个类中有几百甚至上千个方法,这时候可以通过分类来对方法进行划分,便于管理和维护。

在团队开发中,可以不同的人员共同构造一个类,每个人员写同一个类的不同部分,通过分类组合成为一个最终的类。通过包含不同分类的头文件即可将不同分类组合在一起,成为一个完整的类。实际开发中分类按照分模块来写,并用模块来命名。

分类的作用就是在不改变原来类的内容的基础上,为这个类扩充一些方法。并且分类只能扩充方法,不能扩充属性。在分类的方法中,可以访问类的成员变量。对于同名的方法,分类的优先级是最高的,对象调用某个方法时先去找分类中的方法。查找顺序为 :分类,类,父类,父类的父类。。。超类。

但是分类中的方法并不是重写,而是覆盖,如果在分类中定义了一个和类中同名的方法,那么就是覆盖掉类中的方法,对象永远不能再调用原来类中的方法,只能调用分类的方法。而对于不同的分类中的同名方法,根据编译器编译的顺序来决定最后留下的是哪个方法,最后编译的分类就是最后留下的方法,而编译的顺序是按照头文件的声明顺序来决定的,并且编译器在编译时只对。m和。c文件进行编译,。h文件只是声明作用,并不会实际编译。

由于分类中的同名方法会发生覆盖现象,因此不建议在分类中定义同名的方法。


在开发过程中,多数是为系统自带类进行分类扩充,而不是对自定义的类进行扩充。当系统自带的类的方法不能满足功能需求时,就可以通过分类进行方法扩充。而系统自带的类的源代码是闭源的。分类名一般按功能命名,并且分类名和类名首字母都大写。


题外补充:对于字符一定要使用单引号‘’引用,对于数字字符也一样。


分类扩充的方法可以被类的对象或者类直接调用,而不用加注标识,只要方法名对应即可。

而所说的开源的类库就是包含了很多不同的分类,定义有相关的功能,只要包含了相关的。h头文件后,通过参考API就可以拿来直接使用了。


项目开发中要养成 分文别类的好习惯,对于不同的模块放在不同的文件夹中。


类的深层研究:

OC中的类的本质也是一个对象,oc是源自c,开上去oc是面向对象的,实际的底层还是面向过程的。

任何类在使用时都会首先加载进内存中,但是每种类只加载1次,相当于创建了一个类对象。而创建对象后,对象的方法实际上是放在类中的。所有的实例对象的isa指针都指向类对象,而类对象的isa指针指向这个类的元类对象。


类本身也是一个对象,只要是对象就是有类型,而类对象的类型就是类类型:class    //  注意,不要加*号。既然类也是一个对象,那么就会有自己的属性,其中一个属性就是class,这个属性表明了这个对象是属于哪个类的。

类A的实例对象的类属性是类A,并且类A的类对象的类属性也是类A。

所以这个属性的数据类型是类类型,即一个指向什么类的指针,但是不需要加*号。同时系统中也自带了一个get属性的方法:【类对象 class】,这个方法就会返回的是一个指针,输出指针得出的结果是这个指针所指向的地址的值,用%p接收指针的值(p相当于16进制输出)。任何对象调用class 方法都可以得到一个指向这个对象的类的指针,即获得这个类的类对象。


其实在oc中所有的方法都必须是有对象调用的,通常所说的类方法由类调用,其实是指有类对象调用,对象方法由实例对象调用,实例对象源于类对象。

类=类名=类对象。获取类对象的方式有两种,一种是对象调用对象方法,另一种是类对象调用类方法。其实类方法就是类对象的方法。对象方法是实例对象的方法。但得到的都是同一个类对象。因为在内存中每个类的类对象只有一个。


类的加载过程和初始化。

只要程序一启动就会加载所有的类进入内存中,加载的顺序是先父类后子类。

有这样一个类方法:+(void)load,这个方法在类加载的时候执行,每个类只加载一次。只要程序一启动,就会加载类,而加载类就会调用load方法,所以load方法是一定会执行的方法,如果在程序中某些类根本没被使用到,甚至主函数中没有包含这些类的头文件,只要这些类是在同一个项目文件夹中,那么一样会被加载进内存中。

目前最新版本的xcode已经无法这样实现这个函数的功能了?

另一个函数 +(void) initialize 则是在类第一次 使用的时候调用,用到类即用到类对象,在调用类方法比如new或者或者alloc或者init方法时就是用到了类,这时候initialize方法就会调用。

分类也会同样加载,只要分类在这个项目中,即使没有包含头文件声明,即使没有使用这个类,load 也一样会被调用。load 是加载时调用的函数,因此不管类还是分类都会被加载,load都会被调用。

而如果分类中定义了initialize方法,那么在第一次使用类时优先使用分类的这个方法,即类的方法被覆盖,调用的是分类的方法。

目前最新版本的xcode中已经无法实现。

先加载父类,再加载子类,先初始化父类,在初始化子类,先调用父类的load,在调用子类的load,可以通过initialize方法来监听某个类什么时候被使用。


description(描述) 方法:

有两种的description 方法

- description

+ description

接收一个对象类型用于打印输出用%@接收,可以把整个对象的属性一次性打印出来而不用单独打印。但是在默认情况下,用nslog输出一个对象输出的是对象所在的内存地址,输出是<类名 内存地址>。

具体的过程是先调用对象的- descripton 方法,这一方法返回值是一个oc的字符串对象(NSString *),所以用%@来接收,默认返回的字符串就是<类名 内存地址>

要想一次打印出对象的属性,重写子类的description方法即可,因为同名方法以子类的方法优先。

拼串用NSString 的一个类方法:stringWithFormat,并且这个方法可以接收带有参数的变量值,然后在拼起来,这个方法会经常使用。

如果是要打印输出一个类(即类对象),那么系统首选使用的是+ description 方法,默认返回值也是一个字符串,返回类型是<类名> 没有内存地址值。

总的来说,打印输出的是实例对象,就用实例对象的方法,打印输出的是类,就用类的方法。要想改变输出的结果,那么就重写对应的方法即可。

NSLog不仅可以输出对象和类,还能输出很多东西,详细可以参考官方的文档,



SEL 类型:

SEL类型是一种数据类型。这种类型的变量代表方法。一个SEL类型的数据就代表一个方法。有类才能有方法。在类中包含了方法列表。每个方法都有一个相对于的SEL数据。一对一,一个方法一个sel数据。

而每个对象中都有一个isa指针指向类,包括类对象,也有指针指向元类。方法都存在类中,对象根据isa指针找到自己所属的类,然后获得相关的方法。

系统会把方法封装成为SEL类型的数据,对象会同sel数据找到对应的方法。其实sel数据实际对应的是方法的地址。有了地址就可以找到方法,然后就可以调用方法。找方法的过程是缓存的,找过一次就会记录下来,然后再调用

方法时就不用再找一次了,这样会提高程序运行的速度。使用@selector(方法名) 就可以获得 方法的地址。如果方法是有参数的,那么方法名是包括冒号和描述参数信息的说明的,方法名要写全。

SEL 是selector的缩写,对应着方法。消息机制中的消息指的就是sel,发出这个消息找到对应的方法并调用。

每个类的实例对象方法列表都存在类对象中,而类对象的对象方法存在于元类中。系统中还隐藏了一个属性 _cmd,这个属性也是一个SEL数据,每个方法的内存中都有着这么一个数据,这个数据对应了一个方法,

这个方法就是当前方法,即指向了自己。记住sel找的是方法的地址,通过地址找到方法。

通过SEL找地址再调用方法是比较消耗性能的,如果某个方法经常调用的话还会有优化的方法。





































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值