Objective-C实例变量?
我敢肯定,我在这里的困惑只是因为我被困在“Java思维模式”中,不理解Obj-C在这种情况下的区别 在Java中,我可以像这样在类中声明一个变量,该类的每个实例都有自己的变量:Objective-C实例变量?,objective-c,Objective C,我敢肯定,我在这里的困惑只是因为我被困在“Java思维模式”中,不理解Obj-C在这种情况下的区别 在Java中,我可以像这样在类中声明一个变量,该类的每个实例都有自己的变量: MyClass { String myVar; MyClass() { // constructor } } 在Obj-C中,我尝试通过仅在.m文件中声明一个变量来执行相同的操作,如下所示: #import "MyClass.h" @implementation MyClass NSStri
MyClass {
String myVar;
MyClass() {
// constructor
}
}
在Obj-C中,我尝试通过仅在.m文件中声明一个变量来执行相同的操作,如下所示:
#import "MyClass.h"
@implementation MyClass
NSString *testVar;
@end
我在这里的期望是这个变量的作用域仅限于这个类。因此,我创建了第二个类(相同):
我所看到的(让我困惑的)是,在一个类中更改变量会影响在另一个类中看到的值。事实上,如果我设置了一个断点,然后“跳转到变量的定义”,它会将我带到
我创建了一个非常小的Xcode项目来演示这个问题。更改此项:
@implementation MyClass
NSString *testVar;
@end
致:
你会得到你所期望的
正如您所看到的,您实际上正在创建一个全局变量。链接器将这两个全局变量合并为一个,这就是为什么在设置一个全局变量时两者都会发生变化的原因。大括号中的变量将是适当的(私有)实例变量
编辑:在无缘无故被否决后,我想我应该指出“旧”的做事方式和新的做事方式
老办法:
某个班级
@interface SomeClass : UIViewController <UITextFieldDelegate> {
UITextField *_textField;
BOOL _someBool;
}
@property (nonatomic, assign) BOOL someBool;
// a few method declarations
@end
@interface SomeClass : UIViewController
@property (nonatomic, assign) BOOL someBool;
// a few method declarations
@end
现在,现代Objective-C编译器采用了新的改进方式:
某个班级
@interface SomeClass : UIViewController <UITextFieldDelegate> {
UITextField *_textField;
BOOL _someBool;
}
@property (nonatomic, assign) BOOL someBool;
// a few method declarations
@end
@interface SomeClass : UIViewController
@property (nonatomic, assign) BOOL someBool;
// a few method declarations
@end
某个班级
@implementation SomeClass
@synthesize someBool = _someBool;
// the method implementations
@end
@interface SomeClass () <UITextFieldDelegate>
@end
@implementation SomeClass {
UITextField *_textField;
}
// the method implementations
@end
@接口SomeClass()
@结束
@类的实现{
UITextField*_textField;
}
//方法实现
@结束
这种新方法有几个优点。主要的优点是,在.h文件中没有显示有关该类的任何特定于实现的详细信息。客户机不需要知道实现需要什么委托。客户不需要知道我使用什么IVAR。现在,如果实现需要新的ivar或者需要使用新的协议,那么.h文件不会更改。这意味着重新编译的代码更少。它更干净,效率更高。它还使编辑更容易。当我编辑.m文件并意识到我需要一个新的ivar时,在我已经编辑的同一个.m文件中进行更改。不需要来回交换
还要注意,实现不再需要属性的ivar或@synthesis
。在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中,您可以这样将变量定义为private
MyClass.h
@interface MyClass : NSObject{
NSString* _myTestVar; // Declaration
}
@end
并通过这样做在实现类中引用它
我的班级
#import "MyClass.h";
@implementation MyClass
-(void)initializieTheString
{
_myTestVar= @"foo"; //Initialization
}
@end
您可能想要的(除非您使用的是非常旧的操作系统和编译器)是只使用属性语法。即:
@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
相同的属性,以便客户端仅读取该属性,但您的代码可以对其进行更改
请注意,如果您没有使用ARC(也就是说,您已经关闭了自动引用计数的默认设置),那么您必须在dealloc
方法中将所有属性设置为nil
(当然,除非它们设置为weak
或assign
)
注意-以上都是@接口
部分。您的实际代码将放在单独的@实现
部分。这样您就可以有头文件(.h
)您可以将只包含您希望它们使用的部分的内容传递给类的客户机,并将实现细节隐藏在实现文件(.m
)中,在那里您可以更改它们,而不必担心有人可能意外使用了它们,并且您会破坏其他代码
PS-请注意,
NSStrings
和其他您想要不可变风格的对象,但也存在于可变风格中(即NSMutableString
)应该始终是copy
属性,因为这会将NSMutableString转换为NSString,这样外部的任何人都不能更改您下面的可变字符串。对于所有其他对象类型,您通常使用strong
(或者retain
如果不是ARC)。对于类的所有者(例如其委托)通常使用弱
(或分配
,如果不是ARC).Objective-C更像C/C++而不是Java。Java相对独特,它没有单独的声明和实现文件,而是将所有内容放在一个文件中。在Objective-C中,您在.h文件的@interface部分声明实例字段。我猜这是因为您没有描述@interface/@im的规范形式实施。你展示的内容在技术上是允许的,但几乎从未被使用过,可能会让新手产生灾难性的困惑。@HotLicks我展示的是新的首选方法。没有理由再在.h文件中放置私有IVAR。现代LLVM编译器不允许。初学者应该学习新方法,而不是旧方法。@HotLicks我编辑了我的ans回答