Alex Gittemeier
Alex Gittemeier

Reputation: 5373

Memory issue in objective c

My application is attempting to use a zombie instance of something, though i have no idea where the problem is. the exception consistently occurs when invoking (IBAction)addTag:sender.
my stack trace is below:

2012-03-12 17:06:45.935 FavoriteTwitterSearches[3636:f803] -[__NSCFString addTag:]: unrecognized selector sent to instance 0x6a30d90
2012-03-12 17:06:45.943 FavoriteTwitterSearches[3636:f803] CRASH: -[__NSCFString addTag:]: unrecognized selector sent to instance 0x6a30d90
2012-03-12 17:06:45.947 FavoriteTwitterSearches[3636:f803] Stack Trace: (
    0   CoreFoundation                      0x013bc06e __exceptionPreprocess + 206
    1   libobjc.A.dylib                     0x0154dd0a objc_exception_throw + 44
    2   CoreFoundation                      0x013bdced -[NSObject doesNotRecognizeSelector:] + 253
    3   CoreFoundation                      0x01322f00 ___forwarding___ + 432
    4   CoreFoundation                      0x01322ce2 _CF_forwarding_prep_0 + 50
    5   CoreFoundation                      0x013bdec9 -[NSObject performSelector:withObject:withObject:] + 73
    6   UIKit                               0x000165c2 -[UIApplication sendAction:to:from:forEvent:] + 96
    7   UIKit                               0x0001655a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
    8   UIKit                               0x000bbb76 -[UIControl sendAction:to:forEvent:] + 66
    9   UIKit                               0x000bc03f -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 503
    10  UIKit                               0x000bb2fe -[UIControl touchesEnded:withEvent:] + 549
    11  UIKit                               0x0003ba30 -[UIWindow _sendTouchesForEvent:] + 513
    12  UIKit                               0x0003bc56 -[UIWindow sendEvent:] + 273
    13  UIKit                               0x00022384 -[UIApplication sendEvent:] + 464
    14  UIKit                               0x00015aa9 _UIApplicationHandleEvent + 8196
    15  GraphicsServices                    0x012a6fa9 PurpleEventCallback + 1274
    16  CoreFoundation                      0x013901c5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
    17  CoreFoundation                      0x012f5022 __CFRunLoopDoSource1 + 146
    18  CoreFoundation                      0x012f390a __CFRunLoopRun + 2218
    19  CoreFoundation                      0x012f2db4 CFRunLoopRunSpecific + 212
    20  CoreFoundation                      0x012f2ccb CFRunLoopRunInMode + 123
    21  GraphicsServices                    0x012a5879 GSEventRunModal + 207
    22  GraphicsServices                    0x012a593e GSEventRun + 114
    23  UIKit                               0x00013a9b UIApplicationMain + 1175
    24  FavoriteTwitterSearches             0x00001fab main + 187
    25  FavoriteTwitterSearches             0x00001ee5 start + 53
    26  ???                                 0x00000001 0x0 + 1
)
objc[3636]: EXCEPTIONS: finishing handler

Support Files/Main.m:

#import <UIKit/UIKit.h>

#import "AppDelegate.h"
void uncaughtExceptionHandler(NSException *exception);

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int retVal;
    @try {
    retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
    @catch (NSException *exception) {
        NSLog(@"CRASH: %@", exception);
        NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    }
    @finally {
        [pool release];
    }
    return retVal;
}

Controller.m

#import "Controller.h"

@implementation Controller
- (id)init
{
    if (self != nil)
    {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *dir = [paths objectAtIndex:0];
        filePath = [[NSString alloc] initWithString:[dir stringByAppendingPathComponent:@"tagsIndex.plist"]];
        NSFileManager *fileManager = [NSFileManager defaultManager];

        if ([fileManager fileExistsAtPath:filePath] == NO)
        {
            tags = [[NSMutableDictionary alloc] init];
        }
        else
        {
            tags = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
        }

        buttons = [[NSMutableArray alloc] init];
        infoButtons = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)awakeFromNib
{
    for (NSString *title in tags)
        [self addNewButtonWithTitle:title];
}

- (void)refreshList
{
    for (UIButton *button in scrollView.subviews)
        [button removeFromSuperview];

    [infoButtons removeAllObjects];

    float buttonOffset = BUTTON_SPACING;

    for (UIButton *button in buttons)
    {
        CGRect buttonFrame = button.frame;
        buttonFrame.origin.x = BUTTON_SPACING;
        buttonFrame.origin.y = buttonOffset;
        buttonFrame.size.width = scrollView.frame.size.width - BUTTON_SPACING - BUTTON_HEIGHT;
        buttonFrame.size.height = BUTTON_HEIGHT;
        button.frame = buttonFrame;

        UIButton *infobutton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [infoButtons addObject:infobutton];

        buttonFrame = infobutton.frame;
        buttonFrame.origin.x = scrollView.frame.size.width - BUTTON_SPACING - SCROLLBAR_WIDTH;
        buttonFrame.origin.y = buttonOffset;
        infobutton.frame = buttonFrame;

        [infobutton
         addTarget:self action:@selector(infoButtonTouched:)
         forControlEvents:UIControlEventTouchUpInside];
        [scrollView addSubview:infobutton];

        buttonOffset += BUTTON_HEIGHT + BUTTON_SPACING;
    }
}

- (void)infoButtonTouched:sender
{
    int index = [infoButtons indexOfObject:sender];

    NSString *key = [[buttons objectAtIndex:index] titleLabel].text;
    tagField.text = key;

    NSString *value = [tags valueForKey:key];
    queryField.text = value;
}

- (IBAction)addTag:sender
{
    [tagField resignFirstResponder];
    [queryField resignFirstResponder];

    NSString *key = tagField.text;
    NSString *value = queryField.text;

    if (value.length == 0 || key.length == 0) return;

    if ([tags valueForKey:key] == nil)
        [self addNewButtonWithTitle:key];

    [tags setValue:value forKey:key];

    tagField.text = nil;
    queryField.text = nil;

    [tags writeToFile:filePath atomically:NO];
}

- (IBAction)clearTags:sender
{
    [tags removeAllObjects];
    [tags writeToFile:filePath atomically:NO];
    [buttons removeAllObjects];
    [self refreshList];
}

- (void)addNewButtonWithTitle:(NSString *)title
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [button setTitle:title forState:UIControlStateNormal];
    [button
     addTarget:self action:@selector(buttonTouched:)
     forControlEvents:UIControlEventTouchUpInside];
    [buttons addObject:button];

    [buttons sortUsingSelector:@selector(compareButtonTitles:)];
    [self refreshList];

    CGSize contentSize = CGSizeMake(
                                scrollView.frame.size.width,
                                buttons.count * (BUTTON_HEIGHT + BUTTON_SPACING) + BUTTON_SPACING);
    [scrollView setContentSize:contentSize];
}

- (void)buttonTouched:sender
{
    NSString *key = [sender titleLabel].text;
    NSString *search = [[tags valueForKey:key]
                        stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *urlString = [NSString stringWithFormat:
                           @"http://search.twitter.com/search?q=%@", search];
    NSURL *url = [NSURL URLWithString:urlString];
    [[UIApplication sharedApplication] openURL:url];
}
- (void)dealloc
{
    [filePath release];
    [tags release];
    [infoButtons release];
    [buttons release];
    [super dealloc];
}
@end

@implementation UIButton (sorting)
- (NSComparisonResult)compareButtonTitles:(UIButton *)button
{
    return [self.titleLabel.text caseInsensitiveCompare:button.titleLabel.text];
}
@end

Upvotes: 3

Views: 263

Answers (2)

Chuck
Chuck

Reputation: 237110

It sounds like most likely a Controller object is getting deallocated prematurely. It's not possible from the code you've posted to tell where it's happening, but you should be able to track it down with Instruments (zombies and malloc stack logging in particular). Or, if Controller isn't used in a lot of places†, it might be quicker just to look there and see if you're mistakenly autoreleasing it.

†For an object called something like "Controller", I wouldn't bet on it, but it's worth mentioning and being able to easily track the life cycle of objects is a great incentive to reduce coupling in your program designs.

Upvotes: 1

Sulthan
Sulthan

Reputation: 130162

[__NSCFString addTag:]: unrecognized selector sent to instance says thay you are calling method addTag: on an instance of type NSString.

Check to what object and how is your IBAction connected in your xib. If everything is okey, try to clean your project, reset your simulator, and then try it again.

EDIT: please, add a NSLog into your dealloc to check if your controller has not been deallocated.

Upvotes: 2

Related Questions