一. 為什么要?jiǎng)討B(tài)添加屬性?
思考:當(dāng)系統(tǒng)提供的類滿足不了我們要求的時(shí)候, 則需我們手動(dòng)添加屬性,且希望能給系統(tǒng)直接添加屬性;
以NSObject為例 (給NSObject 添加一個(gè)自定義屬性)
- 想法: 1. 創(chuàng)建一個(gè)子類繼承NSObject, 此時(shí)可以添加屬性;但是并不是直接給系統(tǒng)的類添加;
- 想法: 2. 給NSObject添加一個(gè)分類, 在分類中我們可以實(shí)現(xiàn)方法, 但是添加屬性, 僅僅只生成方法的聲明;并沒(méi)有方法實(shí)現(xiàn)和生成下劃線成員變量;
二. 此時(shí)考慮使用runtime來(lái)動(dòng)態(tài)實(shí)現(xiàn)給系統(tǒng)的類添加屬性;
tips: 記得區(qū)分屬性與成員變量
{
NSString *_name; // 成員變量
}
@property (nonatomic, strong)NSString *name; // 成員屬性
三. 實(shí)現(xiàn)步驟:
1.0 給NSObject 添加一個(gè)分類(Property),在里面添加一個(gè)自定義屬性;
#import <Foundation/Foundation.h>
#import <Foundation/Foundation.h>
@interface NSObject (Property)
@property NSString *name; // 既然沒(méi)有生成成員變量,那么無(wú)需策略進(jìn)行修飾
@end
2.0 導(dǎo)入runtime的頭文件,
3.0 在.h文件中實(shí)現(xiàn)name方法的getter 和setter方法
#import "NSObject+Property.h"
#import <objc/message.h>
@implementation NSObject (Property)
- (void)setName:(NSString *)name
{
// 保存name
// 動(dòng)態(tài)添加屬性的本質(zhì)是:讓對(duì)象的某個(gè)屬性與值產(chǎn)生關(guān)聯(lián)
objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{
// 獲取對(duì)應(yīng)屬性的值
return objc_getAssociatedObject(self, "name");
}
@end
解析:
// 關(guān)聯(lián)值的方法
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
object:保存到哪個(gè)對(duì)象中
key:用什么屬性保存?zhèn)魅氲闹? value:需保存值
policy:策略,strong,weak等
// 獲取值的方法:
objc_getAssociatedObject(id object, const void *key);
object:從哪個(gè)對(duì)象中獲取值
key: 用什么屬性獲取值
四.驗(yàn)證: 在其他文件導(dǎo)入NSObject的分類頭文件,并使用自定義屬性;
NSObject *objc = [[NSObject alloc] init];
objc.name = @"abel";
NSLog(@"%@",objc.name); // 可打印出: abel
題外話:
對(duì)于如何記住runtime的方法, 只有一個(gè)原則:誰(shuí)的事情誰(shuí)處理;故我們可判斷runtime方法的前綴是什么.
以本文方法為例, 我們需要給系統(tǒng)添加一個(gè)自定義屬性;
動(dòng)態(tài)添屬性的本質(zhì)是:讓對(duì)象的某個(gè)屬性與值(其他對(duì)象)產(chǎn)生關(guān)聯(lián);
則runtime方法前綴應(yīng)該是objc(對(duì)象) ,_setAssociatedObject(關(guān)聯(lián)另一個(gè)對(duì)象)
objc_getAssociatedObject(id object, const void *key)方法亦是如此;