定格 2020-04-17
首先,category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改,并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。
类别主要有4个作用:
1).将类的实现分散到多个不同文件或多个不同框架中。
2).创建对私有方法的前向引用。
3).向对象添加非正式协议。
继承可以增加,修改或者删除方法,并且可以增加属性。
一.通过理解category的概率我们来增加类的方法(项目中常用的category)
//十六进制颜色的类别
label.backgroundColor = [UIColor colorWithHexString:@"#0387EC" alpha:1.0];
//注册和忘记密码的倒计时
[self.verifyCodeBtn countDownFromTime:60 title:@"获取验证码" unitTitle:@"秒" mainColor:[UIColor clearColor] countColor:[UIColor clearColor]];
//常用第三方库(MJRefresh)的头部刷新
WEAK_SELF; self.MainTableView.header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ [weakSelf DataRefresh]; [weakSelf.MainTableView.header endRefreshing]; }];
//第三方库yy_modelWithJSON方法
selfModel *list = [selfModel yy_modelWithJSON:responseObj];
当然还有很多,这里先列举我本人常用的几个。
现在就以扩展UIButton的一个倒计时方法为例子:
建一个UIButton的Category
最后就是在刚才这个category的.m文件里实现这个方法了
@implementation UIButton (countdownButton) - (void)countDownFromTime:(NSInteger)startTime title:(NSString *)title unitTitle:(NSString *)unitTitle mainColor:(UIColor *)mColor countColor:(UIColor *)color { __weak typeof(self) weakSelf = self; // 剩余的时间 __block NSInteger remainTime = startTime; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // 每秒执行一次 dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC); // 子线程(queue)执行event_handler dispatch_source_set_event_handler(timer, ^{ if (remainTime <= 0) { // 倒计时结束 dispatch_source_cancel(timer); // 主线程更新UI dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.backgroundColor = mColor; [weakSelf setTitle:title forState:UIControlStateNormal]; weakSelf.enabled = YES; }); } else { NSString *timeStr = [NSString stringWithFormat:@"%ld", remainTime]; dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.backgroundColor = color; [weakSelf setTitle:[NSString stringWithFormat:@"%@%@",timeStr,unitTitle] forState:UIControlStateDisabled]; weakSelf.enabled = NO; }); remainTime--; } }); dispatch_resume(timer); } @end
然后到要需要的类里面调用这个扩展的方法就可以了。
- (void)viewDidLoad { [super viewDidLoad]; self.title = @"category"; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(60, 260, 300, 30)]; label.text = @"I am a Label"; label.backgroundColor = [UIColor colorWithHexString:@"#0387EC" alpha:1.0]; label.textColor = [UIColor whiteColor]; label.textAlignment = NSTextAlignmentCenter; [self.view addSubview:label]; verifyCodeBtn = [UIButton buttonWithType:UIButtonTypeCustom]; verifyCodeBtn.frame = CGRectMake(60,360,300,40); [verifyCodeBtn setTitle:@"获取验证码" forState:UIControlStateNormal]; verifyCodeBtn.titleLabel.font = [UIFont systemFontOfSize:12]; [verifyCodeBtn setTitleColor:[UIColor colorWithHexString:@"#0387EC" alpha:1.0f] forState:UIControlStateNormal]; [verifyCodeBtn addTarget:self action:@selector(codeSendCode:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:verifyCodeBtn]; } -(void)codeSendCode:(UIButton *)sender { [verifyCodeBtn countDownFromTime:60 title:@"获取验证码" unitTitle:@"秒" mainColor:[UIColor clearColor] countColor:[UIColor clearColor]]; }
展示一下出来的效果
剩下三种就不一一展示了。
二.我们来看看category的作用
1.将类的实现分散到多个不同文件或多个不同框架中。
一般,我们在使用类的时候,我们将类的接口放入.h文件上,而将类的实现放在.m文件中,但不可能将@implementation分散到多个不同的.m文件中。而类别就只要你在需要使用的类或者框架中导入.h,就可以将类的实现分散到多个不同文件或多个不同框架中去。
2.创建对私有方法的向前引用。
类中的私有方法访问不了,如果强行访问,会报错。这个时候可以使用类别来声明这个方法(不必提供方法实现),编译器就不会再产生警告
#import <UIKit/UIKit.h> @interface PsonVC : UIViewController - (void)PublicMethod; //公开方法,可在其他类或子类进行访问 @end #import "PsonVC.h" @interface PsonVC () - (void)PrivateMethod;//在类延展中定义的是私有方法 @end @implementation PsonVC - (void)PublicMethod //.h中有申明,公开方法 { NSLog(@"这是公有方法,其他类可以调用"); } - (void)PrivateMethod {//类延展中有申明,私有方法 NSLog(@"这是私有方法,其他类无法调用");
如果没写类别,在别的类中,是调用不了私有方法的;
在psonVC类的类别中,声明方法的话,那在别的类中调用不会产生警告和报错。这就是创建对私有方法的向前引用。
3.向对象添加非正式协议:非正式协议是NSObject类(显而易见,还包括它的子类)的类别,其所有的子类都含蓄地接受了这个协议。所谓的非正式协议就是类别,即凡是NSObject或其子类的类别,都是非正式协议。创建一个NSObject的类别称为 “创建一个非正式协议”,因为可以作为任何类的委托对象使用。