美文网首页
高效编写代码的方法(二十一):Category(1)

高效编写代码的方法(二十一):Category(1)

作者: 蜂猴 | 来源:发表于2016-07-16 18:43 被阅读528次

避免在Category中出现属性

属性是一种数据的封装形式,理论上来说,你也可以在Category中声明属性,但是我们应该尽量避免这样做。
因为这样做,Category是不会生成任何实例变量的,当然也不能够由实例变量去合成一个属性变量的。
比如我们创建一个Friend的Person分类,用来处理Person类中关于“Friend”的逻辑内容,如果你像下面这样声明:

#import "Person.h"

@interface Person (Friendship)

@property (nonatomic, strong) NSArray *friends;

- (void)addFriend:(Person *)aFreind;

@end

编译会得到这样的警告:

Property 'friends' requires method 'setFriends:' to be defined - use @dynamic or provide a method implementation in this category

这个有点“莫名其妙”的警告的意思是无法为这个属性生成实例变量,从而也不能合成一个属性变量。
如果你非要在分类中声明这个friends的数组属性,那么需要将friend声明为@dynamic或者自己为实例变量提供setter和getter方法。将属性声明为dynamic意思就是告诉编译器,自己会在runtime生成setter和getter方法,让编译器给我们放行通过:

@implementation Person (Friendship)
@dynamic friends;

@end

另一种方法如下:

static const char *kFriendProperty = "friend";
@implementation Person (Friendship)
//@dynamic friends;
- (NSArray *)friends
{
    return objc_getAssociatedObject(self, kFriendProperty);
}

- (void)setFriends:(NSArray *)friends
{
    objc_setAssociatedObject(self, kFriendProperty, friends, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

虽然通过上面的方法我们可以理论上的实现为Category增加属性,但是这仍然是不推荐的,如果属性是像NSMutableArray那样可变的,那么处理起来就可能会更加麻烦。因此,最理想的方法还是将属性和数据的封装放到主类中。

使用类扩展来隐藏实现细节

其实类扩展,听着很高大上,只不过是下面代码中注释的部分。

#import "Person+Friendship.h"
#import <objc/runtime.h>
//@interface Person()
//
//@end

static const char *kFriendProperty = "friend";
@implementation Person (Friendship)
- (NSArray *)friends
{
    return objc_getAssociatedObject(self, kFriendProperty);
}

这个学过iOS的应该都知道一点其用法,主要是用来声明一些隐藏的变量用的。
例子如下:

#import "Person+Friendship.h"
#import <objc/runtime.h>
@interface Person()
{
    NSString *_aString;
}
@end

static const char *kFriendProperty = "friend";
@implementation Person (Friendship)
//@dynamic friends;
- (NSArray *)friends
{
    return objc_getAssociatedObject(self, kFriendProperty);
}

此时aStirng就作为一个“隐藏”的实例变量而不用对外暴露。
多的不多做介绍,主要总结如下

  • 1 通过类扩展可以向类中新增实例变量。

  • 2 如果某属性在主接口中声明为“readonly”,而类的内部又要用设置方法修改此属性,那么就在类扩展中将其扩展为“readwrite”。

  • 3 如果想让类所遵循的协议不暴露在主接口,可以在类扩展中进行声明。

相关文章

网友评论

      本文标题:高效编写代码的方法(二十一):Category(1)

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