关闭

Category

标签: ios
209人阅读 评论(0) 收藏 举报
分类:

在创建iOS的特有Objective-C 文件的时候我们可以看到Category和Extentsion


Category相信是不难学习的,并且非常重要,可以动态地对OC的类添加方法,为什么称为动态,例如,如果声明一个关于NSData的类目并且在里面实现了两个方法,是不是每一个NSData的相关子类都有了这个类目特性,不,你可以不导入头文件,这时候就好像压根没有实现。

在输入File名字之后,Xcode会自动地帮你创建  “Class” + “File Name”  这种结构,并且其.h .m文件如下:

#import <Foundation/Foundation.h>

@interface NSString (Extend)

@end

#import "NSString+Extend.h"

@implementation NSString (Extend)

@end

而最基本的类UIView,都有大量这样的形式的声明:

@interface UIView(UIViewRendering)

- (void)drawRect:(CGRect)rect;

- (void)setNeedsDisplay;
- (void)setNeedsDisplayInRect:(CGRect)rect;


我们都知道,协议是不允许添加实例变量的,那Category呢?直接动手敲


非常明显啦,instance variables may not be placed in categories , 实例变量不能被放置于分类中


我们先来看看UITableView中一个非常实用的分类:

// This category provides convenience methods to make it easier to use an NSIndexPath to represent a section and row
@interface NSIndexPath (UITableView)

+ (NSIndexPath *)indexPathForRow:(NSInteger)row inSection:(NSInteger)section;

@property(nonatomic,readonly) NSInteger section;
@property(nonatomic,readonly) NSInteger row;

@end

见:http://www.cocoachina.com/bbs/read.php?tid=292400

如果你觉得上面section 和 row为什么能放,哈哈,你就和我一样too young too naive啦,如果看懂了上面的解释,你就该懂了,就是getset方法理解的不透彻,属性变量时自动地声明了getset方法,所以上面的@property不是着重于 “变量” 这一侧,而是重于方法这一侧,所以我们为什么能直接地用:

indexPath.section
indexPath.row

其实是使用了NSIndexPath的get方法来取得 值 而已,而且很明显是readonly只能调用它的get方法而不能调用它的set方法。这种情况下,是不会生成实例变量的。

同理于Protocol协议中的实例变量和属性变量的区别也是同样原理。

见:http://blog.csdn.net/itianyi/article/details/8618128

这里文章中部分也阐述了。

但是注意的是,即使不能为分类添加实例变量,但是分类是包含相关类本身的所有属性和实例变量的,所以可以在分类的方法实现上大胆使用!



那如果我们非得添加实例变量呢? 从网上面收集到的信息大概有两类。

1.使用匿名分类(扩展):

其实这里的匿名分类可以说和分类其实没多大关系,具体使用就是把@interface写在实现文件里,并且将:superClass 改成 ()罢了,所谓匿名就是不要名字,这时候注意,这里的实例变量和方法声明都是私有的。

2.使用全局变量

这个没去研究。

3.通过Associative References来添加

http://www.cnblogs.com/wengzilin/p/4331685.html?utm_source=tuicool



接下来是Category和Extension有什么区别。

动手建立一个关于NSString类的ExtensionTest,如下:


发现并没有.m文件。

这里说到了一点:把代码写到原始类的.m文件中。


经过网上资料的了解,原来Extension和匿名Category非常非常像,简直可以直说就是,其实自己看就知道,创建了之后的格式基本一样。总结来说就是:扩展(extension)可以添加成员变量, 扩展(extension)就是匿名的Category。



那我们到底什么时候需要继承子类实现新方法什么时候需要使用分类呢?

1.如果需要动用到新的实例变量,理所当然用继承子类 

2.如果需要大批量增加类的方法并不改变类本身(不能和原有方法重名,会权重于分类,从而覆盖原有方法),使用分类



实战,在做仿微信键盘的时候遇到一个分类的实现和使用:

1.

#import <UIKit/UIKit.h>

@interface UIImage (StrethImage)

+ (id)strethImageWith:(NSString *)imageName;

@end

#import "UIImage+StrethImage.h"

@implementation UIImage (StrethImage)

+ (id)strethImageWith:(NSString *)imageName
{
    UIImage *image=[UIImage imageNamed:imageName];
    
    image=[image stretchableImageWithLeftCapWidth:image.size.width*0.5 topCapHeight:image.size.height*0.5];
    
    return image;
}
@end

self.backImageView.image = [UIImage strethImageWith:@"toolbar_bottom_bar.png"];

原来就是增加了拉伸图片以适配的功能,与其说增加,不如说是封装了如此的功能,如果我们拆开在.m中也是可以实现的,所以这里的分类更多的是一种规范,封装的作用!


2.

做仿微信键盘的时候见到这个方法,点进去endEditing一看:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}
这个endEditing是一个很显然的扩展:

@interface UIView (UITextField)
- (BOOL)endEditing:(BOOL)force;    // use to make the view or any subview that is the first responder resign (optionally force)
@end

因为是原生类我们不知道其实现,但是有趣的是,且看它处于的位置和命名规律:

可以看到它放在UITextField类的头文件来声明,并且分类的名字为UITextField,结合在实际中的使用就会知道这里的分类的作用是一种相互合作,相互补充的作用!

补充:这些叫做  category methods !






参考资料:

基本语法:http://www.cnblogs.com/kenshincui/p/3869639.html#category

整理和解释:http://blog.sina.com.cn/s/blog_a2c098b50101gsn0.html

突破添加实例变量的瓶颈:http://www.cnblogs.com/wengzilin/p/4331685.html?utm_source=tuicool

实例变量和属性变量在分类的纠结:http://www.cocoachina.com/bbs/read.php?tid=292400



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:79866次
    • 积分:4418
    • 等级:
    • 排名:第7229名
    • 原创:374篇
    • 转载:7篇
    • 译文:4篇
    • 评论:4条
    最新评论