PDA

View Full Version : Objective-C help with NSMutableArray




dancks
Apr 15, 2013, 01:41 PM
I am learning cocoa from 4th ed Cocoa Programming for Mac OS X. I am doing an where I make a simple gui that reads in user text and add it to a list: I'm using a NSTextField and NSTableView respectively. The problem is it crashes randomly, I cant get anything to show up in NSMutableArray so I guess I have a memory leak somewhere. I was confused if NSMutableArray stored objects by copying or by reference:

GUI:

407923

appdelegate.h:

#import <Cocoa/Cocoa.h>
#import "NewTable.h"

@interface AppDelegate : NSObject <NSApplicationDelegate,NSTableViewDelegate>
{
NSInteger at;
int count;
NSMutableArray *list;
}

@property (assign) IBOutlet NSWindow *window;

@property (assign) IBOutlet NSTextField *input;
@property (assign) IBOutlet NSButton *add;
@property (assign) IBOutlet NSButton *remove;
@property (assign) IBOutlet NSTableView *table;

-(IBAction)addToList:(id)sender;
-(IBAction)removeFromList:(id)sender;
-(IBAction)checkList:(id)sender;

@end


appdelegate.m (GUI controller):

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize add;
@synthesize remove;
@synthesize input;
@synthesize table = _table;

- (void)dealloc
{
[list release];
[super dealloc];
}
-(id)init
{
[super init];
at=0;
count=1;
list = [[NSMutableArray alloc] init];
NSString *var = @"Type something";
[list addObject:var];
return self;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}


-(void)tableView:(NSTableView *)aTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{

}
- (int)numberOfRowsInTableView:(NSTableView *)tableView
{
NSLog(@"numberOfRowsInTableView called");
return count;
}
- (id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(int)row
{
NSLog(@"objectValueForTableColumn called");
at = [_table clickedRow];
if((int)at > count) at = (NSInteger) count;
else if(at<0) at = 0;
if(!count || (row>count))
{
return @"";
}
else
{
return [list objectAtIndex:row];
}
}



-(void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row = [_table selectedRow];
if(row==-1)
{
return;
}
else
{
at = row;
}
}

-(IBAction)addToList:(id)sender
{
NSLog(@"addToList click registered, at=%ld, count=%i",at,count);
[list insertObject:[NSString stringWithString:[input stringValue]] atIndex:at];
count++;
}
-(IBAction)removeFromList:(id)sender
{
NSLog(@"removeFromList click registered at=%ld, count=%i",at,count);
if(at<count)
{
NSString *var = [list objectAtIndex:at];
[list removeObjectAtIndex:at];
[var release];
count--;
}
}

-(IBAction)checkList:(id)sender
{
NSString *the_list = [[NSString alloc] initWithString:@"List: "];
for (NSString *var in list)
{
[the_list stringByAppendingFormat:@"%@, %@",the_list,var];
}
NSLog(the_list);
[the_list release];
}

-(void)awakeFromNib
{
NSIndexSet *indices = [NSIndexSet indexSetWithIndex:1];
[_table selectRowIndexes:indices byExtendingSelection:NO];
[_table scrollRowToVisible:1];
at = count;
}
@end



fluxforge
Apr 15, 2013, 02:53 PM
I was confused if NSMutableArray stored objects by copying or by reference

It stores the reference and retains it.

Oh, and about your code: Don't call directly -dealloc on objects. It's not intended to be called from the outside and will lead to undefined behaviour. Dealloc will be called automatically when the object gets destroyed. (The exception is the [super dealloc] call which is ok.)

If you're working without ARC you should call -release where you put your dealloc calls in the example. With ARC everything is taken care for you by the runtime.

ArtOfWarfare
Apr 15, 2013, 03:45 PM
Click on the breakpoints tab of Xcode and turn on Exception breakpoints. That'll help you identify the line that's crashing your application.

dancks
Apr 15, 2013, 03:46 PM
It stores the reference and retains it.

Oh, and about your code: Don't call directly -dealloc on objects. It's not intended to be called from the outside and will lead to undefined behaviour. Dealloc will be called automatically when the object gets destroyed. (The exception is the [super dealloc] call which is ok.)

If you're working without ARC you should call -release where you put your dealloc calls in the example. With ARC everything is taken care for you by the runtime.

That is what I figured, so I make NSString pointers, pass them in, and let the variables fall out of scope without worry of a memory leak, and simply release when I need them gone. But with all that why is NSMutableArray losing scope of the strings and causing segfaults? I thought the above code was correct (other than the dealloc/release thing)

dancks
Apr 15, 2013, 04:25 PM
Click on the breakpoints tab of Xcode and turn on Exception breakpoints. That'll help you identify the line that's crashing your application.

It automatically compiles with the GDB flag so XCode knows which line it crashed on. Last time it ran (It crashes in different places) I crashed on for(NSString *var in list) and here:[list insertObject:[NSString stringWithString:[input stringValue]] atIndex:at];Which would make sense if its pointing to bad memory.