Objective C实例variables
好的 – 所以我确信我的困惑只是被卡在“Java心态”中,而不了解Obj C在这种情况下的不同之处。
在Java中,我可以像这样在类中声明一个variables,并且该类的每个实例都有自己的variables:
MyClass { String myVar; MyClass() { // constructor } }
在Obj中,CI试图通过只在.m文件中声明一个variables来做同样的事情:
#import "MyClass.h" @implementation MyClass NSString *testVar; @end
我的期望是这个variables的范围仅限于这个类。 所以我创build了第二个类(相同):
#import "MySecondClass.h" @implementation MySecondClass NSString *testVar; @end
我所看到的(让我感到困惑的是)改变一个class级的variables,影响另一class级的价值。 事实上,如果我设置了一个断点,然后“跳到定义”的variables,它需要我
我创build了一个非常小的XCode项目来演示这个问题
没有什么比移动到一种新的语言更谦虚:)
提前致谢。
改变这个:
@implementation MyClass NSString *testVar; @end
至:
@implementation MyClass { NSString *testVar; } // methods go here @end
你会得到你所期望的。
就像你一样,你实际上正在创build一个全局variables。 这两个全局variables被链接器合并成一个,这就是为什么当你设置一个variables的时候它们都会改变。 花括号中的variables将是一个适当的(和私有的)实例variables。
编辑:在没有明显原因被低估之后,我想我会指出做事的方式和方式。
旧的方式:
SomeClass.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编译器的新的改进方法:
SomeClass.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文件不会更改。 这意味着更less的代码被重新编译。 它更干净,更高效。 这也使编辑更容易。 当我编辑.m文件并意识到我需要一个新的ivar时,请在我正在编辑的.m文件中进行更改。 不需要来回交换。
另请注意,实现不再需要ivar或@synthesize
作为属性。
在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
在Objective-C中,通过这样做来将variables定义为私有
MyClass.h @interface MyClass : NSObject{ NSString* _myTestVar; // Declaration } @end
并通过像MyClass.m那样在实现类中引用它
#import "MyClass.h"; @implementation MyClass -(void)initializieTheString { _myTestVar= @"foo"; //Initialization } @end
你可能想要的(除非你使用的是一个非常老的操作系统和编译器)只是使用属性语法。 即:
@interface MyClass : NSObject // method declarations here ... @property (copy) NSString* myVar; // ... or here. @end
这将做你想做的事情。 这将隐式地为这个variables合成一个实例variables和一个getter / setter对。 如果你手动创build实例variables(除非你需要你的代码来处理非常旧的MacOS版本,那么你通常不需要这个variables),这就是上面的代码在创buildivar时所做的:
@interface MyClass : NSObject { NSString* _myVar; } // method declarations here. @end
注意花括号,它告诉编译器,这不仅仅是方法之间的全局variables,而且实际上是一个属于这个对象的实例variables。
如果你只是为了内部使用而创build这个属性,并且不希望你的类的客户弄乱它,那么你可以通过使用一个类inheritance来“隐藏”这个类来隐藏它,而不是最老的ObjC编译器声明来自头文件,但可以独立于它(通常在你的实现文件中)。 类扩展看起来像一个没有名字的类:
@interface MyClass () @property (copy) NSString* myVar; @end
你可以把你的财产声明在那里,甚至是伊娃的声明(再次用大括号括起来)。 您甚至可以在类接口中声明相同的属性为readonly
属性,然后将其重新声明为相同的,但在扩展名中为readwrite
,以便客户端只读取它,但是您的代码可以更改它。
请注意,如果你没有使用ARC(也就是说,你已经closures了自动引用计数的默认设置),你必须在你的dealloc
方法中将所有属性设置nil
(除非它们被设置为weak
或者当然assign
)。
注意 – 以上都是@interface
部分。 你的实际代码将在单独的@implementation
部分。 这样,您可以将头文件( .h
)交给您的课程客户端,它们只包含您打算使用的部分,并将实现细节隐藏在实现文件( .m
)中,您可以在其中无需更改不必担心有人可能意外地使用了它们,并且会破坏其他代码。
PS – 请注意NSStrings
和其他对象,你想不可变的味道,但也存在一个可变的味道(即NSMutableString
)应该永远是copy
属性,因为这将把一个NSMutableString变成一个NSString,使外部没有人可以改变你下面的可变string。 对于所有其他对象types,通常使用strong
types(或者retain
如果不是ARC)。 对于你的class级的所有者(例如它的代表),你通常使用weak
(或者如果不是ARC,则assign
)。