【问题标题】:Objective-C releasing a property declared in a category?Objective-C 释放在类别中声明的属性?
【发布时间】:2010-12-06 19:53:26
【问题描述】:

我在现有类上有一个类别,它向该类添加了一个属性和一些方法。

@interface AClass (ACategory) {
    NSString *aProperty;
}

@property (nonatomic, retain) NSString *aProperty;

@end

在实现文件中,我想在对象被释放的时候释放这个属性。但是,如果我在这个类中声明dealloc,它将根据我的理解覆盖原始类中的 dealloc。那么当对象被释放时释放这个aProperty的正确方法是什么?

@implementation AClass (ACategory)

@synthesize aProperty;

- (void)dealloc {
    [aProperty release];
    // this will skip the original dealloc method from what I understand
    [super dealloc];
}

@end

【问题讨论】:

    标签: objective-c dealloc objective-c-category


    【解决方案1】:

    嗯,这有点问题,因为你的代码是错误的。

    1. 您不能在类别中声明实例变量;使用最新的 Objective-C ABI,您可以在类扩展 (@interface AClass () {//...) 中声明新的实例变量,但这与类别 (@interface AClass (ACategory)) 不同。
    2. 即使可以,实例变量声明的语法也是在@interface 行之后用大括号括起来。

    您可以在类别中声明属性,但必须在不使用新实例变量的情况下定义其存储(因此,@dynamic 而不是 @synthesize)。


    至于您的实际问题,除非您使用方法调配(由method_exchangeImplementations 等运行时函数促进),否则您不能调用被覆盖方法的原始实现。无论如何,我建议不要这样做;这真的很可怕也很危险。


    更新:类扩展中实例变量的解释

    类扩展类似于类别,但它是匿名的,必须放在与原始类关联的.m 文件中。它看起来像:

    @interface SomeClass () {
        // any extra instance variables you wish to add
    }
    @property (nonatomic, copy) NSString *aProperty;
    @end
    

    它的实现必须位于您班级的主要@implementation 块中。因此:

    @implementation SomeClass
    // synthesize any properties from the original interface
    @synthesize aProperty;
    // this will synthesize an instance variable and accessors for aProperty,
    // which was declared in the class extension.
    - (void)dealloc {
        [aProperty release];
        // perform other memory management
        [super dealloc];
    }
    @end
    

    因此,类扩展对于将私有实例变量和方法保留在公共接口之外很有用,但不会帮助您将实例变量添加到您无法控制的类中。覆盖-dealloc 没有问题,因为您只需像往常一样实现它,同时为您在类扩展中引入的实例变量包括任何必要的内存管理。

    请注意,这些内容仅适用于最新的 64 位 Objective-C ABI。

    【讨论】:

    • +1 表示“方法混乱......真的很可怕和危险”
    • 感谢@Jonathan。我在 SO 编辑器中模拟了示例,但感谢您指出语法错误。
    • 如果这有帮助,如果您能接受它作为您问题的答案,那就太好了。否则,如果还有什么让您感到困惑的地方,请告诉我,我会尽力澄清。 :)
    • 您能否详细说明声明实例变量将如何与类扩展一起使用?我们将如何处理 dealloc 覆盖问题?谢谢:)
    【解决方案2】:

    顺便说一句,您可以使用关联引用来“模拟将对象实例变量添加到现有类”。

    基本上,您可以添加一个关联对象,如下所示:

    static void* ASI_HTTP_REQUEST;  // declare inside the category @implementation but outside any method    
    
    // And within a method, init perhaps
    objc_setAssociatedObject(self, 
        &ASI_HTTP_REQUEST, 
        request, 
        OBJC_ASSOCIATION_RETAIN);
    

    并通过发送'nil'释放关联对象:

    // And release the associated object
    objc_setAssociatedObject(self,
        &ASI_HTTP_REQUEST, 
        nil, 
        OBJC_ASSOCIATION_RETAIN);
    

    Apple 文档是 here

    我花了一段时间才找到,所以我希望它可以帮助某人。

    【讨论】:

    • 好!但是最后一个问题,你什么时候会取消你的关联对象?你怎么知道这个类别会被发布?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 1970-01-01
    • 2015-04-20
    相关资源
    最近更新 更多