【问题标题】:Help with pointers in Cocoa帮助 Cocoa 中的指针
【发布时间】:2010-06-11 11:47:09
【问题描述】:

我正在尝试用 cocoa 制作一个简单的计算器应用程序。当我单击其中一个按钮时,程序挂起。我想我已经将问题追溯到控制器的一部分,该部分在当前显示的数字末尾添加了一个数字:

- (void)updateNumber:(int)buttonClicked{
 *self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;
 [outputField setFloatValue:*self.activeNumberPointer];
}

我使用了一个指向“activeNumber”的指针,以便让我的程序知道我正在编辑两个操作数中的哪一个。

任何帮助表示赞赏,谢谢。

(编辑):我的声明和@property:

//CalculatorController.h
@interface CalculatorController : NSObject {
    IBOutlet NSTextField *outputField;
    float variable1, variable2;
    float *variable1Pointer, *variable2Pointer;
    float *activeNumberPointer;
}

float variable1 = 0;
float variable2 = 0;
float* variable1Pointer = &variable1;
float* variable2Pointer = &variable2;
float* activeNumberPointer = &variable1;

@property (readwrite) float variable1, variable2;
@property (readwrite) float *vairable1Pointer, *variable2Pointer;
@property (readwrite) float *activeNumberPointer;

...

此处提供完整的 XCode 文件:http://rapidshare.com/files/397664243/Calculator_2.zip (仅供参考:我实际上在项目中使用了 leftNumberValue 和 rightNumberValue 而不是 variable1 和 variable2) 由于我是 Objective-C 和 XCode 的新手,欢迎提出任何一般性批评。

【问题讨论】:

  • 为什么activeNumberPointer是一个指针?
  • 它应该指向用户编辑并显示在ouputField上的variable1。当用户单击加、减、乘或除时,它会将activeNumberPointer 更改为指向variable2。单击等号时,它会对variable1variable2 执行必要的操作。我希望这能澄清我的问题。
  • 如果您添加声明和@property 声明,我们会更轻松。还有,variable1variable2 在哪里,它们是 ivars 吗?
  • “程序挂起”是什么意思?是否崩溃?是否有任何错误输出到控制台?
  • 没有有用的控制台输出。该程序启动正常,但当我单击 10 个数字按钮之一时挂起。它只是以 (gdb) 结尾,然后在 XCode 中的 *self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked; 旁边放一个红色箭头

标签: objective-c cocoa pointers macos


【解决方案1】:

不清楚 Objective-C 中具有简单变量类型的指针,也不完全清楚为什么要使用指针。

*self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;

您在此表达式左侧使用了错误的 * 运算符(取消引用)。在进行分配时,您不想像那样取消引用。

http://www.cplusplus.com/doc/tutorial/pointers/

这是一个 C++ 参考,但对于指针逻辑来说是一个好的开始。

我可能会使用 NSMutableArray 或类似的构造(您想存储的不仅仅是两个数字吗?),并使用整数索引指向您在屏幕上显示的“当前”数字。

另外,我不知道是拼写错误,还是缺少代码等,但是...

@interface CalculatorController : NSObject {
    IBOutlet NSTextField *outputField;
    float variable1, variable2;
    float *variable1Pointer, *variable2Pointer;
    float *activeNumberPointer;
}

float variable1 = 0;
float variable2 = 0;
float* variable1Pointer = &variable1;
float* variable2Pointer = &variable2;
float* activeNumberPointer = &variable1;

...您似乎在接口定义中将上述所有变量声明为 ivars - 或直接附加到 CalculatorController 的实例变量,然后在接口定义之外,您将这些变量重新声明为 GLOBAL 变量。第二组定义无需在您的实现

中使用这些定义

如果您希望初始化这些实例变量,通常有一个名为 -init 的函数可以覆盖(因为您是 NSObject 的子类),它类似于其他语言中的构造函数。这将存在于您的实现文件(.m 或 .mm)中。它可能看起来像这样:

-(CalculatorController *)init{
   if( self = [super init] ){
       // Do your initialization here etc
   }
   return self;
}

还有另一个函数 -awakeFromNib,如果它作为用户界面定义的一部分在 XIB/NIB 文件中实例化,则可以覆盖它。 -awakeFromNib 函数在类和 UI 已加载时被调用。

编辑:要明确指针业务.... self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;

这是对的。您不使用左侧的取消引用运算符,但您要使用右侧的取消引用运算符,因为您正在寻找 self.activeNumberPointer 的值。

乔什

【讨论】:

    【解决方案2】:

    当您使用 self.activeNumberPointer 或 activeNumberPointer 时,您不需要在它们前面加上 *,只需在定义它们时。试试:

    - (void)updateNumber:(int)buttonClicked{
     self.activeNumberPointer = self.activeNumberPointer * 10 + buttonClicked;
     [outputField setFloatValue:activeNumberPointer];
    }
    

    【讨论】:

    • 是的,但我不需要在指针前添加 * 以获得它指向的值吗?
    【解决方案3】:
        float variable1, variable2;
        float *variable1Pointer, *variable2Pointer;
        float *activeNumberPointer;
    }
    
    float variable1 = 0;
    float variable2 = 0;
    float* variable1Pointer = &variable1;
    float* variable2Pointer = &variable2;
    float* activeNumberPointer = &variable1;
    

    您不能在@interface 类中初始化实例变量。您在此处实际所做的是用这些名称中的每一个声明了两个变量。

    对于每个名称,一个变量是实例变量,在紧跟@interface 之后的 {...} 中声明,另一个是全局变量,在标题的其他位置声明。具体来说,您在@interface 中声明了全局变量,但这并不重要:全局变量与任何类或对象都没有关系,您可以将它们放在@interface 之内或之外,编译器不会反对。

    您将全局指针变量初始化为指向全局float 变量,但在@implementation 中的方法主体内,实例变量的排名高于全局变量(实例变量的范围更窄)。此外,属性总是基于实例变量,而不是全局变量。因此,在方法中,您指的是(通过属性)实例变量,而不是您初始化的全局变量。

    实例变量在实例创建时被初始化为nil,所以activeNumberPointer实例变量的值为NULL。因此,像这样的陈述:

    *self.activeNumberPointer = *self.activeNumberPointer * 10 + buttonClicked;
    

    读取和写入空指针。这就是你看到的崩溃。

    还值得指出的是:

    *self.activeNumberPointer = …
    

    不是属性赋值,也就是说它不发送selfsetActiveNumberPointer:消息;它是一个返回指针的属性retrieval(发送getter 消息)。值得削减属性以避免在这里混淆两者。

    崩溃的解决方法是删除全局变量并在代码中初始化你的实例变量。这就是init 方法的用途。在the typical fashion 中覆盖init 并在那里设置您的初始指针值。在整个类中直接访问这些实例变量(无需通过属性)。

    更好的是,完全不用指针杂耍。使用BOOL 变量在它们之间进行选择:

    BOOL editingVariable2;
    

    在需要使用活动变量时测试布尔值。为了避免每次出现需要时都编写麻烦的 if-else 语句,您可以将其封装到一个名为 setValueOfActiveVariable:switchActive: 的方法中,该方法执行第一部分所说的,然后,如果第二部分的参数是 @987654341 @,切换活动变量。

    布尔变量解决方案将完全消除从此类访问未初始化或不再有效的float 指针的风险。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多