iOS 学习 --- Categary中声明属性注意事项

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jiaxin_1105/article/details/84302735

前言 

我们在 iOS 开发中经常需要使用分类(Category),为已经存在的类添加属性的需求,但是使用 @property并不能在分类中正确创建实例变量和存取方法。

不过,通过 Objective-C 运行时中的关联对象,也就是 Associated Object,我们可以实现上述需求。

@property声明属性

@interface MyViewController :UIViewController
//属性变量
@property (nonatomic, strong) UIButton *myButton;

@end

在使用上面代码时会做3件事:

  • 生成实例变量 _myButton;
  • 生成getter方法:-myButton
  • 生成setter方法:-setMyButton:
@implementation MyViewController
{
    UIButton *_myButton;
}

-(UIButton *)myButton{
    return _myButton;
}

-(void)setMyButton:(UIButton *)myButton{
    _myButton = myButton;
}

这些代码都是编译器为我们生成的,虽然我们看不到它,但是它确实在这里,不需要我们自己再写这些代码。

类目(Categary)中用@property声明属性

UIViewController+CommonMethod.h

#import <UIKit/UIKit.h>

@interface UIViewController (CommonMethod)

@property (nonatomic, strong) UIButton *LoginButton;

@end

UIViewController+CommonMethod.m 中会报下面警告

这里的警告告诉我们,loginButton 属性的存取方法需要自己手动去实现,或者使用 @dynamic 在运行时实现这些方法。

换句话说,分类中的 @property 并没有为我们生成实例变量以及存取方法,而需要我们手动实现。

实现getter 和setter方法:

#import "UIViewController+CommonMethod.h"
#import <objc/runtime.h>
@implementation UIViewController (CommonMethod)


-(UIButton *)loginButton{
    return objc_getAssociatedObject(self, _cmd);
}

-(void)setLoginButton:(UIButton *)loginButton{
    objc_setAssociatedObject(self, @selector(loginButton), loginButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


@end

OBJC_EXPORT void
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                         id _Nullable value, objc_AssociationPolicy policy)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);


OBJC_EXPORT id _Nullable
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);


OBJC_EXPORT void
objc_removeAssociatedObjects(id _Nonnull object)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
扫描二维码关注公众号,回复: 4693276 查看本文章

注意:

这里的 _cmd 代指当前方法的选择子,也就是 @selector(loginButton)。  

以键值对形式添加关联对象

OBJC_EXPORT void
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
                         id _Nullable value, objc_AssociationPolicy policy)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);

objc_setAssociatedObject :把一个对象与另外一个对象进行关联。该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略。

  • OBJC_EXPORT:打包lib时,用来说明该函数是暴露给外界调用的。
  • id _Nonnull object:表示关联者,是一个对象,变量名理所当然也是object。
  • const void * _Nonnull key:关键字是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字。
  • id _Nullable value:表示被关联者,变量名是value,它要关联到object上的。
  • objc_AssociationPolicy policy:关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。这种关联策略是通过使用预先定义好的常量来表示的。
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {

    OBJC_ASSOCIATION_ASSIGN = 0,          

    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, 

    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  

    OBJC_ASSOCIATION_RETAIN = 01401,      

    OBJC_ASSOCIATION_COPY = 01403         
};

******注意*****

断开关联是使用objc_setAssociatedObject函数,传入nil值即可。

使用函数objc_removeAssociatedObjects可以断开所有关联。

根据 key 获取关联对象

OBJC_EXPORT id _Nullable
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);

  • id _Nonnull object:
  • const void * _Nonnull key:

移除所有关联对象

OBJC_EXPORT void
objc_removeAssociatedObjects(id _Nonnull object)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);

  • id _Nonnull object:

这个方法不推荐使用,因为会遍历所有的关联对象,并且全部释放,可能会造成别的模块功能缺陷。

相关文章:

iOS学习 --- 成员变量,实例变量,属性

iOS 成员变量,实例变量,属性变量的区别,联系

iOS 关于Category

Objective-C Associated Objects 的实现原理

category中添加属性的简单方式

AssociatedObject关联对象原理实现

猜你喜欢

转载自blog.csdn.net/jiaxin_1105/article/details/84302735
今日推荐