给分类添加 属性

给分类添加 属性,第1张

1、分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。所以<原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性>

为什么在分类中声明属性时,运行不会出错呢?

既然分类不让添加属性,那为什么我写了@property仍然还以编译通过呢?

我们知道在一个类中用@property声明属性,编译器会自动帮我们生成_成员变量和setter/getter,但分类的指针结构体中,根本没有属性列表。所以在分类中用@property声明属性,既无法生成_成员变量也无法生成setter/getter。

因此结论是:我们可以用@property声明属性,编译和运行都会通过,只要不使用程序也不会崩溃。但如果调用了_成员变量和setter/getter方法,报错就 在所难免 了。

既然报错的根本原因是使用了系统没有生成的setter/getter方法,可不可以在手动添加setter/getter来避免崩溃,完成调用呢?

其实是可以的。由于OC是动态语言,方法真正的实现是通过runtime完成的,虽然系统不给我们生成setter/getter,但我们可以通过runtime手动添加setter/getter方法。那具体怎么实现呢?

按照这个思路,我们通过运行时手动添加这个方法。

#import <objc/runtime.h>

static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey"  //定义一个key值

@implementation Programmer (Category)

//运行时实现setter方法

- (void)setNameWithSetterGetter:(NSString *)nameWithSetterGetter {

        objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY)

}

//运行时实现getter方法

- (NSString *)nameWithSetterGetter {

    return objc_getAssociatedObject(self, &nameWithSetterGetterKey)

}

@end

Category是Objective-C中常用的语法特性,通过它可以很方便的为已有的类来添加函数。但是Category不允许为已有的类添加新的属性或者成员变量。

一种常见的办法是通过runtime.h中objc_getAssociatedObject / objc_setAssociatedObject来访问和生成关联对象。通过这种方法来模拟生成属性。

//NSObject+IndieBandName.h

@interface NSObject (IndieBandName)

@property (nonatomic, strong) NSString *indieBandName

@end上面是头文件声明,下面的实现的.m文件:

// NSObject+IndieBandName.m

#import "NSObject+Extension.h"

#import <objc/runtime.h>

static const void *IndieBandNameKey = &IndieBandNameKey

@implementation NSObject (IndieBandName)

@dynamic indieBandName

- (NSString *)indieBandName {

return objc_getAssociatedObject(self, IndieBandNameKey)

}

- (void)setIndieBandName:(NSString *)indieBandName{

objc_setAssociatedObject(self, IndieBandNameKey, indieBandName, OBJC_ASSOCIATION_RETAIN_NONATOMIC)

}

@end DLIntrospection

这个和Category无关,但是也是runtime.h的一种应用。DLIntrospection,是 一个NSObject Category。它为NSObject提供了一系列扩展函数:

@interface NSObject (DLIntrospection)

+ (NSArray *)classes

+ (NSArray *)properties

+ (NSArray *)instanceVariables

+ (NSArray *)classMethods

+ (NSArray *)instanceMethods

+ (NSArray *)protocols

+ (NSDictionary *)descriptionForProtocol:(Protocol *)proto

+ (NSString *)parentClassHierarchy

@end通过这些函数,你可以在调试时(通过po命令)或者运行时获得对象的各种信息。

先看下它在Xcode8 release版本中官方给出的解释:

就解释来看,似乎Objective-C获得这一功能是提高与Swift的互通性。 向Objective-C添加 class 属性映射到Swift中使用类变量。不过我们可以在OC中使用这个功能,更方便愉快的coding。

我们新建一个TestCar类,同时有一个属性 desc

以便于在其他类访问我们在.h文件里面声明一个属性

当我们声明一个class属性的时候,编译器会发出警告!这也就是前面说的They are never synthesized.

这两个属性永远不会synthesized,因此如果我们不显式的添加setter和getter方法,XCode就会提示警告信息使用@dynamic或者是提供setter和getter方法; 注意在getter方法前面使用 + 让其成为一个类的方法

接下来我们简单实现一下set 和 get方法,以便在其他地方调用

接下来就可以调用了,可以使用类名上的普通点语法访问类属性

这里就可以正常输出内容了

同时也需要注意的是,由于这是Xcode 8中的LLVM编译器的一项功能,因此它可以在低于iOS 10的环境下使用。

假如一个类里面都是类方法,或者想在其他地方访问一个类里面的信息,并且这个类里面还有一些属性的话,那么可以使用class修饰生成类属性,这样调用的时候可以直接使用类名调用,不用再生成一个该类的实例来调用了,使用类属性会更方便一点。

当然想使用这个功能你要付出的就是自己生成set和get方法。想必这不是什么难题!

属性用class修饰同时你也可以修饰为readonly只读,它并不会影响其他功能。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11623101.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-17
下一篇2023-05-17

发表评论

登录后才能评论

评论列表(0条)

    保存