我有一个自定义容器视图控制器,用于管理我的应用程序的视图层次结构。我知道每个控制器都是这个容器控制器的孩子。我认为在UIViewController上有一个允许我访问容器控制器的类别会很好,无论我在层次结构中的哪个位置。
这涉及到控制器层次结构的递归步骤,所以我认为尝试每个控制器只执行一次会很好。所以使用objc_setAssociatedObject,我设置容器一旦找到它并设置一个标志,以便我知道是否需要在后续调用中走分层次结构(我计划在视图控制器移动时使其失效,但这可能是过度杀伤,我没有那么远。)
无论如何,除了我的关于层次结构是否已被遍历的标志似乎附加到UIViewController而不是UIViewController的特定子类之外,大部分都可以正常工作。
我调整了加载以尝试在我的关联对象上设置默认值无效。
有什么想法吗?如何获取类别中的关联对象以与定义类别的类的子类关联?
这是我的代码,为了更好的衡量标准。
#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 :(得分:0)
碰巧,上面的代码工作得很好。我的容器控制器在第一次初始化时加载了它管理的所有控制器,而不是在第一次显示控制器时,所以对我来说看起来好像标志已经设置好了。