Objective C类别的实例变量

Jos*_*ice 32 oop cocoa objective-c categories

我有一种情况,似乎我需要将实例变量添加到一个类别,但我从Apple的文档中知道我不能这样做.所以我想知道最好的选择或解决方法是什么.

我想要做的是添加一个为UIViewControllers添加功能的类别.我会发现它在我所有不同的UIViewControllers中都很有用,无论它们扩展了什么特定的UIViewController子类,所以我认为一个类别是最好的解决方案.为了实现这个功能,我需要几种不同的方法,我需要跟踪它们之间的数据,这就是我想要创建实例方法的原因.

如果它有用,这就是我特别想做的事情.我希望能够更容易地跟踪软件键盘何时隐藏和显示,以便我可以在视图中调整内容的大小.我发现可靠的唯一方法是将代码放在四个不同的UIViewController方法中,并跟踪实例变量中的额外数据.所以那些方法和实例变量是我想要放入一个类别的,所以每次我需要处理软件键盘时都不需要复制它们.(如果对于这个确切的问题有一个更简单的解决方案,那也没关系 - 但我仍然想知道类别实例变量的答案以供将来参考!)

Dav*_*ong 28

是的,你可以这样做,但既然你问,我不得不问:你绝对确定你需要吗?(如果你说"是",那就回去看看你想做什么,看看是否有不同的做法)

但是,如果您真的想将存储注入您无法控制的类中,请使用关联引用.

  • 新的关联参考链接:http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html (4认同)

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,因此必须这样做.


Jer*_*myP 6

我相信现在可以将合成属性添加到类别中,并且实例变量是自动创建的,但我从未尝试过,所以我不确定它是否可行.

一个更黑客的解决方案:

创建一个单独的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)

上述方法存在两个潜在问题:

  • 没有办法删除已经解除分配的视图控制器的键.只要您只跟踪少数,这应该不是问题.或者,一旦您知道完成了该键,就可以添加一种从字典中删除键的方法.
  • 我不是100%确定NSValue的isEqual:方法比较内容(即包装指针)来确定相等性,或者它是否仅仅比较self以查看比较对象是否是完全相同的NSValue.如果是后者,则必须使用NSNumber而不是NSValue作为密钥(NSNumber numberWithUnsignedLong:将在32位和64位平台上执行此操作).


mal*_*hal 6

最好使用内置的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/


Jos*_*zzi 0

为什么不简单地创建 的子类UIViewController,向其中添加功能,然后使用该类(或其子类)呢?

  • `UITableViewController` 是 `UIViewController` 的子类。类别将为两者添加功能,而子类则不会。 (6认同)