【问题标题】:What is the correct way to declare a private member variable for an Objective-C class?为 Objective-C 类声明私有成员变量的正确方法是什么?
【发布时间】:2011-02-06 07:50:27
【问题描述】:

我无法让变量赋值在以下初始化程序中工作:

- (id)initWithBaseURL:(NSString *)url  {
  self = [super initWithNibName:@"MyNibName" bundle:nil];
  if (self) {
    baseURL = [url copy];
  }

  return self;
}

我已经验证了 url 参数对于适当的内容是有效的(创建为通过 NSXMLParser 构建的 NSMutableString,然后在调试器的 initWithBaseURL 方法中检查),但是在将复制操作的结果分配给 baseURL 之后,baseURL变量“超出范围”并且仍然无效。任何尝试在类的其他方法中访问 baseURL 变量都会导致 EXC_BAD_ACCESS 错误。

我在 .h 文件中声明了 baseURL,如下所示,没有 @property 或 @synthesize 操作,因为我试图将它用作私有成员变量:

@interface SignInViewController : UIViewController {
  // other variables

  @private
  NSString *baseURL;
}

// Other @property delcarations, IBAction method declartions, and method declarations

@end

我也尝试使用here 描述的技术,但这只会导致初始化程序中出现 EXC_BAD_ACCESS 错误。

我在做什么会导致 EXC_BAD_ACCESS 错误发生,我该如何解决?

【问题讨论】:

  • “超出范围”的事情是红鲱鱼。见这里:stackoverflow.com/questions/1566086/…
  • 调试您的问题(这超出了您发布的内容):如果错误发生在初始化程序中,则参数 url 可能无效。尝试CFShow(url) 并查看是否在此处捕获或遇到错误。如果不是,则检查 CFShow 的输出以确保没有忽略某些内容(无效的参数类型?)。如果控制台中一切正常,请尝试在启用 NSZombies 的情况下运行。祝你好运
  • @Justin 我尝试按照您的建议调用 CFShow(url) ,但得到相同的 EXC_BAD_ACCESS 错误。启用 NSZombies 表明我正在处理一个已释放的实例,这很奇怪,因为直到 initWithBaseURL: 方法之后才调用 release。
  • 啊哈!维护对 url 值的引用的实例设置不正确(在外部类的初始值设定项中设置值时,我忘记包含自引用)。 NSZombies 和 CFShow 来救援!

标签: iphone objective-c variables


【解决方案1】:

以下是一些可能相关也可能不相关的观察结果。

  • 从 Obj-C 的角度来看,您发布的代码绝对没问题。
  • 您应该真正调用 UIViewController 的指定初始化程序 initWithNibName:bundle:,而不是 [super init]
  • 您将方法命名为initWithBaseURL:,但它需要NSString 作为参数。虽然这确实与 @interface 中的声明相匹配,但请确保您不希望 baseURL 成为代码中其他位置的 NSURL 对象。
  • 删除@private 后会发生什么?我怀疑您看到的异常没有任何变化。

确保你不要这样做:

NSString *myURL = [NSString stringWithFormat:...]; // myURL is autoreleased
SignInViewController *controller = [[SignInViewController alloc] initWithBaseURL: myURL]; // retains myURL because it's immutable
[myURL release]; // does not crash because myURL has been *retained*
// baseURL is left with 0 retain count

您可以验证将copy 发送到一个NSMutableString 确实会产生另一个对象,而将copy 发送到一个不可变的NSString 等效于retain,只是因为在不可变对象的精确副本上浪费内存是低效的。如果 baseURL 确实是 myURL 的副本,那么当自动释放池耗尽时就会发生崩溃。

换句话说,错误可能在一个地方,只是在另一个地方表现出来。上面的例子不是太做作。

【讨论】:

  • 感谢 initWithNibName:bundle: 中的正确,我完全忽略了这一点。此外,正如您所怀疑的,将其更改为 public 没有任何效果。
【解决方案2】:

您已正确声明它。另外,您发布的程序是正确的。

更正:

正如 Costique 所说:您应该调用超类的指定初始化程序之一。

【讨论】:

  • 我支持这个。除了阿德里安目前正在研究的方面之外,该错误还存在于某个地方。
  • 感谢您的确认。正如@Costique 所指出的,我传入的值确实存在其他问题。
猜你喜欢
  • 2012-03-05
  • 1970-01-01
  • 2011-04-04
  • 1970-01-01
  • 2022-12-14
  • 2021-08-16
  • 2016-03-31
  • 1970-01-01
  • 2020-10-04
相关资源
最近更新 更多