I'm sorry for repost. What have really bug me is if property retain should release when:
case 1 : (code below) button is already alloc in init: then add to subview then release it, and by any chance I set the button property in another class (I didn't release in dealloc:) it will leak then? case 2 : button is already alloc in init: then add to subview then release it, and by any chance I didn't set the any button property in another class (I didn't use the property) (I release it in dealloc) then it will crash.So what should I do if I want to alloc button in init: and I want to set the property too ?
@interface SomeClass : UIView {
UIButton *_button;
}
@property (nonatomic, retain)UIButton *button;
@implementation SomeClass
@synthesize button = _button;
- (id)init {
_button = [[UIbutton alloc] initWithFrame:CGRectMake(0.0f,0.0f,100.0f,20.0f)];
[[_button titleLabel] setFont:BUTTON_FONT];
[_button setBackgroundImage:[[UIImage imageNamed:@"button_blue.png开发者_如何学Python"] stretchableImageWithLeftCapWidth:20.0f topCapHeight:15.0f] forState:UIControlStateNormal];
[_button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_button setTitleShadowColor:[UIColor blackColor] forState:UIControlStateNormal];
[[_button titleLabel] setShadowOffset:CGSizeMake(0.0f, 1.0f)];
[_button addTarget:self action:@selector(buttonDidTapped:) forControlEvents:UIControlEventTouchUpInside];
[self addSubView:_button];
[_button release];
}
- (void)dealloc {
//[self.button release]; // case 1
[self.button release]; // case 2
[super dealloc];
}
@end
So what should I do if I want to alloc button in init: and I want to set the property too ?
Here's how your code should look:
@implementation SomeClass
@synthesize button = _button;
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
UIButton *button = [[UIbutton alloc] initWithFrame:CGRectMake(0.0f,0.0f,100.0f,20.0f)];
// Setup the button here...
[self addSubView:button];
self.button = button;
[button release];
}
return self;
}
- (void)dealloc {
[_button release];
[super dealloc];
}
@end
Changes I made:
initWithFrame:
is the designated initializer of theUIView
, so that's the init method you've got to override- Always check to make sure that your superclass initialized successfully before you setup your class
- You've got to return self at the end of your init statements. I don't think your code would have compiled as written.
- You created a property, you should use it. Use a temp variable to do all the setup for your button, then when you're finished with setup, use the property accesssor to set the variable and release your temp variable.
- Because you only use the property to get/set your button, when it's time to dealloc you can guarantee that the
_button
iVar will either be valid or nil. Either way calling release on that variable is OK.
I don’t understand what you mean by “using it for read-only”. As declared, the property is read-write both for the class itself and from the outside. But the question can be reasonably answered nevertheless – once your class retains some object, it must release it when it gets deallocated.
P.S. I think you can safely drop the underscore prefix for private variables, it serves no real purpose and makes you write more code. In fact, with modern runtimes you can even drop the instance variable declaration:
@interface Foo : NSObject {}
@property(assign) BOOL bar;
@end
@implementation Foo
@synthesize bar;
@end
OK, third attempt: The problem is that you are in fact setting the property by assigning to the instance variable. Properties and instance variables are closely tied, when you give the following declaration…
@synthesize button = _button;
…you are saying that the _button
instance variable should be used to store the value of the button
property. Which means that your code over-releases, since you alloc the button in init
(+1), release the button in init
(-1) and then release again in dealloc
(-1 again).
If you have not yet studied the Cocoa Memory Management Guide, do it. Even if you don’t plan to read any other documentation (which would be a pity), make an exception with this one, it will pay you back plenty.
sure, You should release it, because you have used retain for it.
In your -init
method, you have a balanced retain
/release
call. So you don't need to release it again. But by doing it, you are sacrificing the reliability of the value held by _button
. If somewhere down the lane the button is removed from the subviews, the button's retainCount could hit zero and it can be deallocated. Then the value held by _button
is garbage. So you should not release _button
in -init
and rather you should do that in -dealloc
.
Now, if you access the property elsewhere (outside this UIView object), you don't need to release it again unless you retain it there.
Try to replace [self.button release];
with [self.button removeFromSuperview];
精彩评论