对象似乎被释放但内存占用不断增加

时间:2013-09-28 23:20:28

标签: ios objective-c cocoa-touch memory-management ios7

我已经开发了一个应用程序大约一个星期左右,我认为这是一个好的时间来分析它以确保我正在做的一切正确,我发现即使我的所有对象都得到了dealloc'd分配金额正在上升。当我释放一个对象时,我会执行以下操作:

[object release];
object = nil;

在我的应用中,我有一个初始视图控制器,它决定要显示我的LoginViewController还是TimeLineViewController,具体取决于我是否有访问令牌。 (这部分无关紧要,因为我遇到的问题在LoginViewController / SignupViewController内。)。登录控制器有两个文本字段和两个按钮,这些按钮可以将sVC推送到导航视图控制器或尝试登录。

奇怪的是,在我的视图和视图控制器上调用dealloc方法,但是在调用它们之后内存会上升。

SDK 7.0版 Xcode 5.0版

编辑:

在我的LoginViewController中,当我从LoginView获得单击SignupButton的事件时,会调用此方法:

- (void)signupButtonPressed
{
    SignupViewController *signupVC = [[SignupViewController alloc] init];
    [self.navigationController pushViewController:signupVC animated:true];
    destroy(signupVC);
}

***注意,破坏宏如下:

#define destroy($x)                                             \
if($x)                                                          \
{                                                               \
[$x release];                                               \
$x = nil;                                                   \
}

创建SignupViewController时,ViewDidLoad方法如下:

self.view = [[SignupView alloc] initWithFrame:self.view.frame];

    [[(SignupView *)self.view evtSignupButtonPressed] addHandler:AFFHandler(@selector(signupPressed))];
    [((SignupView *)self.view).profileImage addTarget:self action:@selector(profileImagePressed) forControlEvents:UIControlEventTouchUpInside];

[self.navigationController setNavigationBarHidden:false animated:true];

然后在SignupView中创建视图的UI,如下所示:

- (void)setupUI
{

    self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:IS_IPHONE5 ? @"genericBackground-568h.jpg" : @"genericBackground.jpg"]];

    _overlayView = [[UIView alloc] initWithFrame:self.frame];

    _scrollView = [[UIScrollView alloc] initWithFrame:self.frame];


    _profileImage = [[UIButton alloc] init];

    profileImageContainer = [[UIView alloc] initWithFrame:CGRectMake(18.5, 0, _profileImage.imageView.image.size.width + 10, _profileImage.imageView.image.size.height + 10)];


    selectProfilePictureText = [[UILabel alloc] initWithFrame:CGRectMake(profileImageContainer.affX, 0, 229, 17)];


    UIView *padding = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 17, 40)];

    _usernameField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 284, 40)];
    _usernameField.delegate = self;

    _passwordField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 284, 40)];
    _passwordField.delegate = self;

    _repeatPasswordField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 284, 40)];

    _repeatPasswordField.delegate = self;

    _emailField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 284, 40)];
    _emailField.delegate = self;

    destroy(padding);

    buttonImage = [[UIImage imageNamed:@"largeButton.png"] copy];
    _submitButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, buttonImage.size.width, buttonImage.size.height)];
    [_submitButton addTarget:self action:@selector(signupButtonPressed) forControlEvents:UIControlEventTouchUpInside];


    destroy(buttonImage);




    [self addSubview:_scrollView];
    [self addSubview:_overlayView];
    [_scrollView addSubview:profileImageContainer];
    [profileImageContainer addSubview:_profileImage];
    [_scrollView addSubview:selectProfilePictureText];

    [_scrollView addSubview:_usernameField];
    [_scrollView addSubview:_passwordField];
    [_scrollView addSubview:_repeatPasswordField];
    [_scrollView addSubview:_emailField];
    [_scrollView addSubview:_submitButton];


    destroy(profileImageContainer);
    destroy(selectProfilePictureText);

}

**注意,我已经省略了所有改变了这些对象属性的代码,比如改变了backgroundColour等。

SignupVC和SignupView的dealloc方法如下:

SignupView:

- (void)dealloc
{

    self.usernameField.delegate = nil;
    self.passwordField.delegate = nil;
    self.repeatPasswordField.delegate = nil;
    self.emailField.delegate = nil;

    AFFRemoveAllEvents();

    destroyAndRemove(_usernameField);
    destroyAndRemove(_passwordField);
    destroyAndRemove(_repeatPasswordField);
    destroyAndRemove(_emailField);
    destroyAndRemove(_profileImage);
    destroyAndRemove(_submitButton);
    destroyAndRemove(_scrollView);
    destroyAndRemove(_overlayView);

    if(buttonImage)
        destroy(buttonImage);


    [super dealloc];
}

SignupVC(在按下NavigationBar的后退按钮后调用它)

    - (void)dealloc
    {
        [[(SignupView *)self.view evtSignupButtonPressed] removeHandlersForObserver:self];
        [((SignupView *)self.view).profileImage removeTarget:self action:@selector(profileImagePressed) forControlEvents:UIControlEventTouchUpInside];
        destroy(profileImage);
        destroyAndRemove(self.view);


        [super dealloc];
    }

DestroyAndRemove这样做:

#define destroyAndRemove($x)                                    \
if($x)                                                          \
{                                                               \
[$x removeFromSuperview];                                   \
[$x release];                                               \
$x = nil;                                                   \
}

2 个答案:

答案 0 :(得分:5)

切换到ARC。说真的,没有充分的理由不使用它,它甚至可能解决你的记忆问题:

1)Apple强烈鼓励并表示他们在更新和新应用中使用ARC

2)绝大多数新的应用程序提交和更新使用ARC,并且在绝大多数情况下它已被证明与手动引用计数一样有效(您的应用程序可能不是例外)对此)。

3)ARC简化了您作为Objective-C开发人员的生活。您不必再在releaseretain等地方丢弃代码了。

4)有一个易于使用的转换工具:

转到Edit> Refactor> Convert to Objective C ARC

5)即使您使用的是尚未切换到ARC的第三方库(最常用的已有),您也可以选择不在单个文件上使用ARC。请参阅此另外SO post了解如何操作。

如果您在切换到ARC之后仍然遇到问题 - 如上所述,切换到ARC可能会修复您的内存问题 - 请回来,我们会再次提出。

答案 1 :(得分:4)

哪些物体正在吸积?

即。使用分配工具时,打开"仅跟踪实时对象" (或等效命名的特征)。然后使用您的应用程序,并查看哪些对象在内存中不应该存在,哪些不应该。也可以打开参考事件跟踪器。

更有可能的是,这是一个保留周期。也许一个强大的计时器引用你的对象?或者其他类似的关系。

一旦你确定了记忆中存在的物体,那么你应该点击保留和释放的清单,看看什么是不平衡的。

请注意,您确实应该使用ARC。