您的位置:首页 > 移动开发 > IOS开发

ios-基础之【11】-类的category

2016-03-27 10:37 344 查看
原文链接:http://www.jianshu.com/p/535d1574cb86
参考文:http://www.cnblogs.com/crazypebble/p/3439261.html

类别的简介
在开发中有时会用到Category,类别有三个作用:(1)可以将类的实现分散到多个不同文件或多个不同框架中,方便代码管理。也可以对框架提供类的扩展(因为框架类没有源码,不能修改)。 (2)创建对私有方法的前向引用:如果其他类中的方法未实现,在你访问其他类的私有方法时编译器报错这时使用类别,在类别中声明这些方法(不必提供方法实现),编译器就不会再产生警告 (3)向对象添加非正式协议:创建一个NSObject的类别称为“创建一个非正式协议”,因为可以作为任何类的委托对象使用。有两个方面的局限性: (1)无法向类中添加新的
实例变量
,类别没有位置容纳实例变量。(2)名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。这个类似于方法的重载,但是这里是直接覆盖了原方法。

但是却又经常听说Category只能添加方法不能添加属性,额。。。看这里:



屏幕快照 2016-03-15 21.50.22.png

哦呦,属性哎!!!!什么鬼?不是不能添加属性吗????这个问题真心烦人啊,怎么回事儿呢?以前看的他们说的Category不能添加属性难道不对吗?(⊙o⊙)…相信很多童鞋会有和我一样的疑问。。。

首先解释一下属性和成员变量的区别吧:

属性和成员变量的区别
@property (nonatomic, strong) UIButton *myButton;

我们声明了一个属性,因为现在我们用的编译器已经是LLVM了,所以不再需要为属性声明实例变量了。如果LLVM发现一个没有匹配实例变量的属性,它将为你生成以下划线开头的实例变量_myButton,不需要自己手动再去写实例变量。而且也不需要在.m文件中写
@synthesize myButton;
也会自动为你生成setter,getter方法。@synthesize的作用就是让编译器为你自动生成
setter
getter
方法。那么在
.m
文件中可以直接的使用_myButton实例变量,也可以通过属性self.myButton.两者都是一样的。

注意:
这里的self.myButton其实是调用的myButton属性的getter/setter方法。

假如在Objective-C中我们

@interface MyViewController:UIViewController
{
NSString *name;
}
@end

.m文件中,self.name 这样的表达式是错误的。xcode会提示你使用->,改成self->name就可以了。因为oc中点表达式是表示调用方法,而上面的代码中没有name这个方法。

Objective-C中的点语法说明:
如果点表达式出现在 "=" 左边,该属性名称的setter方法将被调用。如果点表达式出现在右边,该属性名称的getter方法将被调用。所以在oc中点表达式其实就是调用对象的setter和getter方法的一种快捷方式。

@synthesize 还有一个作用,可以指定与属性对应的实例变量,例如
@synthesize myButton = xxxx;
那么
self.myButton
其实是操作的实例变量
xxxx
,而不是
_myButton
了。

在实际项目中,我们一般在.m中这样写:
@synthesize myButton;
这样写了之后,那么编译器会自动生成
myButton
的实例变量,以及相应的
getter
setter
方法。注意:
_myButton
这个实例变量是不存在的,因为自动生成的实例变量为
myButton
而不是
_myButton
,所以现在
@synthesize
的作用就相当于指定实例变量;

如果.m文件中写了
@synthesize myButton;
那么生成的实例变量就是
myButton
;如果没写
@synthesize myButton;
那么生成的实例变量就是
_myButton
。所以跟以前的用法还是有点细微的区别。  

Category中属性Property
类别中只能添加方法,不能添加实例变量。我们经常看见在类别中这样写:

@property (nonatomic, assign) CGFloat x;

在这种情况下是不会自动生成实例变量的。这里添加的属性,其实是添加的setter和getter方法。



屏幕快照 2016-03-15 21.21.14.png

那为什么Objective-C类别中可以添加方法和属性但是不能添加实例变量呢?

在Objective-C提供的runtime函数中,确实有一个class_addIvar()函数用于给类添加成员变量,但是文档中特别说明:

This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.

意思是说,这个函数只能在“构建一个类的过程中”调用。一旦完成类定义,就不能再添加成员变量了。经过编译的类在程序启动后就
runtime
加载,没有机会调用
addIvar
。程序在运行时动态构建的类需要在调用
objc_registerClassPair
之后才可以被使用,同样没有机会再添加成员变量。那为什么可以在类别中添加方法和属性呢?

因为方法和属性并不“属于”类实例,而成员变量“属于”类实例。我们所说的“类实例”概念,指的是一块内存区域,包含了isa指针和所有的成员变量。所以假如允许动态修改类成员变量布局,已经创建出的类实例就不符合类定义了,变成了无效对象。但方法定义是在objc_class中管理的,不管如何增删类方法,都不影响类实例的内存布局,已经创建出的类实例仍然可正常使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: