0

I have a UIView subclass, and within this I call this other UIView subclass.

Stars.h

@interface Stars : UIView {

    BOOL _gained;

}

@property (nonatomic, weak) id<NSObject> delegate;
@property (nonatomic) BOOL gained;

-(void)animateAndRemove;

@end

Stars.m

#import "Stars.h"

@implementation Stars

@synthesize delegate = _delegate;
@synthesize gained = _gained;

- (id)initWithFrame:(CGRect)frame
{
    frame.size.width = 31;
    frame.size.height = 30;
    self = [super initWithFrame:frame];
    if (self) {
        _gained = NO;
        self.backgroundColor = [UIColor clearColor];

        // Add star
        UIImageView *star = [[UIImageView alloc] initWithFrame:frame];
        [star setImage:[UIImage imageNamed:@"star-sticker"]];
        [self addSubview:star];

    }
    return self;
}

- (void)animateAndRemove
{
    [UIView animateWithDuration:0.2
                          delay:0
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI);
                         self.transform = transform;
                     }
                     completion:^(BOOL finished){
                         [UIView animateWithDuration:0.3
                                               delay:0
                                             options:UIViewAnimationOptionCurveLinear
                                          animations:^{
                                              CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI);
                                              self.transform = transform;
                                              CGAffineTransform move = CGAffineTransformMakeTranslation(0, -200);
                                              self.transform = move;
                                              self.alpha = 0.0;
                                          }
                                          completion:^(BOOL finished){
                                              if ([self.delegate respondsToSelector:@selector(removeStar:)]) {
                                                  [self.delegate performSelector:@selector(removeStar:) withObject:self];
                                              }
                                          }];
                     }];
}

- (void)dealloc
{
    NSLog(@"%s",__FUNCTION__);
}

@end

This simply adds an image, which I animate before removing. I add this to the original UIView like this:

star1 = [[Stars alloc] init];
star1.center = self.center;
star1.delegate = self;
[self addSubview:star1];

And start the removal process with the animation like this:

if (CGRectIntersectsRect(thumbR, star1.frame)) {
        if (!star1.gained) {
            star1.gained = YES;
            [star1 animateAndRemove];
        }
    }

Which when complete calls this:

- (void)removeStar:(Stars *)star
{
    star.delegate = nil;
    [star removeFromSuperview];
    star = nil;
}

Now the NSLog in dealloc isn't called when the class is removedFromSuperview and set to nil. Why not?

I'm actually seeing the same thing with the first UIView that i'm loading this Stars class into. That one is also not dealloc'ing when I think it should. Both dealloc methods are intact called when I reassign the containing UIView by alloc and initing it again.

Am I wrong to expect this to dealloc when it's been removed from view and set to nil?

Kazuki Sakamoto
  • 13,929
  • 2
  • 34
  • 96
Darren
  • 10,182
  • 20
  • 95
  • 162

1 Answers1

1

Consider your removeStar:

- (void)removeStar:(Stars *)star
{
   star.delegate = nil;
   [star removeFromSuperview];
   star = nil;
}

This must be called from somewhere using a call along the lines of:

[<some object reference> removeStar:<some Stars reference>]

Now the variable star in removeStar is local to that method. When the method is called this variable is initialized to the passed in Stars reference - so you have an additional reference. over and above the reference the caller of removeStar has, to the Stars instance the method is called with.

When you then assign nil to this local variable you only remove this additional reference. The caller of removeStar still has its reference. So no dealloc.

Guessing: The caller of removeStar is probably the owner of the instance and needs to remove its reference as well.

CRD
  • 52,522
  • 5
  • 70
  • 86
  • Your right, you can see I call removeStar from the Star class after the animation is complete and it passes itself as the sender. I assumed as they where just pointers, that setting one to nil would set the object to nil. Thanks – Darren Jun 09 '12 at 19:49