50

我确信我在这里的困惑只是因为陷入“Java 思维方式”而不理解 Obj-C 在这种情况下的不同之处。

在 Java 中,我可以像这样在类中声明一个变量,并且该类的每个实例都有自己的:

MyClass {

  String myVar;

  MyClass() {
    // constructor
  }
}

在 Obj-C 中,我尝试通过仅在 .m 文件中声明一个变量来做同样的事情,如下所示:

#import "MyClass.h"

@implementation MyClass

NSString *testVar;

@end

我的期望是这个变量的范围仅限于这个类。所以我创建了第二个类(相同):

#import "MySecondClass.h"

@implementation MySecondClass

NSString *testVar;

@end

我所看到的(让我感到困惑)是在一个类中更改变量会影响在另一个类中看到的值。事实上,如果我设置一个断点,然后“跳转到定义”的变量,它带我去

我创建了一个非常小的 Xcode 项目来演示这里的问题。

4

4 回答 4

139

改变这个:

@implementation MyClass

NSString *testVar;

@end

到:

@implementation MyClass {
    NSString *testVar;
}

// methods go here

@end

你会得到你所期望的。

正如你所拥有的,你实际上是在创建一个全局变量。这两个全局变量被链接器合并为一个,这就是为什么当你设置一个时它们都改变了。花括号中的变量将是一个适当的(和私有的)实例变量。

编辑:在无缘无故被否决之后,我想我会指出“旧”的做事方式和新的方式。

老办法:

一些类.h

@interface SomeClass : UIViewController <UITextFieldDelegate> {
    UITextField *_textField;
    BOOL _someBool;
}

@property (nonatomic, assign) BOOL someBool;

// a few method declarations

@end

SomeClass.m

@implementation SomeClass

@synthesize someBool = _someBool;

// the method implementations

@end

现在使用现代 Objective-C 编译器的新方法和改进方法:

一些类.h

@interface SomeClass : UIViewController

@property (nonatomic, assign) BOOL someBool;

// a few method declarations

@end

SomeClass.m

@interface SomeClass () <UITextFieldDelegate>
@end

@implementation SomeClass {
    UITextField *_textField;
}

// the method implementations

@end

新方式有几个优点。主要优点是关于类的具体实现细节都没有出现在 .h 文件中。客户端不需要知道实现需要什么委托。客户不需要知道我使用什么 ivars。现在,如果实现需要一个新的 ivar 或者它需要使用一个新的协议,那么 .h 文件不会改变。这意味着更少的代码被重新编译。它更清洁,更高效。它也使编辑更容易。当我正在编辑 .m 文件并意识到我需要一个新的 ivar 时,请在我已经在编辑的同一个 .m 文件中进行更改。无需来回交换。

另请注意,实现不再需要 ivar 或@synthesize属性。

于 2012-11-07T04:57:39.863 回答
0

您可能想要的(除非您使用的是非常旧的操作系统和编译器)只是使用属性语法。IE:

@interface MyClass : NSObject

// method declarations here ...

@property (copy) NSString*    myVar;

// ... or here.

@end

这将做你打算做的事情。这将隐式合成一个实例变量和该变量的 getter/setter 对。如果您想要手动创建实例变量(通常不需要,除非您需要您的代码在非常旧的 MacOS 版本上工作),这就是上面的代码在后台创建 ivar 的作用:

@interface MyClass : NSObject
{
    NSString*    _myVar;
}

// method declarations here.

@end

请注意花括号,它告诉编译器这不仅仅是方法之间的全局变量,实际上是属于该对象的实例变量。

如果您创建该属性仅用于内部使用并且不希望您的类的客户端弄乱它,您可以通过使用“继续”类的类扩展将它隐藏在最古老的 ObjC 编译器之外的所有东西中来自标头的声明,但可以与它分开放置(通常在您的实现文件中)。类扩展看起来像一个没有名称的类别:

@interface MyClass ()

@property (copy) NSString*    myVar;

@end

你可以把你的属性声明放在​​那里,或者甚至是 ivar 声明(同样用大括号括起来)。您甚至可以声明与类接口中相同的属性readonly,然后重新声明它相同,但readwrite与扩展中的一样,这样客户端只能读取它,但您的代码可以更改它。

Note that, if you didn't use ARC (that is, you've switched off the default of Automatic Reference Counting), you would have to set all your properties to nil in your dealloc method (unless they're set to weak or assign of course).

NB - All the above are @interface sections. Your actual code will go in separate @implementation sections. This is so you can have header files (.h) you can hand off to your class's clients that just contain the portions you intend them to use, and hide away implementation details in the implementation file (.m) where you can change them without having to worry someone might have accidentally used them and you'll break other code.

PS - 请注意,NSStrings您想要不可变风格但也存在于可变风格(即NSMutableString)中的其他对象应该始终是copy属性,因为这会将 NSMutableString 转换为 NSString ,这样外部的任何人都无法更改可变的你身下的绳子。对于所有其他对象类型,您通常使用strong(或者retain如果不是 ARC)。对于您的班级所有者(例如其代表),您通常使用weak(或者assign如果不是 ARC)。

于 2015-05-09T09:44:22.067 回答
-1

在 Java 中

MyClass {

  String myVar;
  MyClass() {
    // constructor
  }
}

在 Objective-c 中

MyClass.h

@interface MyClass : NSObject{

      NSString* str; // Declaration
}
@end

MyClass.m

@implementation MyClass

  -(void)initializieTheString
  {
     //Defination 
  }

@end
于 2012-11-07T09:11:57.800 回答
-1

在objective-c中,您可以通过这样做将变量定义为私有

MyClass.h

@interface MyClass : NSObject{

      NSString* _myTestVar; // Declaration
}
@end

并通过像这样 MyClass.m 在实现类中引用它

#import "MyClass.h";

@implementation MyClass

  -(void)initializieTheString
  {
     _myTestVar= @"foo"; //Initialization

  }

@end
于 2015-05-09T08:18:06.407 回答