Objective-C分类

作者: 蜗牛你慢慢来 | 来源:发表于2019-07-25 14:02 被阅读0次

    第24条:将类的实现代码分散到便于管理的数个分类之中

    1. 什么是分类?
      例如,我们把个人信息建模为类。
    #import <Foundation/Foundation.h>
    NS_ASSUME_NONNULL_BEGIN
    @interface EOCPerson : NSObject
    @property (nonatomic, copy, readonly) NSString *firstName;
    @property (nonatomic, copy, readonly) NSString *lastName;
    @property (nonatomic, strong, readonly) NSSet *friends;
    -(id)initWithFirstName:(NSString *)firstName
                  lastName:(NSString *)lastName;
    /** Friendship methods */
    -(void)addFriend:(EOCPerson *)person;
    -(void)removeFriend:(EOCPerson *)person;
    -(BOOL)isFriendsWith:(EOCPerson *)person;
    /** Work methods */
    -(void)performDaysWork;
    -(void)takeVacationFromWork;
    /** Play methods */
    -(void)goToTheCinema;
    -(void)goToSportsGame;
    @end
    

    可以用“分类”机制把刚才的类改写成下面这样:

    #import <Foundation/Foundation.h>
    NS_ASSUME_NONNULL_BEGIN
    @interface EOCPerson : NSObject
    @property (nonatomic, copy, readonly) NSString *firstName;
    @property (nonatomic, copy, readonly) NSString *lastName;
    @property (nonatomic, strong, readonly) NSSet *friends;
    -(id)initWithFirstName:(NSString *)firstName
                  lastName:(NSString *)lastName;
    @end
    
    @interface EOCPerson (Friendship)
    -(void)addFriend:(EOCPerson *)person;
    -(void)removeFriend:(EOCPerson *)person;
    -(BOOL)isFriendsWith:(EOCPerson *)person;
    @end
    
    @interface EOCPerson (Work)
    -(void)performDaysWork;
    -(void)takeVacationFromWork;
    @end
    
    @interface EOCPerson (Play)
    -(void)goToTheCinema;
    -(void)goToSportsGame;
    @end
    

    在本例中,类的基本要素(属性与初始化方法等)都声明在“主实现(mainimplementation)”里。
    分类后,又可拆分成如下文件:
    EocPerson+Friendship(.h/.m)
    EocPerson+Work(.h/.m)
    EocPerson+Play(.h/.m)

    1. 如何创建分类示意


      创建分类1
      创建分类2
    #import "EOCPerson.h"
    NS_ASSUME_NONNULL_BEGIN
    @interface EOCPerson (Friendship)
    -(void)addFriend:(EOCPerson *)person;
    -(void)removeFriend:(EOCPerson *)person;
    -(BOOL)isFriendsWith:(EOCPerson *)person;
    @end
    NS_ASSUME_NONNULL_END
    

    使用分类后,如果想用分类中的方法,要记得在引入EOCPerson.h时一并引入分类的头文件。

    1. 分类的好处。
      3.1 易于管理
      3.2 便于调试


      image

      3.3 隐藏实现细节
      在编写准备分享给其他开发者使用的程序库时,可以考虑创建Private分类。如果程序库中的某个地方要用到这些方法,就引入此分类的头文件。而分类的头文件并不随程序库一并公开,于是该库的使用者也就不知道库里还有这些私有方法了。

    第25条:总是为第三方类的分类名称加前缀
    向第三方类中添加分类时,总应给其名称加上你专用的前缀。
    向第三方类中添加分类时,总应给其中的方法名加上你专用的前缀。

    #import <Foundation/Foundation.h>
    NS_ASSUME_NONNULL_BEGIN
    @interface NSString (CSK_HTTP)
    //Encode a string with URL encoding
    -(NSString *)csk_urlEncodedString;
    //Decode a URL encoded string
    -(NSString *)csk_urlDecodedString;
    @end
    NS_ASSUME_NONNULL_END
    

    避免莫名其妙的错误,因为如果你覆盖掉了官方的后者别人的代码,或者别人覆盖掉了你的代码,这种bug是很难追查的。

    第26条:勿在分类中声明属性

    1. 把封装所用的全部属性都定义在主接口里。
    2. 属性所要表达的意思是:类中有数据在支持着它。属性是用来封装数据的。
    #import "EOCPerson.h"
    NS_ASSUME_NONNULL_BEGIN
    @interface EOCPerson (Friendship)
    @property (nonatomic, strong) NSArray *friends;
    -(void)addFriend:(EOCPerson *)person;
    -(void)removeFriend:(EOCPerson *)person;
    -(BOOL)isFriendsWith:(EOCPerson *)person;
    @end
    NS_ASSUME_NONNULL_END
    

    例如,这段代码将属性添加到分类中,编译的时候会出现如下警告信息。


    image

    意思是说此分类无法合成与friends属性相关的实例变量,所以开发者需要在分类中为该属性实现存取方法。
    可以使用关联对象(参见第10条)来解决在分类中不能合成实例变量的问题。

    #import "EOCPerson+Friendship.h"
    #import <objc/runtime.h>
    staticconstchar *kFriendsPropertyKey = "kFriendsPropertyKey";
    @implementation EOCPerson (Friendship)
    -(NSArray *)friends
    {
        returnobjc_getAssociatedObject(self, kFriendsPropertyKey);
    }
    -(void)setFriends:(NSArray *)friends
    {
        objc_setAssociatedObject(self,
                                kFriendsPropertyKey,
                                friends,
                                OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    @end
    

    这样做可行,但不太理想。因为我们再为属性实现存取方法的时候,经常会忘记遵从其内存管理语义。不推荐。

    相关文章

      网友评论

        本文标题:Objective-C分类

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