類別(Category)
類別能夠做到的事情主要是:即使在你不知道一個類的源碼情況下,向這個類添加擴展的方法。
①通過在interface中聲明一個額外的方法并且在implementation 中定義相同名字的方法即可。
②分類的名字(也就是括號括起來的LYG_CategoryName)表示的是:對于聲明于其他地方的這個類(ClassName),在此處添加的方法是額外的,而不是表示這是一個新的類。
③你不可以通過分類為一個類添加額外的成員變量(但是可以使用@dynamic 來彌補這種不足--即運行時Runtime)。
④Category的方法不一定非要在@implementation中實現(xiàn),也可以在其他位置實現(xiàn),但是當調(diào)用Category的方法時,依據(jù)繼承樹沒有找到該方法的實現(xiàn),程序則會崩潰。
類別的使用三種場景:
- 擴展已有的類
類別特別適合已經(jīng)存在大量子類,需要添加公用方法,但又無法修改它們父類(如系統(tǒng)類)的情形 - 引用父類未公開方法
- 實現(xiàn)簡單協(xié)議
類別聲明模板:
.h中
@interface ClassName (LYG_CategoryName)
- (void)lyg_addedMethod;
@end
.m中
@implementation ClassName (LYG_CategoryName)
- (void)lyg_addedMethod {
}
@end
- LYG--是我自定義的前綴,建議都加上一個自定義的前綴。
創(chuàng)建過程如下:
1
2
3
4
以下實例代碼:
實例1:(需要記錄上次的點擊的cell,特此做的分類添加的屬性)--特殊
#import <UIKit/UIKit.h>
@interface UITableView (SpokenHomeWorkTable)
@property (nonatomic,strong) NSIndexPath *recordIndexPath;
@end
#import "UITableView+SpokenHomeWorkTable.h"
#import <objc/runtime.h>
@implementation UITableView (SpokenHomeWorkTable)
static NSString *indexpathKey = @"recordIndexPath";
- (NSIndexPath *)recordIndexPath{
return objc_getAssociatedObject(self, &indexpathKey);
}
- (void)setRecordIndexPath:(NSIndexPath *)recordIndexPath{
objc_setAssociatedObject(self, &indexpathKey, recordIndexPath, OBJC_ASSOCIATION_RETAIN);
}
@end
實例2:擴展已有的類(自定義tabbar上的小紅點)
#import <UIKit/UIKit.h>
@interface UITabBarController (badge)
/**
* 顯示提示小紅點標記
*
* @param index tabbar下標位置
*/
- (void)showBadgeOnItemIndex:(int)index;
/**
* 隱藏小紅點標記
*
* @param index tabbar下標位置
*/
- (void)hideBadgeOnItemIndex:(int)index;
/**
* 移除小紅點標記
*
* @param index tabbar下標位置
*/
- (void)removeBadgeOnItemIndex:(int)index;
@end
#import "UITabBarController+badge.h"
//#define TabbarItemNums 3.0 //tabbar的數(shù)量
@implementation UITabBarController (badge)
- (void)showBadgeOnItemIndex:(int)index{
//移除之前的小紅點
[self removeBadgeOnItemIndex:index];
//新建小紅點
UIView *badgeView = [[UIView alloc]init];
badgeView.tag = 888 + index;
badgeView.layer.cornerRadius = 5;
badgeView.backgroundColor = [UIColor redColor];
CGRect tabFrame = self.tabBar.frame;
//確定小紅點的位置
NSInteger tabbarItemNums = 3;
if ([UserDefault boolForKey:KCreatEnglishTabbar]) {
tabbarItemNums = 4;
}
float percentX = (index +0.6) / tabbarItemNums;
CGFloat x = ceilf(percentX * tabFrame.size.width);
CGFloat y = ceilf(0.1 * tabFrame.size.height);
badgeView.frame = CGRectMake(x, y, 10, 10);
[self.tabBar addSubview:badgeView];
}
//移除小紅點
- (void)hideBadgeOnItemIndex:(int)index{
[self removeBadgeOnItemIndex:index];
}
//按照tag值進行移除
- (void)removeBadgeOnItemIndex:(int)index{
for (UIView *subView in self.tabBar.subviews) {
if (subView.tag == 888+index) {
[subView removeFromSuperview];
}
}
}
/*
//顯示
[self.tabBarController.tabBar showBadgeOnItemIndex:2];
//隱藏
[self.tabBarController.tabBar hideBadgeOnItemIndex:2]
//其它
// self.tabBarItem.badgeValue =@"10";
// UITabBarItem * item=[self.tabBarController.tabBar.items objectAtIndex:2];
// item.badgeValue=[NSString stringWithFormat:@"%d",10];
*/
@end
實例3: 引用父類未公開方法
(比如父類 XSDLabel)
XSDLabel.h
#import <UIKit/UIKit.h>
@interface XSDLabel : UILabel
@end
XSDLabel.m
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
}
@end
XSDLabel1繼承自XSDLabel:
#import <UIKit/UIKit.h>
#import "XSDLabel.h"
@interface XSDLabel1 : XSDLabel
@end
現(xiàn)在需要在設置text時,同時設置文字顏色,調(diào)用父類的giveTextRandomColor:
#import "XSDLabel1.h"
@implementation XSDLabel1
- (void)setText:(NSString *)text {
[super setText:text];
[self giveTextRandomColor];
}
@end
直接編譯會報錯:編譯器提示找不到父類的方法
在子類中聲明父類類別后,即可通過編譯:
#import "XSDLabel1.h"
@interface XSDLabel (private)
- (void)giveTextRandomColor;
@end
@implementation XSDLabel1
- (void)setText:(NSString *)text {
[super setText:text];
[self giveTextRandomColor];
}
@end
類別名private是任意的,但不可以缺省。
- 請不要亂來:蘋果官方會拒絕使用系統(tǒng)私有API的應用上架,因此即使學會了如何調(diào)用私有方法,在遇到調(diào)用其它類的私有方法時,要謹慎處理,盡量用其它方法替代。
實例4: 實現(xiàn)簡單協(xié)議
假設我們需要在文字顏色改變時,發(fā)出一個消息,現(xiàn)在修改XSDLabel如下:
#import <UIKit/UIKit.h>
@interface XSDLabel : UILabel
@property(nonatomic) id delegate;
@end
@interface NSObject (XSDLabelDelegateMethods)
- (void)textColorChanged:(UIColor *)colorNow;
@end
增加delegate,聲明為id,表示接受任何類。
聲明NSObject的類別,聲明它實現(xiàn)的方法。
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
[self.delegate textColorChanged:self.textColor]; // 調(diào)用代理的方法
}
@end
調(diào)用的地方:
#import "XSDLabel1.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
XSDLabel1 *label = [[XSDLabel1 alloc] initWithFrame:CGRectMake(10.0, 40.0, 100.0, 30.0)];
[self.view addSubview:label];
label.delegate = self;
label.text = @"溪石iOS";
}
- (void)textColorChanged:(UIColor *)colorNow {
NSLog(@"text color changed to %@", colorNow);
}
這里利用了任何類都是NSObject子類的特點,通過添加NSObject的類別,實現(xiàn)了一個“簡單”的代理協(xié)議。
對比“正式的協(xié)議”,這種協(xié)議不需要實現(xiàn)類顯示聲明(如<NSCopying>),不過這里還有個缺點,當ViewController未實現(xiàn)textColorChanged方法時,會引發(fā)崩潰,因此在調(diào)用前,需要檢查代理方法是否被實現(xiàn):
#import "XSDLabel.h"
@implementation XSDLabel
- (void)giveTextRandomColor {
self.textColor = [UIColor orangeColor];
if ([self.delegate respondsToSelector:@selector(textColorChanged:)]) {
[self.delegate textColorChanged:self.textColor];
}
}
@end
擴展(Extension)
類擴展就像匿名(也就是沒有那個括號里面的名字LYG_CategoryName)的分類一樣,除了一樣不同的是,類擴展聲明必須在@implementation在實現(xiàn)。
// .h
@interface BaseClass : NSObject
@property (readonly) NSString *privateString; // 該.h文件對外公開
@end
// .m
@interface BaseClass() // 該.m文件對外是不公開的, 當然這里也可以放在專門的一個.h文件中,但同樣不把這個文件進行公開。
@property (readwrite) NSString *privateString;
@end
@implementation BaseClass
@synthesize privateString;
//...
@end
聲明的方法必須要實現(xiàn),不然編譯器會提出警告。
從上面看出,分類和類擴展的相似之處是:都可以為類添加一個額外的方法;
不同之處在于:要添加額外方法,分類必須在第一個@interface中聲明方法,并且在@implementation中提供實現(xiàn),不然運行時出錯。而類擴展,你添加的方法是一個required API,如果不去實現(xiàn),編譯器會警告,而且這個方法的聲明可以不在第一個@interface中去聲明。
區(qū)別:
分類:是不可以聲明實例變量,通常是公開的,文件名通常為:”主類類名+分類類名.h”
擴展:是可以聲明實例變量,是私有的,文件名通常為:”主類類名_擴展標識.h”,注意擴展沒有名的。
區(qū)別分類與擴展
1.都可以在主類中聲明使用
2.通常來講由于分類不能創(chuàng)建實例變化,本質(zhì)上與主類有區(qū)別,所以不建議寫在主類中。
3.擴展與主類緊密聯(lián)系在一起,可以創(chuàng)建實例變量,所以通常來講會把擴展和主類創(chuàng)建在一起。



