標籤:objective 關聯
objective-c 中的關聯介紹
轉載請註明CSDN部落格上的出處:
http://blog.csdn.net/daiyibo123/article/details/46471993
如何設定關聯
我們可以使用下面的方法來關聯屬性:
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
- 被關聯的對象,下面舉的例子中關聯到了UIAlertView
- 要關聯的對象的索引值,一般設定成靜態,用於擷取關聯對象的值
- 要關聯的對象的值,從介面中可以看到接收的id類型,所以能關聯任何對象
- 關聯時採用的協議,有assign,retain,copy等協議,具體可以參考官方文檔
可以通過下面的方法來擷取我們剛剛關聯的object:
objc_getAssociatedObject(id object, const void *key);
- 被關聯的對象
- 要關聯的對象的索引值,一般設定成靜態,用於擷取關聯對象的值
簡單運用下面是簡單地viewController類,黏貼直接可以運行:
#import <UIKit/UIKit.h>@interface ViewController : UIViewController@end
#import "ViewController.h"#import <objc/runtime.h>static char kUITableViewIndexKey;@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, [UIScreen mainScreen].bounds.size.width, 50)]; lable.backgroundColor = [UIColor lightGrayColor]; lable.text = @"關聯屬性"; lable.textColor = [UIColor blackColor]; objc_setAssociatedObject(self, &kUITableViewIndexKey, lable, OBJC_ASSOCIATION_RETAIN_NONATOMIC);//設定一個關聯 [self.view addSubview:objc_getAssociatedObject(self, &kUITableViewIndexKey)];//擷取剛剛關聯的lable}@end
註:在擷取和設定關聯的時候,調用的被關聯對象(代碼中用的是self)和關聯索引值(代碼中用kUITableViewIndexKey)都必須是同一個對象。這樣才可以保證能擷取到關聯對象。
個人理解下面是索引值的較好的運用:
代碼介紹:一個仿系統的TabBarController類(RDVTabBarController,這個是第三方庫,:https://github.com/robbdimitrov/RDVTabBarController)
在建立RDVTabBarController時,建立了兩個UIViewController的擴充,擴充中建立關聯,關聯代碼如下:
@interface UIViewController (RDVTabBarControllerItemInternal)- (void)rdv_setTabBarController:(RDVTabBarController *)tabBarController;@end@interface UIViewController (RDVTabBarControllerItem)@property(nonatomic, readonly) RDVTabBarController *rdv_tabBarController;@end
@implementation UIViewController (RDVTabBarControllerItemInternal)- (void)rdv_setTabBarController:(RDVTabBarController *)tabBarController { objc_setAssociatedObject(self, @selector(rdv_tabBarController), tabBarController, OBJC_ASSOCIATION_ASSIGN);}@end@implementation UIViewController (RDVTabBarControllerItem)- (RDVTabBarController *)rdv_tabBarController{ RDVTabBarController *tabBarController = objc_getAssociatedObject(self, @selector(rdv_tabBarController)); //這裡使用的遞迴演算法 if (!tabBarController && self.parentViewController) { tabBarController = [self.parentViewController rdv_tabBarController]; } return tabBarController;}@end
然後在RDVTabBarController建立中調用ViewController的擴充方法rdv_setTabBarController:
(因為RDVTabBarController也是ViewController的子類,所以可以調用)。通過這個方法設定關聯,將TabBarViewController中的childView都和TabBarViewController關聯起來。
下面是RDVTabBarController中調用擴充方法設定關聯的代碼:
(這個簡化了其他與關聯無關的代碼,需要瞭解其他的,自己從github上下載這個第三方庫看源碼。)
- (void)setViewControllers:(NSArray *)viewControllers { if (viewControllers && [viewControllers isKindOfClass:[NSArray class]]) { //向TabBarViewController中添加關聯 for (UIViewController *viewController in viewControllers) { [viewController rdv_setTabBarController:self]; } } else { //沒有向TabBarViewController中添加viewController,刪除關聯,刪除TabBarViewCOntroller中的childViewController for (UIViewController *viewController in _viewControllers) { [viewController rdv_setTabBarController:nil]; } _viewControllers = nil; }}
完成了上面的設定之後,我們就在項目中,直接通過當前啟動並執行viewController來擷取tabBarViewController這個屬性了。
下面是示範代碼:
[self.rdv_tabBarController setTabBarHidden:!_viewController.rdv_tabBarController.tabBarHidden animated:YES];//通過點運算子,調用UIViewController中的擴充方法:`rdv_tabBarController`。然後在`rdv_tabBarController`擴展方法中,遞迴尋找和RDVTabBarViewController關聯的屬性。
運行結果簡介:
簡單運行一個demo,po打出相關RDVTabBarController中相關資訊:
在這裡遞迴尋找關聯值,第一個ViewController地址為:’0x7f9378e750a0‘沒有進行關聯,找不到。然後跳到父視圖中,地址為:‘0x7f9378d39a70’有相關,找到,不需要在向下尋找。遞迴結束,找到關聯值,返回結果。
小結:
這裡,通過擴充和關聯的結合使用,將RDVTabBarController這個執行個體屬性,和當前的ViewController結合起來。這種思想,在以後自己編寫第三方庫函數的時候,值得借鑒!
總體來說,associative的主要原理,就是把兩個對象相互關聯起來,使得其中的一個對象作為另外一個對象的一部分。
參考:
http://m.blog.csdn.net/blog/csz0102/19555673
objective-c 中的關聯介紹