分类和扩展的使用

作者: 小白进城 | 来源:发表于2017-07-31 10:05 被阅读21次

    一、类扩展

    格式:

    @interface 类名()
    //属性
    //方法
    @end
    

    说明:

    1、类扩展可以为某一个类添加额外的属性,成员变量,方法等,并且都是该类的私有项

    2、类扩展一般都是在.m文件中,在类实现的上方,比如在我们新建UIController时,系统已经为我们写好了类扩展,再其他文件中,如UIView里,我们也可以手写上述格式来使用类扩展

    3、通过新建类扩展文件来使用类扩展,但是子类是不能使用父类类扩展成员,因为是父类私有的


    二、分类/类别

    格式:

    @interface 类名(分类名字)
    /*方法声明*/
    @end
    @implementation类名(分类名字)
    /*方法实现*/
    @end
    

    说明:

    1、类别用来为已有的类(通常是系统的类)添加新方法

    2、类别一般只扩充方法,不能新增属性和成员变量


    三、分类/类别的应用场景

    a、扩展系统类方法

    这是我们经常使用分类的情形,分类的好处就是在不新建类的情况下,可以通过扩展系统类方法来实现某种功能,例如分类NSString,将日期转换为字符串类型

    .h 文件

    /**
     日期转成字符串
     @param date 日期
     @param format 格式
     @return 日期字符串
     */
    +(NSString*)dateToString:(NSDate*)date format:(NSString *)format;
    

    .m 文件

    +(NSString*)dateToString:(NSDate*)date format:(NSString *)format{
        NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
        [dateFormat setDateFormat:format];
        NSString *dateString = [dateFormat stringFromDate:date];
        return dateString;
    }
    

    这样我们就可以直接通过NSString类来调用日期转字符串方法了:

    分类来新增方法

    b、方法工厂

    有时候,我们手写初始化代码时,要写控件的很多样式,通过分类,我们可以快速完成控件初始化。这种方式依旧是新增方法,我们通过给UIButton新增方法来说明:

    /**
     *  普通的按钮样式
     */
    +(UIButton*)buttonNormalWithTitle:(NSString*)title
                               target:(id)target
                             selector:(SEL)selector
                                frame:(CGRect)frame
                                bgImage:(UIImage*)bgImage
                         imagePressed:(UIImage*)imagePressed
                            textColor:(UIColor*)aColor
                             textFont:(UIFont*)textFont;
    

    这样,我们就可以在初始化时,调用该法类快速完成一个按钮的初始化了,是不是很方便呢?


    c、新增属性

    一般来说,分类里是不能添加属性的,即使新增里属性,也不会自动生成setter和getter方法,但是OC的特点之一就是动态运行时,我们可以根据这一特性来关联实现setter和getter方法,以达到新增属性的功能

    这里我们给UIViewController新增属性为例:

    1)、新建UIViewController的分类

    新建分类

    2)、新增属性

    @interface UIViewController (Based)
    @property (copy ,nonatomic) NSString *name;
    @end
    

    3)、使用运行时完成setter和getter方法

    #import <objc/runtime.h>
    @implementation UIViewController (Based)
    -(void)setName:(NSString *)name{
        objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    -(NSString *)name{
        return objc_getAssociatedObject(self, _cmd);
    }
    @end
    

    4)、导入文件,使用

    self.name = @"LOLITA";
    NSLog(@"%@",self.name);
    

    5)、运行结果


    运行结果

    这里,可能有人会问了,我可以直接在Controller里新增这个属性啊?使用分类做会不会多次一举呢?当然不是,有没有遇到过这样的情况呢?在维护别人的代码时,想针对共用的属性、方法、控件等做统一的管理,但是项目中又没有使用继承,新建一个基础类成本又太大,那么使用分类是你比较好的选择


    为何是使用UIViewController来举例呢?笔者在维护别人的代码时,就遇到的上述头疼的问题,就采用来分类来优化项目,将通用部分统统放到了分类中去,并使用懒加载的方式,到了需要的时候才会申请空间,并大大减少了代码量,提高了复用性。

    共用的部分通常包括:指示器Loading控件,导航栏视图、自定义返回手势、检查更新、获取网络状态、权限提示框、请求类等等,将这些放到分类中,大大减少了重复造轮子的问题,并且不像继承那样具有依赖性


    补充:新增控件

    @property (strong, nonatomic) NavigationView *navigationBar;
    
    -(NavigationView *)navigationBar{
        NavigationView *navBar = objc_getAssociatedObject(self, _cmd);
        if (navBar==nil) {
            navBar = [[NavigationView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 64)];
            objc_setAssociatedObject(self, @selector(navigationBar), navBar, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            navBar.backgroundColor = RiseColor;
            navBar.delegate = self;
            [self.view addSubview:navBar];
        }
        return navBar;
    }
    -(void)setNavigationBar:(NavigationView *)navigationBar{
        objc_setAssociatedObject(self, @selector(navigationBar), navigationBar, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    

    四、体会

    1、合理的使用分类可以很好的简化代码

    2、如果有不正确的地方,或者有其他分类的使用,欢迎留言交流

    3、针对笔者的问题,如果有更好的解决办法,也欢迎留言交流,谢谢

    相关文章

      网友评论

        本文标题:分类和扩展的使用

        本文链接:https://www.haomeiwen.com/subject/gvpllxtx.html