【问题标题】:iPhone basic memory managementiPhone基本内存管理
【发布时间】:2011-03-21 15:42:39
【问题描述】:

这是正确的内存管理吗?我想知道我是否应该在-viewDidLoad 中的alloc 之后release

SomeViewController.h

#import <UIKit/UIKit.h>

@interface SomeViewController : UIViewController {
    UIButton *someButton;
    NSString *someString;
}

@property (nonatomic, retain) IBOutlet UIButton *someButton;
@property (nonatomic, copy) NSString *someString;

@end

SomeViewController.m

#import "SomeViewController.h"

@implementation SomeViewController

@synthesize someButton, someString;

- (void)viewDidLoad {
    [super viewDidLoad];
    someButton = [[UIButton alloc] init];
    someString = [[NSString alloc] init];
}

- (void)viewDidUnload {
    self.someButton = nil;
    self.someString = nil;
}

- (void)dealloc {
    [someButton release], self.someButton = nil; 
    [someString release], self.someString = nil;
    [super dealloc];
}

@end

谢谢

编辑:还有一件事。如果我在 IB 中放置了 UIButton,我还需要 alloc 吗?

【问题讨论】:

    标签: iphone objective-c xcode iphone-sdk-3.0 memory-management


    【解决方案1】:

    这是一个相当长的故事,你可以通过谷歌搜索找到,有人可能会进入这里,但为了简短起见,这里有一些调整:

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.someButton = [[[UIButton alloc] init] autorelease];
        self.someString = [[[NSString alloc] init] autorelease];
    }
    

    即使用二传手 (self.something = ...;) 并始终使用 releaseautorelease 任何 alloc。 (逻辑上的区别是谁“拥有”这些对象;通过这些调整,函数放弃了所有权,而类得到了它。)

    编辑:不,如果您在 IB 中创建一个按钮,该按钮将就在那里,并使用您的样式进行分配和初始化。

    【讨论】:

      【解决方案2】:

      当您对一个对象调用 init 时,保留计数变为 1。您有两个不同的 setter 属性:一个是 UIButton 的“保留”,另一个是 NSString 的“复制”。当你打电话时

      self.someButton = someUIButtonObject;
      

      someUIButtonObject 收到一条保留消息,因此它的保留计数上升到 1。对于您的原始代码,在 dealloc 中调用 release 将释放对 someUIButtonObject 的一个引用,但它的保留计数仍然为 1,因此被泄露。

      您的 NSString 的另一种情况有不同的问题,但仍然会泄漏内存。在这里,您对 [[NSString alloc] init] 的调用会产生一个新的字符串对象,然后调用

      self.someString = someNSStringObject;
      

      导致创建一个复制 someNSStringObject 内容的全新对象。在这种情况下, someNSStringObject 和 setter 的复制对象每个都有一个保留计数。在这里,您泄漏了您分配初始化的字符串,因为您不再拥有对它的引用,并且它超出了范围,保留计数为 1。

      附注:我不知道您的实际代码是什么样的,但不要忘记 NSStrings 是不可变的(因此仅调用 [[NSString alloc] init] 非常没用)并且 UIButton 需要一个框架(试试 [[UIButton alloc] initWithFrame:(CGRect)frame];)。

      基本上,您需要将每个对保留、复制或分配的调用与对释放(或自动释放)的调用相匹配。这是合适的,所以使用

      self.someButton = [[[UIButton alloc] init] autorelease];
      

      这将释放对象,但在未来某个未知时间。如果您的内存非常紧张并且您需要尽快内存,请不要使用自动释放。在这种情况下,你会这样做:

      UIButton* tempButton = [[UIButton alloc] init];
      self.someButton = tempButton;
      [tempButton release];
      

      这保证您的自动释放池中没有大对象等待。

      此外,始终使用 getter/setter 来访问这些属性(self.someButton 而不是 someButton)。这样您就不会意外地将 someButton 分配给新指针并泄漏旧指针。

      当您在 IB 中创建按钮时,XIB 会保存对该按钮的引用(+1 保留计数)。如果您创建一个 IBOutlet 以便以编程方式访问该按钮,您将在该对象上获得另一个保留,因此如果您有一个指向 someButton 的 IBOutlet,则一旦加载了 XIB,someButton 的保留计数为 2。您不需要分配对象,这是在 XIB 加载到内存时自动完成的。此外,您只负责释放对按钮的一个引用(您的 IBOutlet 引用)。一般来说,一旦您知道不再需要它,就立即发布您的参考资料是一个很好的做法。例如,如果您知道您需要一个按钮并且必须进行初始自定义而不做其他任何事情,那么您可能会这样做:

      -(void)viewDidLoad {
        // Do some customization of someButton
        [someButton release];
      }
      

      否则,您可能会在 viewDidUnload 中释放 someButton,因为您知道此时您将不再需要对该按钮的引用。

      【讨论】:

      • 如果我在 IB 中创建 UIButton 并在 -viewDidLoad 中自定义它然后在那里发布,我还需要在 -viewDidLoad 中执行 self.someButton = nil 并在 -dealloc 中发布它吗?
      • 不,您应该只松开按钮一次。您实际上不必将其设置为零,它比其他任何东西都更偏好。不过,不要在 viewDidLoad 和 dealloc 中释放它 - 选择其中一个。
      【解决方案3】:

      如果您的按钮是在 IB 中设置的,则无需在代码中分配(IB 会为您分配)。

      基本上,您使用allocnew 创建的每个对象都应该在代码中的某处有一个release。如果是接口变量,应该在dealloc函数中释放。

      【讨论】:

        猜你喜欢
        • 2011-04-10
        • 2011-10-10
        • 2010-10-28
        相关资源
        最近更新 更多