我一直在学习Objective-C。根据我的学习,我知道当你在 .h文件中的@interface
内声明一个变量时,可以公开访问该变量(类似于java中的公共变量)。
@interface MyObject
@property NSInteger intData;
@end
但是当您在 .m文件中的@interface
内声明它时。它只能在@implementation下的.m文件中访问,除非你为它提供了一个getter和setter。
@interface MyObject ()
@property NSInteger intData;
@end
但我也注意到另一种声明变量的方法,即在@implementation
@implementation
NSInteger intData;
@end
我发现它的工作原理与在{。1}中使用@interface
在.m文件中声明
我不明白两者之间的区别(在@implementation和@interface下声明(在 .m文件中)。
我已经在堆栈中搜索了这个,但他们都在谈论@implementation和@interface之间的区别(在 .h文件中)。所以认为这不是重复。
答案 0 :(得分:6)
首先,您不会声明变量;你在宣布一项财产。属性由实例变量支持,但它也添加了方法。这是对变量放置位置的解释:
@interface MyClass : NSObject {
NSInteger i ;
}
@end
这是一个在您的类上放置实例变量的地方。它只能通过您的类和类别的方法访问。 (旁注:可以在外部访问,但这不是推荐的做法)
另一个例子:
@interface MyClass : NSObject
@end
@implementation MyClass {
NSInteger i ;
}
@end
这也是一个实例变量,但只能通过该块内部编写的方法进行访问。 (旁注:可以通过挖掘类定义来访问它,但这不是推荐的(或常见的)实践)
另一个例子:
@interface MyClass : NSObject
@property NSInteger i ;
@end
与:
相同@interface MyClass : NSObject {
NSInteger _i ; // you are not allowed to access it by this variable
}
- (NSInteger) i ;
- (void) setI:(NSInteger)value ;
@end
这是一个允许人们获取和设置的属性。您可以在方法或其他方法中使用该变量:
NSLog ( @"The value is %i" , self.i ) ; // if it's your instance method
NSLog ( @"The value is %i" , object.i ) ; // if it's object's instance method
另一个例子:
@interface MyClass : NSObject {
NSInteger i ;
}
@property NSInteger i ;
@end
@implementation MyClass
@synthesize i ; // Causes the property to line up with the ivar by the same name.
@end
与:
相同@interface MyClass : NSObject {
NSInteger i ; // you ARE allowed to use this since you defined it
}
- (NSInteger) i ;
- (void) setI:(NSInteger)value ;
@end
在这里,您可以使用getter / setter方法或实例变量本身。但是,您通常应该使用这些方法,因为您[隐式]将它们声明为原子,因此它们具有线程同步。如果你想让它不做线程(并加快速度,只要你不打算在多线程环境中使用它):
@property (nonatomic) NSInteger i ;
@property (nonatomic,readonly) NSInteger i ; // only makes a getter method
我建议暂时避免这种情况并使用直接属性,因为它可以帮助您避免许多常见错误。除非您对程序进行概要分析并确定这是性能损失的原因,否则您应该只使用这些属性。
另一个例子:
@interface MyClass : NSObject
@end
@implementation MyClass
NSInteger i ;
@end
这是 NOT 实例变量。它是一个全局变量,碰巧写在@implementation
范围内。
请参阅上文,了解如何将其转换为实例变量(即将其置于大括号中)。
还有一点需要注意:
声明这样的属性:
@interface MyClass ()
@property NSInteger i ;
@end
不会将其设为私有。但是,它隐藏在人们通常无法访问的文件中,因此编译器不知道属性存在。
代码中其他地方的其他功能仍然可以调用:
[yourObject i] ;
要获得该属性的价值 - 但他们必须首先了解它。
在评论中回答问题的附录:
默认情况下,属性是原子的。它并不一定遵循原子的严格定义(这是一种蠕虫,我建议你现在不要看),但具有相同的效果:线程保证看到完整和最新值,无论另一个线程何时写入它。它通常在合成getter / setter方法时执行此操作:
- (NSInteger) i {
@synchronized(self) {
return i ;
}
}
- (void) setI:(NSInteger)value {
@synchronized(self) {
i = value ;
}
}
如果您改为指定nonatomic
,则会合成这些:
- (NSInteger) i {
return i ;
}
- (void) setI:(NSInteger)value {
i = value ;
}
如果您的财产是atomic
,那么您就不应该直接访问ivar。这样做会违反您开始时提供的线程保护。 (旁注:有些情况你可以,但是等到你在尝试之前更熟悉线程/同步。)
答案 1 :(得分:4)
当您在@interface MyObject (){}
中声明属性时,您将在所谓的匿名或类别类别中声明它。因为它是在.m文件中声明的,所以它只在该文件中可见(没有其他类可以看到它)。但是,您可以在.h文件中声明此类别,在这种情况下,它将对其他类可见。
在类的NSInteger intData
部分内声明@implementation
实际上并未声明实例变量。它声明了一个全局变量,这意味着整个应用程序共享一个单独的实例,或者,如果您想以这种方式查看它,那么您的类的所有实例(因为它是唯一一个知道的实例)这个全局变量)。