RunTime的一些知识点之对象一
先来看一个问题:category能不能创建一个实例化对象?不能?怎么才能创建?
看下runtime是如何创建对象的,过会来回答这个问题
/**
* Adds a new instance variable to a class.
*
* @return YES if the instance variable was added successfully, otherwise NO
* (for example, the class already contains an instance variable with that name).
*
* @note This function may only be called after objc_allocateClassPair and before objc_registerClassPair.
* Adding an instance variable to an existing class is not supported.
* @note The class must not be a metaclass. Adding an instance variable to a metaclass is not supported.
* @note The instance variable's minimum alignment in bytes is 1<<align. The minimum alignment of an instance
* variable depends on the ivar's type and the machine architecture.
* For variables of any pointer type, pass log2(sizeof(pointer_type)).
*/
OBJC_EXPORT BOOL class_addIvar(Class cls, const char *name, size_t size,
uint8_t alignment, const char *types)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
有以下注意点:
- objc_allocateClassPair 与 objc_registerClassPair 之间调用
- 不能用于已经存在的类
- 不能操作元类(metaclass)
由于category是在运行期间决议的,所以就不能添加实例变量
再来看下如何进行创建?可以使用关联对象,下面截取了关联对象API
/* Associative References */
/**
* Policies related to associative references.
* These are options to objc_setAssociatedObject()
*/
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. */
};
/**
* Sets an associated value for a given object using a given key and association policy.
* 通过 key 和 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);
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
/**
* Removes all associations for a given object.
*
* @param object An object that maintains associated objects.
*
* @note The main purpose of this function is to make it easy to return an object
* to a "pristine state”. You should not use this function for general removal of
* associations from objects, since it also removes associations that other clients
* may have added to the object. Typically you should use \c objc_setAssociatedObject
* with a nil value to clear an association.
*
* @see objc_setAssociatedObject
* @see objc_getAssociatedObject
*/
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
所以就可以通过设置关联对象这种方式来处理 category 的"实例化对象",其中主要涉及的方法是: objc_setAssociatedObject 和 objc_getAssociatedObject
property 为什么不可以?
由于 category 是运行期决议的,所以不能对已有类添加 ivar, 那么property 也就不能生成 set 和 get 方法。
如何解决?
利用 property 手动实现 set 和 get 和 Associated ,来实现 category 的"实例对象"的创建.
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, @"name");
}
使用时需要注意,一定要使用 self.name 去设置和获取。
网友评论