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