在@Implementation下声明变量和在.m文件下声明@Interface之间的区别

fin*_*tic 6 objective-c

我一直在学习Objective-C.根据我的学习,我知道当你@interface.h文件中声明一个变量时,可以公开访问该变量(类似于java中的公共变量).

@interface MyObject

@property NSInteger intData;

@end
Run Code Online (Sandbox Code Playgroud)

但是当你@interface.m文件中声明它时.它只能在@implementation下的.m文件中访问,除非你为它提供了一个getter和setter.

@interface MyObject ()

@property NSInteger intData;

@end
Run Code Online (Sandbox Code Playgroud)

但我也注意到另一种声明变量的方法,即声明变量 @implementation

@implementation

NSInteger intData;

@end
Run Code Online (Sandbox Code Playgroud)

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

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

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

iAd*_*nct 6

首先,你没有声明一个变量; 你是在申报财产.属性由实例变量支持,但它也添加了方法.这里是放置变量的地方的解释:

@interface MyClass : NSObject {
    NSInteger i ;
}
@end
Run Code Online (Sandbox Code Playgroud)

这是一个在您的类上放置实例变量的地方.它只能通过您的类和类别的方法访问.(旁注:可以在外部访问,但这不是推荐的做法)

另一个例子:

@interface MyClass : NSObject
@end

@implementation MyClass {
    NSInteger i ;
}
@end
Run Code Online (Sandbox Code Playgroud)

这也是一个实例变量,但只能通过该块内部编写的方法访问.(旁注:可以通过挖掘类定义来访问它,但这不是推荐的(或常见的)实践)

另一个例子:

@interface MyClass : NSObject
@property NSInteger i ;
@end
Run Code Online (Sandbox Code Playgroud)

是相同的:

@interface MyClass : NSObject {
    NSInteger _i ; // you are not allowed to access it by this variable
}
- (NSInteger) i ;
- (void) setI:(NSInteger)value ;
@end
Run Code Online (Sandbox Code Playgroud)

这是一个允许人们获取和设置的财产.您可以在方法或其他方法中使用该变量:

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
Run Code Online (Sandbox Code Playgroud)

另一个例子:

@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
Run Code Online (Sandbox Code Playgroud)

是相同的:

@interface MyClass : NSObject {
    NSInteger i ; // you ARE allowed to use this since you defined it
}
- (NSInteger) i ;
- (void) setI:(NSInteger)value ;
@end
Run Code Online (Sandbox Code Playgroud)

在这里,您可以使用getter/setter方法或实例变量本身.但是,您通常应该使用这些方法,因为您[隐式]将它们声明为原子,因此它们具有线程同步.如果你想让它不做线程(并加快速度,只要你不打算在多线程环境中使用它):

@property (nonatomic) NSInteger i ;
@property (nonatomic,readonly) NSInteger i ; // only makes a getter method
Run Code Online (Sandbox Code Playgroud)

我建议暂时避免这种情况并使用直接属性,因为它可以帮助您避免许多常见错误.除非您对程序进行概要分析并确定这是性能损失的原因,否则您应该只使用这些属性.

另一个例子:

@interface MyClass : NSObject
@end

@implementation MyClass
NSInteger i ;
@end
Run Code Online (Sandbox Code Playgroud)

不是实例变量.它是一个全局变量,碰巧写在您的@implementation范围内.

请参阅上文,了解如何将其转换为实例变量(即将其置于大括号中).

还有一点说明:

声明这样的属性:

@interface MyClass ()
@property NSInteger i ;
@end
Run Code Online (Sandbox Code Playgroud)

不要把它私有化.但是,它隐藏在人们通常无法访问的文件中,因此编译器不知道属性存在.

代码中其他地方的其他功能仍然可以调用:

[yourObject i] ;
Run Code Online (Sandbox Code Playgroud)

要获得该属性的价值 - 但他们必须先了解它.

在评论中回答问题的附录:

默认情况下,属性是原子的.它不一定遵循原子的严格定义(这是一种蠕虫,我建议你现在不要看),但具有相同的效果:线程保证看到完整和最新的值,无论如何当另一个线程写入它时.它通常在合成getter/setter方法时执行此操作:

- (NSInteger) i {
    @synchronized(self) {
        return i ;
    }
}
- (void) setI:(NSInteger)value {
    @synchronized(self) {
        i = value ;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您改为指定nonatomic,它将合成这些:

- (NSInteger) i {
    return i ;
}
- (void) setI:(NSInteger)value {
    i = value ;
}
Run Code Online (Sandbox Code Playgroud)

如果您的财产是atomic,那么您不应该直接访问ivar.这样做会违反您开始时提供的线程保护.(旁注:有些情况你可以,但要等到你在尝试之前更熟悉线程/同步.)

  • 这个答案有一些问题.1)不应使用第一个代码示例.没有理由在公共头文件中声明私有ivars.2)第二个代码示例声明一个私有的ivar.您的声明"通过该块内部编写的方法可访问"有点令人困惑.这样的变量可以通过类的任何实例方法访问.3)你应该提到`@ implementation`行中的全局变量声明只需使用花括号就可以变成一个合适的ivar. (2认同)