您的当前位置:首页正文

分类(category)能否添加成员变量研究

来源:图艺博知识网

前几天遇到项目中要讲 BaseViewController 中的文件抽出来,里面有使用私有成员变量,知道分类中可以访问暴露在. h 文件中成员变量;
原来BaseViewController私有,表示也就没有意愿给自己. m 以外的地方用.

如代码所示:deciveAlertView是一个私有的成员变量,所以将这一个方法抽到在分类中,先要解决私有成员变量的问题;

下面有几种实现方式:

  1. 使用一个全局变量,但是这个全局变量是保存在静态区,不会随着这个类创建的对象 dealloc 而释放,这点不太爽

  2. 直接修改代码逻辑,分类中就不要使用成员变量了

分析

  1. category 里面的方法是 runtime 动态添加进去的,使用Associated Objects也可以动态添加进去,但是这是最后的方法,一般不想这么搞

  2. 使用全局不会释放,这点不太好;放弃

3.直接修改逻辑,这样能不适用成员变量;这样就使方法纯粹了,这也是分类的目的所在

那到底能不能在 category 加成员变量呢?结果是不可以的,除非用Associated;我不要听,我要试试!!!

验证 category 不能加成员变量

第一种:在.h 文件的@ interface 里面加
#import <UIKit/UIKit.h>
#import "CXAlertView.h"

@interface UIViewController (QDCXAlertView)

/** deciveAlertView*/
@property (nonatomic ,strong) CXAlertView *deciveAlertView;

-(void)deciveCodeError:(NSNotification*)notification;
@end

.m文件会报如下 warning,怎么处理呢?
你可以采取如下措施:用@ dynamic 消除编译器 warning, 使用Associated来使用 setter 和 getter;归根到底是用了Associated.

归根到底没有帮你加成员变量

UIViewController+QDCXAlertView.m:20:17: Property 'deciveAlertView' requires method 'setDeciveAlertView:' to be defined - use @dynamic or provide a method implementation in this category

UIViewController+QDCXAlertView.m:20:17: Property 'deciveAlertView' requires method 'deciveAlertView' to be defined - use @dynamic or provide a method implementation in this category
第二种:在. h 文件中的@ interface 用{}

#import <UIKit/UIKit.h>
#import "CXAlertView.h"

@interface UIViewController (QDCXAlertView){
    CXAlertView *_deciveAlertView;
}

-(void)deciveCodeError:(NSNotification*)notification;
@end
  UIViewController+QDCXAlertView.h:14:18: Instance variables may not be placed in categories

结果更加悲剧,直接爆红;说分类中不可以加成员变量,不死心,接着第三种

第三种:在. m 的@ implement 用{}
@implementation UIViewController (QDCXAlertView){
    CXAlertView *_deciveAlertView;
}
UIViewController+QDCXAlertView.m:20:49: Expected identifier or '('

什么鬼,直接爆红,不能理解意思;好吧放弃,第四种

第四种:在. m 搞个 extension, 在 extension的@interface 用@property
@interface UIViewController ()

/** deciveAlertView*/
@property (nonatomic ,strong) CXAlertView *deciveAlertView;
@end

好像可以哦,没有报红,没有 warning. 哦也可以了!!!

等一下,我重写 getter 试试

-(CXAlertView *)deciveAlertView{
    return _deciveAlertView;
}
UIViewController+QDCXAlertView.m:27:12: Use of undeclared identifier '_deciveAlertView'

又报红了,说没有定义;我靠! 白开心一场

第五种:在. m 搞个 extension, 在 extension的@interface 用{}
@interface UIViewController (){
    
    CXAlertView *_deciveAlertView;
}

我去,可以用,没有报红,没有 warning!!!马上就要成功了,不行我要运行下试试.看行不行.我靠爆红了!!!

  "_OBJC_IVAR_$_UIViewController._deciveAlertView", referenced from:
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我累了,不弄了!要休息...

要抽到分类的代码

-(void)deciveCodeError:(NSNotification*)notification{

     NSLog(@"%s",__func__);
    
    NSString * msg = nil;
    if([notification.object isEqualToString:@"001"]){
        msg = @"你的账号已经在其他手机登录了,请注意是否本人操作";
        [[QDNetworkManager share] canelAllRequests];
        
    }
    
    if([notification.object isEqualToString:@"002"]){
        msg = @"你的账号已经在其他手机登录了,请注意是否本人操作";
        
        [[QDNetworkManager share] canelAllRequests];
    }
    
    __weak typeof(self) weakSelf = self;
    //判断最外层 VC是不是自己,是自己才弹
    if (!self.deciveAlertView.isVisible&&![UCSInfo shareInfo].isShowingHasBeenKickOffNotificationAlertView) {
        self.deciveAlertView=[[CXAlertView alloc]initWithTitle:nil message:msg cancelButtonTitle:@"重新登录"];
        [self.deciveAlertView setWillDismissHandler:^(CXAlertView *alertView){
            
            //清除用户的缓存
            [[UCSInfo shareInfo] cleanAllValue];
            
            if (![weakSelf isKindOfClass:[QDLoginContentVC class]]) {
                
                [weakSelf jumpToLogin];
            }
            
        }];
        [self.deciveAlertView show];
        //记录正在显示 alertView,弹完框之后,默认不让手势密码显示了,需要这个来标记
        [[UCSInfo shareInfo]setIsShowingHasBeenKickOffNotificationAlertView:YES];
    }
    
}

写在最后

看看大牛的总结:

连类比事-category和extension

但是category则完全不一样,它是在运行期决议的。就category和extension的区别来看,我们可以推导出一个明显的事实,extension可以添加实例变量,而category是无法添加实例变量的(因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的)。

参考文章

如果喜欢,帮我点个赞哦!

Top