【问题标题】:Instance variables lose value after initWithNib and before IBAction in NSViewController实例变量在 initWithNib 之后和 NSViewController 中的 IBAction 之前失去价值
【发布时间】:2011-12-21 13:51:18
【问题描述】:

我正在编写的 OS X 应用程序有一个非常基本的初始化问题。我在我的 NSViewController 的 initWithNibName 中初始化实例变量。但是,当我在 IBAction 方法中访问它们时,这些变量失去了它们的值并最终等于 nil。

这是我的代码。我有一个具有 1 个主窗口和 1 个 NSViewController 的应用程序。应用程序委托在 applicationDidFinishLoading 中以编程方式调用 initWithNibName。出现视图,视图中的按钮成功调用onButtonClick。但是,在该方法中,myString 的值为 null。日志清楚地显示它在 initWithNibName 方法期间成功初始化。所以它在 initWithNibName 和按钮点击之间失去了它的价值。

//MyAppDelegate.m
@implementation MyAppDelegate

@synthesize window; 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    MainView* mainViewController = [[MainView alloc] initWithNibName:@"MainView" bundle:[NSBundle mainBundle]];
    [mainViewController loadView];
NSView *controllerView = [mainViewController view];
    [window setContentView:controllerView];
}

@end

//MainView.h
@interface MainView : NSViewController {
    NSButton *myButton;
    NSString* myString;
}

@property (assign) IBOutlet NSButton *myButton;
@property (assign) NSString* myString;

- (IBAction)onMyButtonClick:(id)sender;

@end

//MainView.m
@implementation MainView

@synthesize myButton;
@synthesize myString;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    NSLog(@"initWithNibName");
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialization code here.
        NSLog(@"Initializing...");
        [self setMyString:@"try to set the variable"];
        NSLog(@"String is %@", myString);
    }

    return self;
}

- (void)awakeFromNib {
    NSLog(@"awakeFromNib");
    //[self setMyString:@"init in here works, but is called too many times"];
}

- (IBAction)onMyButtonClick:(id)sender{
    NSLog(@"Button clicked");
    NSLog(@"%@", myString);  //Always nil when initialized in initWithNibName()!!
}

@end


//Logs

initWithNibName
Initializing...
String is try to set the variable
awakeFromNib
awakeFromNib
Button clicked
(null)

如何让 myString 保留其价值?

我已经尝试了我能想到的所有类型的属性声明。我还尝试了各种赋值方法([self setMyString]、self.myString = @"blah"、myString = [NSString stringWithFormat:@"blah"] 等)。

我已经读到我应该在 awakeFromNib() 中进行初始化。这确实有效。但是,我最终的初始化代码将包含一系列 [[MyObj alloc] init] 调用,当它们被多次调用时,会产生多个指针,这很疯狂。我的最终目标是拥有一个指向对象的指针,控制器始终可以引用该对象并始终获得相同的数据。对象由控制器初始化,控制器保存引用并在用户与控制器交互时根据需要更新它。

那么有没有办法在 NSViewControllers 中初始化实例变量,只初始化一次,并让它们在控制器的生命周期内保持它们的值?

谢谢

凯夫

【问题讨论】:

  • 我已将您的代码复制到一个测试项目中,它工作正常。您的设置有误,可能是在 NIB 中。尝试创建一个新项目并使用 Xcode 自动生成的现有 MainView.xib。
  • 有什么方法可以将您的测试项目的 zip 文件发送给我,以便我比较两者吗?谢谢。
  • 谢谢!谢谢!谢谢!我弄清楚我做错了什么。我正在向代表视图控制器的每个笔尖添加一个视图控制器。然后我将按钮点击附加到那个单独的视图控制器对象。您的项目向我展示了我应该将按钮单击附加到文件所有者,然后将文件所有者设置为视图控制器。当您可以只使用文件所有者作为占位符时,基本上不需要将第二个视图控制器导入笔尖。再次感谢!

标签: objective-c xcode macos cocoa nsviewcontroller


【解决方案1】:

您应该将属性声明为(复制)而不是(分配)

【讨论】:

  • 分配和复制是互斥的。你不能两者兼得。
【解决方案2】:

您是否尝试将它们声明为(非原子,保留)?

【讨论】:

  • 你永远不应该将 NSString 属性声明为 (retain)。如果你将一个 NSMutableString 分配给一个保留的 NSString 属性,有一天它会以泪水告终。 NSArray、NSData 等也是如此。
  • 我只是尝试将属性声明为“复制”和“保留”,但都不起作用。然而,我发现了一些新的东西。我添加了一些 NSLog 语句来打印出 self 的内存地址和 self.myString。我将这些 NSLog 语句添加到每个 initWithNib、awakeFromNib 和 onMyButtonClick。事实证明,在 awakeFromNib 和 onMyButtonClick 中 self 的地址是匹配的。但是那个地址和initWithNib中self的地址不同。很明显,init 初始化了一个与 awakeFromNib 不同的对象。知道为什么吗?
【解决方案3】:

请允许我回答这个问题,因为正确答案隐藏在我问题的 cmets 中。

我发现我做错了什么。我正在向代表视图控制器的每个 nib 添加一个视图控制器。然后我将按钮点击附加到那个单独的视图控制器对象。 @Francis-McGrew 附加了一个项目,显示我应该将按钮单击附加到文件所有者,然后将文件所有者设置为视图控制器。当您可以使用文件所有者作为占位符时,基本上不需要将第二个视图控制器导入到 nib 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 2011-03-14
    • 1970-01-01
    • 2013-11-17
    相关资源
    最近更新 更多