Reputation: 9351
I am trying to solve a larger problem and I am tipping on the fact that ARC apparently is releasing the view to my NSViewController too early. I think :) So I created a simple app to reconstruct the situation.
I have a simple ARC Cocoa application. In the Window of the MainMenu.xib
I hook up a Custom View
to a @property (strong) IBOutlet NSView *theView;
which is declared in the AppDelegate.h
In the AppDelegate.m
I synthesize the property and then call the following:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
TestViewController *tvc = [[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil];
[_theView addSubview:[tvc view]];
}
The TestViewController
gets displayed in the Custom View
- no problem. It contains one NSButton. It is hooked up to a method called -(IBAction)btnPressed:(id)sender
and one NSTextView which is also hooked up as an IBOutlet
.
In the TestViewController.h
I declare:
@property (nonatomic, strong) IBOutlet NSTextField *textField;
@property (nonatomic, strong) NSString *theString;
-(IBAction)btnPressed:(id)sender;
In the TestViewController.m
I then do
@synthesize theString = _theString;
@synthesize textField = _textField;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Initialization code here.
_theString = @"Hello World";
}
return self;
}
-(IBAction)btnPressed:(id)sender
{
[_textField setStringValue:_theString];
}
When I run the app and press the button it crashes. If I check it for zombies I receive the following:
# Address Category Event Type RefCt Timestamp Size Responsible Library Responsible Caller
0 0x7f97a3047560 TestViewController Malloc 1 00:00.652.631 128 TestARC -[AppDelegate applicationDidFinishLaunching:]
1 0x7f97a3047560 TestViewController Retain 2 00:00.653.088 0 TestARC -[TestViewController initWithNibName:bundle:]
2 0x7f97a3047560 TestViewController Release 1 00:00.653.089 0 TestARC -[TestViewController initWithNibName:bundle:]
3 0x7f97a3047560 TestViewController Retain 2 00:00.653.912 0 AppKit -[NSNib instantiateNibWithOwner:topLevelObjects:]
4 0x7f97a3047560 TestViewController Release 1 00:00.658.831 0 AppKit -[NSNib instantiateNibWithOwner:topLevelObjects:]
5 0x7f97a3047560 TestViewController Release 0 00:00.662.377 0 Foundation -[NSNotificationCenter postNotificationName:object:userInfo:]
6 0x7f97a3047560 TestViewController Zombie -1 00:01.951.377 0 AppKit -[NSApplication sendAction:to:from:]
What am I doing wrong? Thanks
Upvotes: 0
Views: 741
Reputation: 31016
Add a property to hold the view controller. Your controller currently has nothing to keep it alive past the end of the method that allocates it.
Add:
@property (strong) TestViewController *tvc;
Modify:
self.tvc = [[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil];
(I'm curious...what do you see as the point of creating a view controller if all you want is the view it contains?)
Concerning the general approach, it seems that this is more properly behavior that should be implemented using a container view controller. That mechanism allows multiple view controllers to share the screen in an organized way.
Upvotes: 2
Reputation: 49034
You need to add an ivar or property to hold the TextViewController. Currently, the only reference to it is going away at the end of applicationDidFinishLaunching:
which causes it to be deallocated.
That's bad, because your button needs the controller to be around to handle the button press. The view doesn't hold on to it's controller, as that would cause a retain cycle. So you are responsible for keeping the controller around if you don't want your button talking to a deallocated object.
Upvotes: 0