【问题标题】:Difference Between Declaring a Variable Under @Implementation And @Interface Under .m file在@Implementation 和@Interface 在.m 文件下声明变量之间的区别
【发布时间】:2015-08-08 15:05:05
【问题描述】:

我学习 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

我发现它的工作方式与在 .m 文件中使用 @property 在 @interface 下声明它的方式相同

我不明白两者之间的区别(在@implementation 和@interface 下声明(在.m 文件中)。

我已经在堆栈中搜索过这个,但他们都在谈论@implementation 和@interface 之间的区别(在 .h 文件中)。所以认为这不是重复的。

【问题讨论】:

  • 在@interface 中声明的NSInteger 是一个全局变量。它也只是一个变量,没有任何属性的陷阱(访问器方法、KVC 等)。

标签: objective-c


【解决方案1】:

首先,您没有声明变量;你在声明一个属性。属性由实例变量支持,但它也添加方法。以下是变量放置位置的说明:

@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

这不是实例变量。它是一个全局变量,恰好写在您的 @implementation 范围内。

如何将其转换为实例变量,请参见上文(即放在大括号中)。

还有一点:

像这样声明一个属性:

@interface MyClass ()
@property NSInteger i ;
@end

不会将其设为私有。但是,它隐藏在人们通常无法访问的文件中,因此编译器不知道属性存在。

代码中其他地方的其他函数仍然可以调用:

[yourObject i] ;

要获取该属性的值 - 但他们必须先知道它的存在。

在 cmets 中回答问题的附录:

默认情况下,属性是原子的。它不一定遵循原子的严格定义(这是一罐蠕虫我建议你现在不要看),但具有相同的效果:线程保证看到一个完整的和向上的-to-date 值,无论何时另一个线程写入它。它通常在合成 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。这样做违反了您一开始就提供的线程保护。 (旁注:在某些情况下您可以,但请等到您对线程/同步更加熟悉后再尝试。)

【讨论】:

  • 首先,感谢您如此努力地回答我的问题。我只是想在你的回答中澄清一些事情。在您的解释中,以“在这里,您可以使用 getter 和 setter 方法...”开头的部分,您提到“您通常应该使用这些方法,因为您 [隐式] 将它们声明为原子的”。嗯,你的意思是“非原子”吗?因为之后的示例说明了@property (nonatomic) NSInteger i。我对那部分有点困惑。
  • @EpicNinja - 我在底部添加了一些额外的内容来描述 atomic 和 nonatomic 正在做什么。
  • 这个答案有一些问题。 1) 不应使用第一个代码示例。没有理由在公共头文件中声明私有 ivars。 2) 第二个代码示例声明了一个私有 ivar。您的陈述“可通过该块内编写的方法访问”有点令人困惑。这样的变量可以被类的任何实例方法访问。 3)您应该提到,@implementation 行内的全局变量声明可以通过使用花括号简单地制成适当的 ivar。
  • “代码中其他地方的其他函数仍然可以调用:[yourObject i] ; 要获取该属性的值 - 但他们必须首先知道它在那里。”完全清楚的是,编译器将强制此属性的隐私:它不允许您在不导入声明的地方调用方法。
  • @JoshCaswell - 不一定。有很多方法可以做到这一点(自己声明另一个具有该方法的类别供您使用;检查类定义;调用 [object performSelector:@selector(i)]; 等等)。编译器将强制执行不可见的普通情况,但这比“私有”更“隐藏”。
【解决方案2】:

当您在@interface MyObject (){} 中声明该属性时,您就是在所谓的匿名或类类别中声明它。因为它是在 .m 文件中声明的,所以它只在该文件中可见(没有其他类可以看到它)。但是,您也可以在 .h 文件中声明此类别,在这种情况下,其他类可以看到它。

在类的@implementation 部分中声明NSInteger intData 实际上并不是在声明实例变量。它声明了一个全局变量,这意味着它的一个实例由您的整个应用程序共享,或者,如果您想以这种方式查看它,您的类的所有实例(因为它是唯一一个知道这个全局变量)。

【讨论】:

猜你喜欢
  • 2011-07-30
  • 1970-01-01
  • 2011-04-27
  • 2011-12-18
  • 2011-01-10
  • 2015-07-29
  • 2012-11-28
  • 2019-07-25
相关资源
最近更新 更多