- 兄弟们。今天探索一波
关联对象~
1.关联对象的使用
-
- 我们已经知道:
分类中用@property定义的属性,只会生成变量的setter,getter方法的声明,不会生成方法的实现。
- 我们已经知道:
-
- 那我们可以准备一份测试代码:
@interface LGPerson (LG)
@property (nonatomic, copy) NSString *cate_name;
@end
@implementation LGPerson (LG)
@end
-
- 这样的话,如果给
cate_name赋值,运行就会崩溃。
- 这样的话,如果给
但是编译不会,这也说明了 :
分类中用@property定义的属性,只会生成变量的setter,getter方法的声明,不会生成方法的实现。
-
- 我们修改一下代码:
@interface LGPerson (LG)
@property (nonatomic, copy) NSString *cate_name;
@end
@implementation LGPerson (LG)
- (void)setCate_name:(NSString *)cate_name{
objc_setAssociatedObject(self, "cate_name", cate_name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)cate_name{
objc_getAssociatedObject(self, "cate_name");
}
@end
我们给他一个
setter和getter方法,他就没啥问题了
这也是
关联对象使用比较多的地方。
2.关联对象的本质
我们探究下
关联对象时怎么实现的。
-
- 在源码工程中,我们可点击
objc_setAssociatedObject进入方法里面,进行探究
- 在源码工程中,我们可点击
兄弟们,看到源码的方法,感觉和原先的不一样了(苹果又做了调整,我这个还是比较新的,😆)
-
- 有些兄弟们可能没有用过
C++,对C++不太了解。不过没有啥关系,点进去看看
- 有些兄弟们可能没有用过
-
- 我们来分析下这个些参数
- (void)setCate_name:(NSString *)cate_name{
objc_setAssociatedObject(self, "cate_name", cate_name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
static void
_base_objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
_object_set_associative_reference(object, key, value, policy);
}
参数一:
id object: 给哪个对象添加属性,这里要给自己添加属性,用self
参数二:
void * key:属性名,根据key获取关联对象的属性的值,在objc_getAssociatedObject中通过次key获得属性的值并返回
参数三:
id value: 关联的值,也就是set方法传入的值给属性去保存
参数四:
objc_AssociationPolicy policy: 策略,属性以什么形式保存。
-
- 我们可以观察下这些
策略有什么:
- 我们可以观察下这些
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. */
};
这样大家就明白点了~,这个策略其实就是:
属性对应的修饰符
-
- 我们继续深入探究,看看他是个什么结构,怎么存的
-
- 我们看下
acquireValue()方法
- 我们看下
inline void acquireValue() {
if (_value) {
switch (_policy & 0xFF) {
case OBJC_ASSOCIATION_SETTER_RETAIN:
_value = objc_retain(_value);
break;
case OBJC_ASSOCIATION_SETTER_COPY:
_value = ((id(*)(id, SEL))objc_msgSend)(_value, @selector(copy));
break;
}
}
}
点进去之后,发现这个是策略判断,然后有个消息转发,也不是重点~
-
- 那么重点应该就在折叠的代码块了~
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.get());
if (value) {
auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
if (refs_result.second) {
/* it's the first association we make */
object->setHasAssociatedObjects();
}
/* establish or replace the association */
auto &refs = refs_result.first->second;
auto result = refs.try_emplace(key, std::move(association));
if (!result.second) {
association.swap(result.first->second);
}
} else {
auto refs_it = associations.find(disguised);
if (refs_it != associations.end()) {
auto &refs = refs_it->second;
auto it = refs.find(key);
if (it != refs.end()) {
association.swap(it->second);
refs.erase(it);
if (refs.size() == 0) {
associations.erase(refs_it);
}
}
}
}
}
-
- 我们断点调试输出一波
-
- 我们把这个关联画一下。否则容易懵逼~
-
- 看起来好复杂的样子。我们来捋一捋:找出关键方法
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
return std::make_pair(
makeIterator(TheBucket, getBucketsEnd(), true),
true);
}
iterator makeIterator(BucketT *P, BucketT *E,
bool NoAdvance=false) {
return iterator(P, E, NoAdvance);
}
这个时候需要一波灵魂画师~
-
- 最后了~ 我把这个结构整体画了一波。大家看看可否满意~
- 最后了~ 我把这个结构整体画了一波。大家看看可否满意~