在 Interface Builder 中实例化同一类的多个对象会导致共享属性

Posted

技术标签:

【中文标题】在 Interface Builder 中实例化同一类的多个对象会导致共享属性【英文标题】:Instantiating multiple objects of the same class in Interface Builder results in shared property 【发布时间】:2014-03-17 12:59:30 【问题描述】:

我正在尝试在我的 OSX 程序中使用 NSPopUpButtons。为了将 KVO 用于其字符串和索引,我编写了一个自定义类(DLPopUpButtonManager)。

@interface DLPopUpButtonManager : NSObject

  @property NSArray  *contentArray;
  @property NSString *selectionString;
  @property NSNumber *selectionIndex;

@end

当在程序中只使用一次时,该类工作正常。但… 当我使用多个实例时,它们的 contentArray 是共享的,这意味着两个 contentArray 指向同一个实例。啊??这完全让我感到困惑。 (封装等)

我有两个 NSPopUpButton,每个都连接到 DLPopUpButtonManager 类的对象。这两个类通过两个对象在 Interface Builder 中实例化。然后在我的 AppDelegate 中初始化它们。

@interface AppDelegate : NSObject <NSApplicationDelegate>

  @property (weak) IBOutlet DLPopUpButtonManager *pUBM_1;
  @property (weak) IBOutlet DLPopUpButtonManager *pUBM_2;


@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
    [self.pUBM_1 setContentArray:[NSArray arrayWithObjects:@"Female", @"Male", nil]];
    [self.pUBM_2 setContentArray:[NSArray arrayWithObjects:@"Tall", @"Short", nil]];
    [self showDetails:nil];

我发现两个实例(令人困惑和不需要)使用相同的 contentArray。

我使用断点进行了调查,发现我确实有两个单独的 DLPopUpButtonManager 实例,但它们的 contentArrays 具有相同的指针值。

Printing description of $20: <DLPopUpButtonManager: 0x6080000100b0>
Printing description of $23: <DLPopUpButtonManager: 0x6080000100c0>
Printing description of $25: <__NSArrayI 0x600000223ba0>
(
Tall,
Short
)
Printing description of $24: <__NSArrayI 0x600000223ba0>
(
Tall,
Short
)
(lldb)

我无法通过 Google 或在 SO 上找到类似的内容。谁能告诉我,我在这里做错了什么? 我上传了一个小示例程序到 GitHub (https://github.com/donnerluetjen/PopUpButtonEtude)。

感谢您对此问题的任何意见。

【问题讨论】:

显而易见的问题,但是,您没有为两者分配相同的数组是吗? (我没有看过示例项目)。 @JoeFryer:我添加了更多细节。我用两个不同的数组初始化它们。 【参考方案1】:

尝试将您的数组和选择索引属性的基础 ivars 移动到 .m 文件中的私有扩展名中,以确保它们实际上不是静态变量。

@interface DLPopUpButtonManager ()
NSArray    *_contentArray;
NSUInteger _selectionIndex;

【讨论】:

谢谢 tjboneman。我不知道。我会读一遍关于实例变量和静态的声明。 我在这里找到了更多信息:在 Apple 的文档中,The Objective-C Language | Defining a Class。实际上,我更喜欢在实现文件中声明实例变量。一旦我可以自己发布答案,我会发布更多内容。【参考方案2】:

感谢 tjboneman,我可以解决我的问题,并且我阅读了更多关于实例变量和静态实例变量的信息。这是我经过认真搜索后发现的:

来自 Apple 的文档,The Objective-C Language | Defining a Class:

类接口

...

注意:从历史上看,接口需要声明类的实例变量,即属于类的每个实例的数据结构。这些是在@interface 声明之后和方法声明之前用大括号声明的:

@interface ClassName : ItsSuperclass

    // Instance variable declarations.

// Method and property declarations.
@end

实例变量代表一个实现细节,通常不应在类本身之外访问。此外,您可以在实现块中声明它们或使用声明的属性合成它们。因此,通常不应在公共接口中声明实例变量,因此应省略大括号。

...

类实现

类的定义与它的声明非常相似。它以@implementation 指令开始,以@end 指令结束。此外,该类可以在@implementation 指令之后用大括号声明实例变量:

@implementation ClassName

    // Instance variable declarations.

// Method definitions.
@end

再次感谢 tjboneman 为我指明了正确的方向。

【讨论】:

以上是关于在 Interface Builder 中实例化同一类的多个对象会导致共享属性的主要内容,如果未能解决你的问题,请参考以下文章

在 Interface Builder 中嵌套 XIB/通过引用嵌入

Interface Builder 和 Cocoa:在 App Controller 类后面连接

不使用 Interface Builder 将 NIB 转换为 XIB

在 Interface Builder 中设置 Nib Name 字段时出现异常

Xcode 的 Interface Builder 中的外部对象占位符丢失

在 Interface Builder 中连接元素