NSMutableArray adding item doesn't work

Discussion in 'Mac Programming' started by Samppaa, Jun 8, 2010.

  1. Samppaa macrumors regular

    Joined:
    Mar 26, 2010
    #1
    Hey guys I am doing a challenge in cocoa programming for os x third edition and when I am trying to add item to the array it won't show on the tableview, I know that tableview works properly as I tried to init it with speech synthentisator names and they showed, but somehow the items I try to add don't show, here is the code:

    TableController.h
    Code:
    //
    //  TableController.h
    //  Challenge3
    //
    //  Created by Samuli Lehtonen on 8.6.2010.
    //  Copyright 2010 Test. All rights reserved.
    //
    
    #import <Cocoa/Cocoa.h>
    
    
    @interface TableController : NSObject {
    	NSMutableArray *items;
    	IBOutlet NSTextField * itemField;
    	IBOutlet NSTableView * tableView;
    
    }
    
    -(IBAction)addNewItem:(id)sender;
    
    @end
    
    TableController.m
    Code:
    //
    //  TableController.m
    //  Challenge3
    //
    //  Created by Samuli Lehtonen on 8.6.2010.
    //  Copyright 2010 Test. All rights reserved.
    //
    
    #import "TableController.h"
    
    
    @implementation TableController
    
    -(int)numberOfRowsInTableView:(NSTableView *)tv
    {
    	return [items count];
    }
    
    -(id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
    {
    	NSString *v = [items objectAtIndex:row];
    	return v;
    }
    
    -(id)init
    {
    	[super init];
    	NSLog(@"Init called!");
    	return self;
    }
    
    -(IBAction)addNewItem:(id)sender
    {
    	NSLog(@"Additem called");
    	[items addObject:[itemField stringValue]];
    	
    }
    
    @end
    
     
  2. ChOas macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #2
    Tell the tableview its content changed:

    Code:
    -(IBAction)addNewItem:(id)sender
    {
    	NSLog(@"Additem called");
    	[items addObject:[itemField stringValue]];
    	[self.tableView reloadData];
    }
    
     
  3. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #3
    In addition to the above: where do you actually create an instance of NSMutableArray and assign it to items? Clearly it's not in the code you posted...
     
  4. Samppaa thread starter macrumors regular

    Joined:
    Mar 26, 2010
  5. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #5
    See my post above. Declaring items in the .h file just says you want space in memory for a pointer to a NSMutableArray. You have to actually create that instance somewhere.
     
  6. sanPietro98 macrumors 6502a

    sanPietro98

    Joined:
    May 30, 2008
    Location:
    28.416834,-81.581214
    #6
    You'll probably want to put the allocation in your viewDidLoad method.
     
  7. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #7
    As people are saying above, declaring a NSMutableArray in your @interface section is not enough.

    When you TableController object is created (presumably through -init) you basically have a hidden line of code that looks like
    items = nil;

    Thus when you're "adding" an object to this array, there is no array there and because ObjC doesn't give any errors when sending a message to nil, nothing happens.

    In -init you need to create and assign an instance of NSMutableArray.
     
  8. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #8
    If only. items is not (I don't think) secretly initialised to nil. It will have whatever value was in that area of memory. This is way worse than nil...
     
  9. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #9
    Untrue. alloc guarantees that all instance variables are zeroed.
     
  10. BadWolf13 macrumors 6502

    Joined:
    Dec 17, 2009
    #10
    Yeah, as with the others, it's probably your lack of initializing the array. Try adding;

    Code:
    items = [[NSMutableArray alloc] init];
    into the init method for tableController. That should do it.
     
  11. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #11
    Ah, interesting. As a declared pointer in C is not guaranteed in a similar way.
     
  12. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #12
    C doesn't have instance variables. C++ does, and you're right on that point: no guaranteed initial value.

    C does have static and local (automatic) variables. Static are guaranteed to be zero unless initialized otherwise. Local are not. Also true for Objective-C.

    Allocated memory from malloc: no guarantee. Allocated memory from calloc: guaranteed zeros. True for C and Objective-C.
     
  13. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #13
    Otherwise it would be very very likely to crash when trying to add an object.
     
  14. Samppaa thread starter macrumors regular

    Joined:
    Mar 26, 2010
  15. PatrickCocoa macrumors 6502a

    Joined:
    Dec 2, 2008
    #15
    I agree with you, I remember the Apple guy lecturing on the Stanford iTunes U CS193p course mentioning this.

    But I would be leery of relying on this, since it's not prominently mentioned in the documentation and Apple could change it at any time. Maybe Xcode 4 does this, maybe it doesn't. Or maybe I'm paranoid.
     
  16. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #16
    It's a widely-known and well-documented feature. There's no possible way Apple could change this now. There's way too much existing code that relies on this. It would all break.

    I don't know how prominently mentioned you think it needs to be. It's a very simple concept, so it doesn't need a lot of discussion in the docs.

    From the reference doc on +alloc in NSObject reference (emphasis added):
    The isa instance variable of the new instance is initialized to a data structure that describes the class; memory for all other instance variables is set to 0. The new instance is allocated from the default zone—use allocWithZone: to specify a particular zone.
    http://developer.apple.com/mac/libr...rence.html#//apple_ref/occ/clm/NSObject/alloc
    The same wording appears for +allocForZone:.
     
  17. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #17
    You 100% CAN rely on this. And this is documented, even if you have to read between the lines.

    Lets take a look at a method for accessing a NSPersistentStoreCoordinator that is auto generated in the template for CoreData applications.

    Code:
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    	
        if (persistentStoreCoordinator != nil) {
            return persistentStoreCoordinator;
        }
    	
        NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"SuperDB.sqlite"]];
    	
    	NSError *error = nil;
        persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
        if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
    		NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    		abort();
        }    
    	
        return persistentStoreCoordinator;
    }
    
    This relies on the ivar persistentStoreCoordinator == nil when the object is created. This is called "lazy loading", and is a technique throughout Apple's, and my own, codebase.
     
  18. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #18
    Really, why would Apple not use calloc()? If they do use calloc() to create memory blocks for NSObject-based classes, why would one not be able to rely on zeroed initialization? The reason local variables have unknown initial values is because they live on the stack, which is a heavily used, constantly changing memory region.
     

Share This Page