Jos*_*ice 32 oop cocoa objective-c categories
我有一种情况,似乎我需要将实例变量添加到一个类别,但我从Apple的文档中知道我不能这样做.所以我想知道最好的选择或解决方法是什么.
我想要做的是添加一个为UIViewControllers添加功能的类别.我会发现它在我所有不同的UIViewControllers中都很有用,无论它们扩展了什么特定的UIViewController子类,所以我认为一个类别是最好的解决方案.为了实现这个功能,我需要几种不同的方法,我需要跟踪它们之间的数据,这就是我想要创建实例方法的原因.
如果它有用,这就是我特别想做的事情.我希望能够更容易地跟踪软件键盘何时隐藏和显示,以便我可以在视图中调整内容的大小.我发现可靠的唯一方法是将代码放在四个不同的UIViewController方法中,并跟踪实例变量中的额外数据.所以那些方法和实例变量是我想要放入一个类别的,所以每次我需要处理软件键盘时都不需要复制它们.(如果对于这个确切的问题有一个更简单的解决方案,那也没关系 - 但我仍然想知道类别实例变量的答案以供将来参考!)
And*_*ips 15
最近,我需要这样做(将状态添加到类别).@Dave DeLong对此有正确的看法.在研究最佳方法时,我发现汤姆哈灵顿的一篇很棒的博客文章.我喜欢@ JeremyP关于在类别上使用@property声明的想法,但不喜欢他的特定实现(不是全局单例或持有全局引用的粉丝).联想参考是可行的方法.
这是为您的类别添加(似乎是)ivars的代码.我在这里详细介绍了这一点.
在File.h中,调用者只能看到干净的高级抽象:
@interface UIViewController (MyCategory)
@property (retain,nonatomic) NSUInteger someObject;
@end
Run Code Online (Sandbox Code Playgroud)
在File.m中,我们可以实现@property(注意:这些不能@ synthesize'd):
@implementation UIViewController (MyCategory)
- (NSUInteger)someObject
{
return [MyCategoryIVars fetch:self].someObject;
}
- (void)setSomeObject:(NSUInteger)obj
{
[MyCategoryIVars fetch:self].someObject = obj;
}
Run Code Online (Sandbox Code Playgroud)
我们还需要声明和定义类MyCategoryIVars.为了便于理解,我已经从正确的编译顺序中解释了这一点.@interface需要放在Category @implementation之前.
@interface MyCategoryIVars : NSObject
@property (retain,nonatomic) NSUInteger someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance;
@end
@implementation MyCategoryIVars
@synthesize someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance
{
static void *compactFetchIVarKey = &compactFetchIVarKey;
MyCategoryIVars *ivars = objc_getAssociatedObject(targetInstance, &compactFetchIVarKey);
if (ivars == nil) {
ivars = [[MyCategoryIVars alloc] init];
objc_setAssociatedObject(targetInstance, &compactFetchIVarKey, ivars, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[ivars release];
}
return ivars;
}
- (id)init
{
self = [super init];
return self;
}
- (void)dealloc
{
self.someObject = nil;
[super dealloc];
}
@end
Run Code Online (Sandbox Code Playgroud)
上面的代码声明并实现了保存我们的ivars(someObject)的类.由于我们无法真正扩展UIViewController,因此必须这样做.
我相信现在可以将合成属性添加到类别中,并且实例变量是自动创建的,但我从未尝试过,所以我不确定它是否可行.
一个更黑客的解决方案:
创建一个单独的NSDictionary,它将UIViewController作为键(或者它的地址包装为NSValue),并将属性的值作为其值.
为实际进入字典的属性创建getter和setter以获取/设置属性.
@interface UIViewController(MyProperty)
@property (nonatomic, retain) id myProperty;
@property (nonatomic, readonly, retain) NSMutableDcitionary* propertyDictionary;
@end
@implementation UIViewController(MyProperty)
-(NSMutableDictionary*) propertyDictionary
{
static NSMutableDictionary* theDictionary = nil;
if (theDictionary == nil)
{
theDictioanry = [[NSMutableDictionary alloc] init];
}
return theDictionary;
}
-(id) myProperty
{
NSValue* key = [NSValue valueWithPointer: self];
return [[self propertyDictionary] objectForKey: key];
}
-(void) setMyProperty: (id) newValue
{
NSValue* key = [NSValue valueWithPointer: self];
[[self propertyDictionary] setObject: newValue forKey: key];
}
@end
Run Code Online (Sandbox Code Playgroud)
上述方法存在两个潜在问题:
NSNumber numberWithUnsignedLong:
将在32位和64位平台上执行此操作).最好使用内置的ObjC功能关联对象(也称为关联引用),在下面的示例中,只需更改为您的类别,并将associatedObject替换为您的变量名称.
NSObject的+ AssociatedObject.h
@interface NSObject (AssociatedObject)
@property (nonatomic, strong) id associatedObject;
@end
Run Code Online (Sandbox Code Playgroud)
NSObject的+ AssociatedObject.m
#import <objc/runtime.h>
@implementation NSObject (AssociatedObject)
@dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self, @selector(associatedObject));
}
Run Code Online (Sandbox Code Playgroud)
请参阅此处获取完整教程:
http://nshipster.com/associated-objects/
为什么不简单地创建 的子类UIViewController
,向其中添加功能,然后使用该类(或其子类)呢?