也说类别Category

本文深入探讨Objective-C中的类别概念,包括如何使用类别对现有类进行方法和属性的扩展,以及类别与继承的区别。文中提供了具体的代码示例,并讨论了类别在实际应用中的优势和局限。

转载请注明出处,谢谢。http://blog.youkuaiyun.com/cloosen/article/category/1191708


该文章会不定时更新,因为毕竟一次把他写全有点难,有的东西忘了写了什么的,如果想起来会补充进去,如果大家有什么疑问可以留言,如果我了解会不定时回答的,3Q.


题外话:今天终于转正了,签了一份3年有违约金的合同,之前公司VP面我得时候说过,公司招过无数牛人,并且公司会给每个人充裕的时间学习,有些人学习了,有些人荒芜了,三年后有些人变成了行业巨牛,有些人泯然众人了。觉得自己真该努力了,要不然三年之后就不知道什么样子了。


        言归正传,也说说Catagory这个东西,这次学聪明了,不像上次写属性的时候写完了才发现苹果的文档,还好有很多东西跟他不一样,要不然不就白写了?有兴趣的童鞋可以先看看苹果关于类别的文档:http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW2。当然了如果你觉得英文看着不爽,你可以去搜搜,有人把他翻译成了汉语。

        类别(Category),是objective-C所特有的一种设计模式,它用来对现有的类进行方法和属性的扩充和优化,即使在完全不知道现有类的代码的情况下。

        最正常的类别写法如下。这个各个blog,各种文档,各种书几乎都是这么写的,因为苹果文档就是这么写的,哈哈。

.h文件

#import <UIKit/UIKit.h>

@interface UIButton (Test)

- (void)myMethod;

@end

.m文件

#import "UIButton+Test.h"

@implementation UIButton (Test)

- (void)myMethod
{
    NSLog(@"myMethod is success~~~");
}

@end

其他类

[button myMethod];

        这么写没啥好说的,规定的,你用UIButton的实例,他已经包含了该方法。


        类别和继承十分的相似,都是对其他类进行扩展,但是他们有两点不同,1是类别中无法加入实例变量,2是类别中不到万不得已千万别重写主类的方法。

        先说说第一点类别中无法加入实例变量,但是你可以加入属性。因为没有实例变量,所以你也无法用@synthesize,因为类无法给你自动生成setget方法,所以我自己写了setget方法,之前写了个小demo,代码如下:

.h文件

#import <UIKit/UIKit.h>

@interface UIButton (Test)
{
    //什么也不能加,不信你试试
}

@property(nonatomic,retain) NSString *myTitle;

- (void)myMethod;

@end

.m文件

#import "UIButton+Test.h"

@implementation UIButton (Test)

//不能写@synthesize

- (NSString *)myTitle
{
    return @"hahahaha,you can get~~";
}

- (void)setMyTitle:(NSString *)inputTitle
{
    NSLog(@"you want set title :%@",inputTitle);
}

- (void)myMethod
{
    NSLog(@"myMethod is success~~~");
}

@end

其他类

    button.myTitle=@"have a look";
    NSString *abab = button.myTitle;
    NSLog(@"%@",abab);
    [button myMethod];

可以看出控制台输出结果


        可以看到,我们写的set,get方法居然被调用到了,所以我觉得自己实现属性的功能完全靠谱,但是因为没有实例变量,无法存储,所以写得set,get并没起到什么大作用,因为实例变量的最终作用有一点就是帮助你完成setget方法。实例变量的作用就是保存一些我们想要保存的值,用于过度,所以我们很容易就想出可以用static,搞一个全局变量来替代实例变量,从辅助我们完成方法的编写,这样我们就用了联合存储模式(以后的blog会讲)模拟了添加实例变量的效果,代码如下:

.m文件

#import "UIButton+Test.h"
#import <objc/runtime.h>

static char MYTITLE;

@implementation UIAlertView (Block)

@dynamic myTitle;

- (void)setMyTitle:(NSString *)myTitle
{
objc_setAssociatedObject(self, &MYTITLE, myTitle, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)myTitle
{
return objc_getAssociatedObject(self, &MYTITLE);
}


        其中方法可以参考苹果的文档:http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html
提示一下,这个函数API在ios3.1以上才有的,不是说这是联合存储模式实现的么,其实底层用的是NSMapXXX实现的,在ios3.1的时候给封装成了API而已,底层实现将在讲联合存储的时候详细讨论.

        然后再说下第2点类别中不到万不得已千万别重写主类的方法
        override这个词大家都再熟悉不过,oop中子类对父类的方法进行重写,子类的该方法也能用,父类的该方法也能用,体现了多态特性,类别中也可以重写主类的方法,但是此重写非彼重写,我想用replace比较合适,就是将主类的该方法完全替换掉了,你再也获得不到主类的此方法,一般多此继承的类第一句都会是[super XXXXX],没错,你无法调用主类的父类做的事情了,可以说你少做了很多事情,经常会出现一些很诡异的bug。所以说万不得已千万别重写主类的方法,但是什么时候要重写呢,就是当主类该方法有问题的时候,这样我们重写他,将他原来的有问题代码replace掉,当时调试UIPageViewController的时候有一个苹果内部相关的什么类来的忘了,控制台说XX方法有问题,然后被我重写了之后好了.


        什么时候用类别,什么时候用继承,确实是一个很让人纠结的事情,没有必须用类别的情况,也没有必须用继承的情况,按书上说的,如果需要把新的实例变量添加到类中,那么继承是优先选择.类别可以用联合存储的模式来模拟实例变量,但是需要以性能为代价;对复杂的类,进行子类化十分困难,类别可以用来替代继承,一般向基类中添加类别比较好,其所有的子类都能用.
        你可以对一个类进行无限次扩展,即写无数个类别,但是有一点是要保证得,你的类别的名字不能重复


        类别还有个好处就是可以分布在多个文件中,这样无论在开发还是维护中都非常好。类别之前还被用作创建非正式协议,后来被protocol的@optional给替代了,现在几乎没有人用类别来创建非正式协议了。再后来就有了类的扩展(Class Extensions),它主要用来:1.做函数的前置声明,2.用于定义私有属性,可参见之前的blog:http://blog.youkuaiyun.com/cloosen/article/details/7796398。当Extensions中写了没有被实现的方法时,编译器会报warning,而Category中写了没有被实现的方法时,编译器会当成非正式协议,从而什么都不会做.


        最后说一下,其实类别也可以实现protocol,这个我用的比较少,以后搞明白了在加上吧.
协议可以放在类别的.h文件中

@interface UIButton (Test)<UIAlertViewDelegate>


也可以放在类别的.m文件中用Extensions隐藏起来.

        以上就是我所了解和掌握的一些关于类别的知识,现在无论是重构还是构建library,用继承还是很多的,因为对类别了解不够深,估计以后在工作中会积累更多了,书上说类别还是要优于继承的,这篇文章也会随着我慢慢了解而不断更新的.
转载请注明出处,谢谢.http://blog.youkuaiyun.com/cloosen/article/category/1191708
------------------------by 郭大虎


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值