基本概念
? ? ? ?objective-c有兩個擴展機制:category和associative。我們可以通過category來擴展方法,但是它有個很大的局限性,不能擴展屬性。于是,就有了專門用來擴展屬性的機制:associative。
? ? ? ?在iOS開發(fā)過程中,category比較常見,而associative就用的比較少。associative的主要原理,就是把兩個對象相互關聯(lián)起來,使得其中的一個對象作為另外一個對象的一部分。
? ? ? ?使用associative,我們可以不用修改類的定義而為其對象增加存儲空間。這在我們無法訪問到類的源碼的時候或者是考慮到二進制兼容性的時候是非常有用。
? ? ? ?associative是基于關鍵字的。因此,我們可以為任何對象增加任意多的associative,每個都使用不同的關鍵字即可。associative是可以保證被關聯(lián)的對象在關聯(lián)對象的整個生命周期都是可用的。
associative機制提供了三個方法:
OBJC_EXPORT
?void?objc_setAssociatedObject(id?object,?const?void?*key,?idvalue,?objc_AssociationPolicy?policy)
OBJC_EXPORT?
id?objc_getAssociatedObject(id?object,?const?void?*key)
OBJC_EXPORT?
void?objc_removeAssociatedObjects(id?object)
創(chuàng)建associative
? ? ? ?創(chuàng)建associative使用的是:objc_setAssociatedObject。它把一個對象與另外一個對象進行關聯(lián)。該函數(shù)需要四個參數(shù):源對象,關鍵字,關聯(lián)的對象、關聯(lián)策略。
? ? ? ?關鍵字是一個void類型的指針。每一個關聯(lián)的關鍵字必須是唯一的。通常都是會采用靜態(tài)變量來作為關鍵字。
? ? ? ?關聯(lián)策略表明了相關的對象是通過賦值,保留引用還是復制的方式進行關聯(lián)的;還有這種關聯(lián)是原子的還是非原子的。這里的關聯(lián)策略和聲明屬性時的很類似。這種關聯(lián)策略是通過使用預先定義好的常量來表示的。
獲取associative對象
? ? ? ? 獲取相關聯(lián)的是函數(shù)objc_getAssociatedObject。
斷開associative
? ? ? ? 斷開associative是使用objc_setAssociatedObject函數(shù),關注的對象傳入nil值即可。
? ? ? ? 使用函數(shù)objc_removeAssociatedObjects可以斷開所有associative。通常情況下不建議這么做,因為他會斷開所有關聯(lián)。
應用場景
==============在UIView中添加NSString類型的標記===============
? ? ? ?蘋果雖然有提供NSInteger類型的tag屬性,用于標記相應的ui。但是在處理比較復雜的邏輯的時候,往往NSInteger類型的標記不能滿足需求。為其添加了NSString類型的標記后。就能使用字符串,快速的標記ui,并且使用viewWithTagString方法,快速找到你所需要的ui。
@interface UIView(BDTag)
@property?(nonatomic,?retain)?NSString?*tagString;
- (UIView?*)viewWithTagString:(NSString?*)value;
@end
#import "UIView+BDTag.h"
#undef???KEY_TAGSTRING
#define KEY_TAGSTRING?????"UIView.tagString"
@implementation?UIView(BDTag)
@dynamic?tagString;
//屬性的get方法
- (NSString?*)tagString {
? ? ? ? ? NSObject?*obj =?objc_getAssociatedObject(self,?KEY_TAGSTRING);
? ? ? ? ? ?if?(obj && [obj?isKindOfClass:[NSString?class]]) {
? ? ? ? ? ? ? ? ? ? ? return?(NSString?*)obj;
? ? ? ? ? ? }
? ? ? ? ? ? return?nil;
}
//屬性的set方法
- (void)setTagString:(NSString?*)value {
? ? ? ? ? ? ?objc_setAssociatedObject(self,?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? KEY_TAGSTRING,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? value,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//獲取到tag對應的view
- (UIView?*)viewWithTagString:(NSString?*)value {
? ? ? ? ? ? ? ? if?(nil?== value) {
? ? ? ? ? ? ? ? ? ? ? ? ?return?nil;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? for?(UIView?*subview?in?self.subviews) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?NSString?*tag = subview.tagString;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?if?([tag?isEqualToString:value]){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return?subview;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ?return?nil;
}
@end
==================為NSObject子類添加任何信息================
? ? ? ? 這是一個方便,強大,并且簡單的類。利用associative機制,為任何Object,添加你所需要的信息。比如用戶登錄,向服務端發(fā)送用戶名/密碼時,可以將這些信息綁定在請求的項之中。等請求完成后,再取出你所需要的信息,進行邏輯處理。而不需要另外設置成員,保存這些數(shù)據(jù)。
@interface NSObject (BDAssociation)
- (id)associatedObjectForKey:(NSString*)key;
- (void)setAssociatedObject:(id)object forKey:(NSString*)key;
@end
#import "NSObject+BDAssociation.h"
@implementation?NSObject (BDAssociation)
//標記關聯(lián)對象字典的關鍵字
static?char?associatedObjectsKey;
- (id)associatedObjectForKey:(NSString*)key {
? ? ? ? //利用關鍵字獲取到關聯(lián)對象字典
? ? ? ? NSMutableDictionary?*dict =?objc_getAssociatedObject(self, &associatedObjectsKey);
? ? ? ? //利用key獲取到字典中對應的value
? ? ? ? return?[dict?objectForKey:key];
}
- (void)setAssociatedObject:(id)object forKey:(NSString*)key {
? ? ? ? ? ? //利用關鍵字獲取到關聯(lián)對象字典
? ? ? ? ? ? NSMutableDictionary?*dict =?objc_getAssociatedObject(self, &associatedObjectsKey);
? ? ? ? ? ? //如果該關鍵字標注的對象尚未關聯(lián),則關聯(lián)該對象
? ? ? ? ? ? if?(!dict) {
? ? ? ? ? ? ? ? ? ? ?//創(chuàng)建關聯(lián)對象
? ? ? ? ? ? ? ? ? ? ?dict = [[NSMutableDictionary?alloc]?init];
? ? ? ? ? ? ? ? ? ? ?objc_setAssociatedObject(self,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &associatedObjectsKey,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dict,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC_ASSOCIATION_RETAIN);
? ? ? ? ? ? }
? ? ? ? ? ? //將value存儲到關聯(lián)對象字典中
? ? ? ? ? ? [dict?setObject:object?forKey:key];
}
@end
=======================內存回收檢測========================
? ? ? ?如果你剛接觸iOS開發(fā),那么內存泄露則是你怎么也繞不開的一道坎,當你遇到內存泄漏時,怎么辦呢?在各個view controller的dealloc中打Log。這種方法雖然有效,但不好管理。
? ? ? ?利用associative機制。讓object在回收時,自動輸出回收信息。
@interface NSObject (BDLogDealloc)
- (void)logOnDealloc;
@end
#import "NSObject+BDLogDealloc.h"
#import <objc/runtime.h>
static?char?__logDeallocAssociatedKey__;
@interface?LogDealloc?:?NSObject
@property?(nonatomic,?copy)?NSString* message;
@end
@implementation?NSObject (BDLogDealloc)
- (void)logOnDealloc {
? ? ? ? ?if(objc_getAssociatedObject(self, &__logDeallocAssociatedKey__) ==?nil) {
? ? ? ? ? ? ? ? ? LogDealloc* log = [[LogDealloc?alloc]?init] ;
? ? ? ? ? ? ? ? ? log.message?=?NSStringFromClass(self.class);
? ? ? ? ? ? ? ? ? objc_setAssociatedObject(self,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &__logDeallocAssociatedKey__,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? log,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OBJC_ASSOCIATION_RETAIN);
? ? ? ? ? ? ? }
}
@end
@implementation?LogDealloc
- (void)dealloc {
? ? ? ? ? ? ? ? ? NSLog(@"dealloc: %@",?self.message);
}
@end
感謝網(wǎng)友http://www.cnblogs.com/mkai/p/6594668.html的文章。