【问题标题】:iphone @property(retain), init(), and standardsiphone @property(retain)、init() 和标准
【发布时间】:2010-06-09 12:31:37
【问题描述】:

我是 iphone 内存管理的新手,对标准/正确性有疑问。

我的头文件声明:

 IBOutlet UITabBarController *tabBarController;
 @property (nonatomic, retain) UITabBarController *tabBarController;

在我的 init() 代码中,我正在执行以下操作:

self.tabBarController = [[UITabBarController alloc] init];
[tabBarController release];
NSLog(@"Retain count of tbc: %d",[tabBarController retainCount]);

将保留计数恢复为一。从标准化的角度来看,这是否正确?它对我来说只是看起来有点不同,但我还是新手。

谢谢

【问题讨论】:

    标签: iphone properties standards


    【解决方案1】:

    这很正常。

    你做什么:

    self.tabBarController = [[UITabBarController alloc] init];
    [tabBarController release];
    

    可能由编译器执行为:

    id *tempVar = [[UITabBarController alloc] init];
    self.tabBarController = tempVar;                  //till now, retainCount is 2
    [tabBarController release];                       //now, retainCount is 1
    

    当你分配它时,这个内存块将被一个临时变量保留。所以更好的方法是:

    UITabBarController *tabCtl = [[UITabBarController alloc] init];
    self.tabBarController = tabCtl;
    [tabCtl release];
    

    我不是object-c的专家,只是对编译有一些了解。所以,如果我错了,请高手指出。

    【讨论】:

      【解决方案2】:

      要分配给属性,您应该使用

      self.tabBarController = [[[UITabBarController alloc] init] autorelease];
      

      [tabBarController release];
      tabBarController = [[UITabBarController alloc] init];
      

      (记得先释放之前的值)

      属性设置器/获取器应单独负责保留/释放实例变量。如果您(或其他人)更改属性设置器以获取输入的副本而不是保留它,会发生什么?在这种情况下,您将过度释放实例变量并泄漏原始对象。

      您实际上是在发送一条具有私人副作用的消息,然后通过释放下一行的实例变量来使用这些私人细节的知识。即您的代码与以下内容相同:

      [self setTabBarControler:[[UITabBarController alloc] init]];
      /* Relying on knowledge of the instance variable is bad here, setTabBarController
         might do something different in the future */
      [tabBarController release];
      

      即使你完全控制了这个类,你仍然应该坚持抽象和封装的基本原则。将实例变量的保留/释放留给底层属性实现。

      【讨论】:

      • 在 init 方法的第一行释放实例变量简直是疯话。
      • 我在学书,书推@property()的;在这种情况下,我真的应该使用该符号吗?还是自己处理 alloc init?
      • @property() 是访问器方法的语法糖。所以问题是你应该使用 setter 访问器方法(这就是使用该属性将为你做的事情)还是不使用(无论哪种方式你都必须处理 alloc/init)?通常,您应该使用 setter 方法使属性的观察者能够收到更新通知,但这与 init 方法无关。此外,如果在子类中重写了 setter 方法,这将导致在子类初始化之前调用它 - 这会很糟糕。
      【解决方案3】:

      为什么不

      tabBarController = [[UITabBarController alloc] init];
      

      ?

      【讨论】:

      • 这对我来说也很有意义 - 这样做并省略了合成的 setter 方法。在这种情况下,我检查了保留计数 - 现在为 2 - 并发现我自己释放了这个东西,这对我来说很奇怪。我很感激这个提示 - 我现在要走这条路。
      【解决方案4】:

      你可以这样做,但最好不要在你的 init() 方法中使用这个隐式的 setter 语法(因为你可能会覆盖 setter 并做进一步的事情,如果对象没有完全初始化可能还不能工作) .

      只要做:

      tabBarController = [[UITabBarController alloc] init];
      

      【讨论】:

      • 如果你把它放在错误的地方并且它被多次调用,这可能会泄漏以前的值。例如,在视图控制器中,在 awakeFromNib 中可以,但在 viewDidLoad 中不行。
      • @progrmr:我指的是init() 方法,我猜tabBarControllerinit() 被调用之前不会有另一个值。
      猜你喜欢
      • 1970-01-01
      • 2010-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-05
      • 1970-01-01
      • 2011-06-09
      • 2015-08-18
      相关资源
      最近更新 更多