开发者

Question on when and where to release an object

I have several places where I need to display an alert and handle the dismiss operation in the same way, namely take them to the same view controller. Instead of duplicating the alert specific code in all those places, I created a separate class like below:


AlertUtility.h:
@interface AlertUtility : NSObject {
}
- (void) displayAlert;
@end

AlertUtility.m:
@implementation AlertUtility {
- (void) displayAlert {
   UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:... message:... 
      delegate:self cancelButtonTitle:... otherButtonTitles:nil] autorelease];
   [alert show];
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
   // Create another view controller and display its views
   [self release] // Release current object because I'm not releasing it where I create it
}

}

Where I need to use this alert (i.e. in MyVie开发者_JAVA百科wController), I have the following:


MyViewController.m:
AlertUtility *utility = [[AlertUtility alloc] init];
[utility displayAlert];

As you can see, I am not releasing the utility object here (which I should since I own it), but rather in the didDismissWithButtonIndex method of the AlertUtility class. I am clearly missing something here.

I've tried autoreleasing the utility object but then by the time the didDismissWithButtonIndex method is 'called' on the utility object, that object was already released (due to the autorelease).

I've tried making the displayAlert method static (and calling it with [AlertUtility displayAlert];), but then the didDismissWithButtonIndex is never called.

Should I just release the current object from within the didDismissWithButtonIndex method, like I do now, or is there a way to release it in MyViewController instead (without creating a AlertUtility property for the current class)?

Thanks!

EDIT Should I use the Singleton pattern instead maybe?


Calling [self release] is a big no-no because no object has information about what other object refer to it. The retention system is intended to make sure that if ObjA needs ObjB, that ObjB will remain in memory until ObjA no longer needs it. If ObjB releases itself, the entire system breaks down.

In this case, the UIAlert itself retains the AlertUtility object as it's delegate so you can release the AlertUtility as soon as your done with it just as you would a UIAlert.

So,this is fine:

AlertUtility *utility = [[AlertUtility alloc] init];
[utility displayAlert];
[utility release];   // released here, but still alive

It's not a problem if the AlertUtility object is still alive past the release. A release doesn't necessarily kill an object. It merely says that the object sending the release message has no further need of the released object. Each retaining object just has the responsibility to balance all retains (including implicit ones like init) with a release. Past that the retaining object has no interest and no responsibility for whether the system keeps released object alive or not.

After all, any single object may be retained by multiple retaining objects each with no knowledge of the other. In this case the AlertUtility is retained once by the ViewController with init. Then it is retained again by the UIAlert as a delegate. (Edit: UIAlert assigns it delegate)When ViewController releases the AlertUtility object, it will remain alive as long as the UIAlert needs it and vice versa.

Since the UIAlert object is retained by the UIWindow when it is displayed this means that the AlertUtility object will remain alive until after the UIAlert is dismissed. (Edit: this is valid only for the view, not the AlertUtility delegate)

You would not normally have a UIAlert delegate whose existence is solely dependent on that of the UIAlertitself. Usually, the UIAlert delegate is the view controller that evokes the alert. That way, you don't have to worry about the delegate dying before it completes the task associated with the alert.


You can use this instead:

void displayAlert(NSString *title, NSString *message)
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
        message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
    [alert release];
}

Or just:

#define MY_ALERT(TITLE, MESSAGE) \
[[[[UIAlertView alloc] initWithTitle:TITLE \
                             message:MESSAGE \
                            delegate:nil \
                   cancelButtonTitle:@"OK" \
                   otherButtonTitles:nil] autorelease] show]

And then write:

MY_ALERT(nil, @"Press, OK!");


Your pattern works, although I agree releasing it "elsewhere" is ugly and I try to avoid this. You could make the following approach:

// AlertUtility.h:
@interface AlertUtility : NSObject {
}
- (void) displayAlert;
@end

// AlertUtility.m:
@implementation AlertUtility {
- (void) displayAlert {
   UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:... message:... 
      delegate:self cancelButtonTitle:... otherButtonTitles:nil] autorelease];
   [alert show];
   [self retain];   // explicitly retain this (self) object
}

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
   // Create another view controller and display its views
   [self release] // Release current object because you retained it earlier here
}

}

And later:

 // MyViewController.m:
    AlertUtility *utility = [[AlertUtility alloc] init];
    [utility displayAlert];
    [utility release];   // released here, but still alive

Edit: removed the release on the alert, as it was autoreleased.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜