您的位置:首页 > 运维架构

iOS--@protocol 和 category 中如何使用 @property

2018-01-23 10:01 507 查看

1、category中使用@property

首先需要明确的一点是,在category中不能添加实例变量。
在我之前的一篇博客中有讲到,使用@property可以让编译器自动帮我们生成实例变量的setter/getter方法
现在我们先在类中添加一个实例变量

//in .h
@interface MyClass : NSObject{
NSString _name;
}
@end
//in  .m
@implementation MyClass{
//NSString * _name;
}
@end

注意这里把实例变量声明在头文件里和实现文件里会有所不同

实例变量在类的声明处声明,若它的访问权限不是@private,那它是可以被子类继承的,并且可以被其他类访问(若访问权限是@public)

实例变量在类的实现处声明和在extension中声明,该实例变量是私有的,即使加@public访问权限也是私有的,不可以被子类继承,当然在category中也不能访问

然后创建一个类别

//in .h
#import "MyClass.h"
@interface MyClass (Extension)
@property(nonatomic,copy)NSString * name;
@end
//in .m
#import "MyClass+Extension.h"
@implementation MyClass (Extension)
//@synthesize name = _name;
@end

编译器给出了警告
大意是说属性name需要提供setter/getter方法,也就是说现在编译器不能自动给我们生成setter和getter方法了


添加一句@synthesize name = _name;也是不行的



此时就需要我们自己写setter/getter方法了

//in category.m
#import "MyClass+Extension.h"
@implementation MyClass (Extension)
- (void)setName:(NSString *)name{
_name = name;
}
- (NSString *)name{
return _name;
}
@end

如果之前我们将实例变量声明在类声明部分的话,这样执行一发,就没问题了。但是很多时候,我们不希望去修改已经写好的类,而且定义的实例变量在类实现部分。那么此时在category中我们就不能直接访问到该实例变量了,例如

//in .h
@interface MyClass : NSObject
@end
//in  .m
#import "MyClass.h"

@implementation MyClass{
NSString * _name;
}
@end

像这种情况,我们就需要利用到runtime了。

objc_setAssociatedObject 相当于 setValue:forKey 进行关联value对象

objc_getAssociatedObject 用来读取对象

objc_AssociationPolicy  属性 是设定该value在object内的属性,即 assgin, (retain,nonatomic)...等

objc_removeAssociatedObjects 函数来移除一个关联对象,或者使用objc_setAssociatedObject函数将key指定的关联对象设置为nil。

我们可以使用这四个函数,在category中任意添加实例变量。例如之前的就可以写成

#import "MyClass+Extension.h"
#import <objc/runtime.h>
@implementation MyClass (Extension)
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self,@selector(name),name,OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name{
NSString *n = objc_getAssociatedObject(self, @selector(name));
return n;
}
@end

就相当于在类中添加了一个名为name的实例变量,与_name不同。
当然使用这种方式并不比使用@property管理内存方便。

2.在@protocol中使用@property

在@protocol中使用@property在编译阶段,编译器会自动帮我们加上setter/getter的声明,但是实现还是需要采用该协议的类去写。因此在协议中使用@property主要是希望采用该协议的类能够实现该属性
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: