Reputation: 13
I have an NSViewController subclass with:
@property (retain) NSMutableArray* entities;
@property (retain) NSMutableArray* tiles;
In my -init
method, both arrays are created with +new
, and are given one object each. After that, I call NSLog(@"%@, %@", entities, tiles);
, and it gives me just as expected:
2012-12-30 15:07:04.160 Project Land III[2177:303] (
"<RBEntity: 0x100508170>"
), (
"<RBTile: 0x100508470>"
)
I can click a button on the view, though, which calls the same log function, and it spit out this:
2012-12-30 15:07:06.071 Project Land III[2177:303] (null), (null)
I've been stuck on this problem in some form or another for days. Why in the world are the arrays null?
I'm more than happy to post more code, just let me know!
Interface:
#import <Cocoa/Cocoa.h>
#import "RBEntity.h"
#import "RBTile.h"
@interface RBMainViewController : NSViewController {
NSMutableArray* _entities;
NSMutableArray* _tiles;
}
@property (retain) NSMutableArray* entities;
@property (retain) NSMutableArray* tiles;
- (IBAction)log:(id)sender;
@end
My -init
method:
- (id)init {
self = [super init];
self.entities = [NSMutableArray new];
self.tiles = [NSMutableArray new];
[self.entities addObject:[RBEntity entityWithLocation:NSMakePoint(4, 5) type:FACEEATER]];
[self.tiles addObject:[RBTile tileWithLocation:NSMakePoint(10, 2) type:GRASS]];
NSLog(@"%@, %@", self.entities, self.tiles);
return self;
}
Upvotes: 1
Views: 152
Reputation: 96373
In my
-init
method, both arrays are created with+new
, and are given one object each. After that, I callNSLog(@"%@, %@", entities, tiles);
, and it gives me just as expected:2012-12-30 15:07:04.160 Project Land III[2177:303] ( "<RBEntity: 0x100508170>" ), ( "<RBTile: 0x100508470>" )
I can click a button on the view, though, which calls the same log function, and it spit out this:
2012-12-30 15:07:06.071 Project Land III[2177:303] (null), (null)
This is a very common novice mistake.
You have two RBMainViewController objects. One of them, you presumably created in code in one of your other .m files, by saying something like [[RBMainViewController alloc] init]
. The other, you created in a nib, probably by dragging it into the nib.
(Note: The nib that you created that VC in is not the VC's nib. That would be circular, to have the VC's nib containing the VC that is loading the nib. The VC that doesn't have its arrays resides in nib A, and each VC will load nib B.)
The VC that you created in a nib is the one whose view appears on the screen. Because that object never received an init
message (it was initialized with some other initWith…
message instead), you never created its arrays. The view controller you created with init
, which does have its arrays, is not visible on the screen (otherwise you would have clicked on its button, rather than the other's, and you'd have seen the arrays in the output).
The solution involves two changes.
The first is to change your implementation of init
to be an implementation of initWithNibName:bundle:
instead. Like so:
- (instancetype) initWithNibName:(NSString *)nibName
bundle:(NSBundle *)bundle
{
self = [super initWithNibName:nibName bundle:bundle];
if (self != nil) {
<#...#>
}
return self;
}
If you want to continue using init
to create your VC in other code, fine, but your implementation of -[RBMainViewController init]
should simply send initWithNibName:bundle:
to self
and return the result.
- (instancetype) init {
return [self initWithNibName:<#nibName#> bundle:<#bundle#>];
}
You also need to delete one of the two view controllers. We'd need to see the code and the nib to know which. If you delete the one you created in code, you may want to create an outlet in that class and connect it in the nib. If you delete the one in the nib, any outlet connections you established in that nib to that VC, you'll need to re-create in code.
Upvotes: 1
Reputation: 2987
I believe you will need to use self.entites
and self.tiles
when working with those objects in your class.
EDIT (after interface added)
You will need to have something in your interface like:
@interface RBMainViewController : NSViewController{
NSMutableArray* _entities;
NSMutableArray* _tiles;
}
@property (retain) NSMutableArray* entities;
@property (retain) NSMutableArray* tiles;
- (IBAction)log:(id)sender;
@end
Then you will need to add this to the implementation:
@synthesize entities = _entities;
@synthesize tiles = _tiles;
Upvotes: 0
Reputation: 32260
Write a custom getter/setter for one of these properties, and put a breakpoint there to see who's resetting the value. If that doesn't catch the problem, and your property is still being reset, you're probably accessing them from an instance of your NSViewController
that hasn't been initialised by your init
, thus those properties were always uninitialised.
Upvotes: 0