【问题标题】:Nested factory methods in Objective-CObjective-C 中的嵌套工厂方法
【发布时间】:2010-03-21 21:43:00
【问题描述】:

使用嵌套工厂方法处理内存管理的最佳方法是什么,如下例所示?

@interface MyClass : NSObject {
    int _arg;
}

+ (MyClass *) SpecialCase1;
+ (MyClass *) SpecialCase2;
+ (MyClass *) myClassWithArg:(int)arg;
- (id) initWithArg:(int)arg;

@property (nonatomic, assign) int arg;

@end

@implementation MyClass

@synthesize arg = _arg;

+ (MyClass *) SpecialCase1
{
    return [MyClass myClassWithArg:1];
}

+ (MyClass *) SpecialCase2
{
    return [MyClass myClassWithArg:2];
}

+ (MyClass *) myClassWithArg:(int)arg
{
    MyClass *instance = [[[MyClass alloc] initWithArg:arg] autorelease];

    return instance;
}

- (id) initWithArg:(int)arg
{
    self = [super init];
    if (nil != self) {
        self.arg = arg;
    }

    return self;
}

@end

这里的问题(我认为)是自动释放池在 SpecialCaseN 方法返回给它们的调用者之前被刷新[编辑:显然不是 - 见下面的 cmets]。因此,SpecialCaseN 的最终调用者不能依赖已保留的结果。 (在尝试将 [MyClass SpecialCase1] 的结果分配给另一个对象的属性时,我得到“[MyClass copyWithZone:]: unrecognized selector sent to instance 0x100110250”。)

需要 SpecialCaseN 工厂方法的原因是,在我的实际项目中,初始化实例需要多个参数,并且我有一个我希望能够创建的“模型”实例的预定义列表很容易。

我确信有比这更好的方法。

[编辑:根据请求添加@interface。]

【问题讨论】:

  • 可以发一下MyClass的界面吗? (另外,我会为这个类写一个 dealloc 方法,如果只是为了完整性)
  • 完成。 (这是一个简化的示例,改编自我正在爆炸的实际课程。)

标签: iphone objective-c xcode macos


【解决方案1】:

为什么你认为自动释放池被刷新了?

自动释放池不会在 cocoa-touch 中刷新,除非您刷新它,或者将控制权返回给事件循环。

来自iPhone Memory Management Guide

应用程序工具包自动 在一个开始时创建一个池 事件循环(或事件循环迭代), 例如鼠标按下事件,以及 最后释放它,所以你的代码 平时不用担心 他们。

【讨论】:

  • 通过阅读这个答案,特别是:“不。你只能指望周围的对象,直到你从你所在的任何方法或函数返回。通常,当控制返回时自动释放池被刷新“ stackoverflow.com/questions/2017793/…
  • 是的,这意味着在事件循环调用的方法返回之前,它们不会被刷新。如果您想在此之后保留某些内容,则必须通过发送保留消息或将其放入具有保留或复制属性的属性来保留它。您可以使用 SpecialCaseN 的结果来执行此操作。我的观点是自动释放的对象在从 SpecialCaseN 返回后仍然处于活动状态
  • 这就是为什么许多人警告不要改写内存管理指南的原因。它给人们一些奇怪的想法,比如当方法返回时,顶级自动释放池会神奇地刷新。人们应该阅读内存管理指南并按照它所说的去做。
  • 我明白你的意思。那么,从表面上看,上述方法没有明显的缺陷吗?
  • "如果你想在之后保留某些东西,你必须保留它,要么发送保留消息,要么将其放入具有保留或复制属性的属性中。你这样做的结果是特例N。”所以这正是我对 SpecialCaseN 的结果所做的(把它放在一个带有 copy 属性的属性中),但是当它爆炸时 [MyClass copyWithZone:] 是一个无法识别的选择器。
【解决方案2】:

该错误准确描述了问题:调用了 copyWithZone,但未在 MyClass 中实现。检查分配给它的属性的属性或实现(查看它是否正在复制)。此外,如果 MyClass 的实例用作 NSDictionary 的键,则将调用 copyWithZone。这是implementing copyWithZone的一些信息。

【讨论】:

  • 通常假设 copyWithZone: 是从 NSObject 继承的,但事实并非如此。当你创建一个 NSObject 子类时,你通常必须直接实现它。
  • 是的 - 就是这样。我确实假设我从 NSObject 免费获得了 copyWithZone:。谢谢!
猜你喜欢
  • 2011-07-23
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多