2013-06-21 13 views
1

我有一個自定義容器視圖控制器,用於管理我的應用程序的視圖層次結構。我知道每個控制器都是這個容器控制器的某個孩子。我認爲在UIViewController上有一個允許我訪問容器控制器的類別會很好,不管我在層次結構中的哪個位置。objc_setAssociatedObject在所有子類的類別集中

這涉及遞歸控制器層次結構,所以我認爲這將是一個很好的嘗試,只有這樣做,每個控制器走一次。因此,通過objc_setAssociatedObject,我找到容器並設置了一個標誌,以便我知道是否需要在隨後的調用中遍歷層次結構(如果viewcontroller曾經移動過,我計劃使其無效),但這可能會過度,我沒有那麼遠)。

無論如何,除了我的標誌是否已經走過層次似乎是附加到UIViewController,而不是UIViewController的特定子類,大部分工作正常。

我嘗試在我的關聯對象上設置默認值無效,我試了一下+ load。

任何想法?如何獲取類別中的關聯對象以與該類別定義的類的子類關聯?

這裏是我的代碼,很好的衡量。

#import "UIViewController+LMPullMenuContainer.h" 
#import <objc/runtime.h> 

static char const * const CachedKey = "__LM__CachedBoolPullMenuAssociatedObjectKey"; 
static char const * const PullMenuKey = "__LM__PullMenuAssociatedObjectKey"; 

@implementation UIViewController (LMPullMenuContainer) 

+ (void)load { 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     SEL initSelector = @selector(initWithCoder:); 
     SEL pullViewInitSelector = @selector(init__LM__Swizzled__WithCoder:); 
     Method originalMethod = class_getInstanceMethod(self, initSelector); 
     Method newMethod = class_getInstanceMethod(self, pullViewInitSelector); 

     BOOL methodAdded = class_addMethod([self class], 
              initSelector, 
              method_getImplementation(newMethod), 
              method_getTypeEncoding(newMethod)); 

     if (methodAdded) { 
      class_replaceMethod([self class], 
           pullViewInitSelector, 
           method_getImplementation(originalMethod), 
           method_getTypeEncoding(originalMethod)); 
     } else { 
      method_exchangeImplementations(originalMethod, newMethod); 
     } 
    }); 
} 

- (instancetype)init__LM__Swizzled__WithCoder:(NSCoder *)coder { 
    self = [self init__LM__Swizzled__WithCoder:coder]; 
    if (self != nil) 
    { 
     objc_setAssociatedObject(self, CachedKey, [NSNumber numberWithBool:NO], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
     objc_setAssociatedObject(self, PullMenuKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    } 
    return self; 
} 

- (LMPullMenuContainerViewController*)pullMenuContainerController { 
    BOOL isCached = [objc_getAssociatedObject(self, CachedKey) boolValue]; 
    if (isCached) { 
     return objc_getAssociatedObject(self, PullMenuKey); 
    } else { 
     return [self pullMenuParentOf:self]; 
    } 
} 

- (LMPullMenuContainerViewController *)pullMenuParentOf:(UIViewController *)controller { 
    if (controller.parentViewController) { 
     if ([controller.parentViewController isKindOfClass:[LMPullMenuContainerViewController class]]) { 
      objc_setAssociatedObject(self, CachedKey, [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
      objc_setAssociatedObject(self, PullMenuKey, controller.parentViewController, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
      return (LMPullMenuContainerViewController *)(controller.parentViewController); 
     } else { 
      return [self pullMenuParentOf:controller.parentViewController]; 
     } 
    } else { 
     objc_setAssociatedObject(self, CachedKey, [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
     objc_setAssociatedObject(self, PullMenuKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
     return nil; 
    } 
} 

現在我已經辭職了,在必要時手動設置屬性。

+0

你是什麼意思的標誌是*「附加到UIViewController,而不是特定的UIViewController子類」*?關聯的對象附加到(子)類的實例,而不是類。 –

+0

這就是我的想法和預期,但是,當我逐步瀏覽它時,我發現'isCached'在特定的子類上設置之前返回了'YES'(但是在其他子類上設置之後)。 –

+0

也許不相關,但是不應該將結果緩存在'return [self pullMenuParentOf:controller.parentViewController]; case? –

回答

0

碰巧,上面的代碼工作得很好。我的容器控制器正在加載它首次初始化時管理的所有控制器,而不是控制器第一次顯示時的狀態,所以對我來說,看起來好像標誌已經設置好了。

相關問題