今天接到一个需求,要在一个指定View的subViews中查找几个特定的View进行指定的操作,但是对于开发者来说,它们都是最普通的View,没有什么特殊型来与其它对象区分开来,这个问题困扰了我好一会,最好想到的办法是在需要特殊处理的View生成时给它指定一个特殊的ID,这样在后期查找是就可以判断出subViews数组中那些对象是我需要处理的。
实现这个功能最方便的方法是新建一个UIView的Category,并动态创建businessID属性。代码如下:
#import <UIKit/UIKit.h>
@interface UIView (Additions)
@property (copy,nonatomic) NSString *sdBusinessID;
@end
#import "UIView+Additions.h"
#import <objc/runtime.h>
static const char *kBusinessID = "com.sd.businessID";
@implementation UIView (Additions)
- (void)setSdBusinessID:(NSString *)sdBusinessID
{
objc_setAssociatedObject(self,
kBusinessID,
sdBusinessID,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)sdBusinessID
{
return objc_getAssociatedObject(self, kBusinessID);
}
@end
如上就实现了动态设置property的功能,导入头文件即可使用。
在实现代码中我们用到了runtime中的两个方法,函数原型如下:
/**
* Sets an associated value for a given object using a given key and association policy.
*
* @param object The source object for the association.
* @param key The key for the association.
* @param value The value to associate with the key key for object. Pass nil to clear an existing association.
* @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
*
* @see objc_setAssociatedObject
* @see objc_removeAssociatedObjects
*/
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
/**
* Returns the value associated with a given object for a given key.
*
* @param object The source object for the association.
* @param key The key for the association.
*
* @return The value associated with the key \e key for \e object.
*
* @see objc_setAssociatedObject
*/
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
我们首先来了解一下设置property的方法objc_setAssociatedObject。其中第一个参数object为要操作的对象;第二个参数key为存储/获取属性的key;第三个参数value为要保存的数据;第四个参数为访问策略,需要传入枚举值,具体如下:
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
};
通过枚举的名称我们就可以知道其功能,主要对应retain nonatomic、retain等,使用时可参照对应的注释选择自己需要的。
读取property值的方法比较简单,只要将操作对象与key传入参数即可。
另外还有一点需要注意,Category在扩展类的同时也存在与系统方法或第三方库中Category方法冲突的问题,在方法命名时可以加入特定的前缀或后缀来规避这一问题。