在查看Apple的一个示例时,在TableViewController.m中,他们有:
// Private TableViewController properties and methods.
@interface TableViewController ()
@property (nonatomic, retain) NSMutableArray* sectionInfoArray;
@property (nonatomic, retain) NSIndexPath* pinchedIndexPath;
@property (nonatomic, assign) NSInteger openSectionIndex;
@property (nonatomic, assign) CGFloat initialPinchHeight;
... more properties and methods
@end
@implementation TableViewController
... usual stuff
我想知道为什么他们将这些属性放在.m文件中以及它是如何私有的。似乎任何导入TableViewController.m文件的人都可以使用这些属性和方法吗?为什么不在.h文件中使用@private?
答案 0 :(得分:4)
他们正在做的是在类上声明一个类别,但由于这是在.m文件中完成的,因此效果是这些方法是“不可见的”。
但这并不意味着不能从外部调用这些方法。这是因为目标c中没有真正的隐私,因为我们处理的是消息,而不是方法调用。这意味着即使您不知道该对象是否实际实现了您尝试调用的方法,也可以向对象发送消息。接收对象将在运行时确定它是否可以处理此调用,它甚至可以转发它,并且该方法是否为调用对象所知也没有区别。
这是为什么可以调用私有API并被拒绝的原因之一。
答案 1 :(得分:2)
AFAIK
a)您无法在.h中将属性标记为@private - 这仅适用于ivars。
b)如果您只导入.m文件(在.h文件中没有接口定义),您将无法引用您的类。如果你这样做 - 你会在链接过程中得到重复的符号。
c)所以是的,这些属性是私有的,因为它们不能作为常规属性从外部访问 - 这些属性只能使用显式消息访问 - 但是在这种情况下你会得到编译器的警告,或者你可以使用KVC < / p>
答案 2 :(得分:2)
他们不私人。他们是匿名属性,因为他们是匿名类别的一部分。
属性之一的好处是将拥有对象的内存管理语义放在一个地方。考虑一下:
@property (nonatomic, assigned) NSString *assigned;
@property (nonatomic, copy) NSString *copied;
@property (nonatomic, retain) NSString *retained;
在所有这三种情况下,您都可以在不知道内存语义是什么的情况下分配给他们:
self.assigned = stringParameter; // assigns to instance variable
self.copied = stringParameter; // copies, assigns copy to instance variable
self.retained = stringParameter; // retains, assigns to instance variable
在所有三种情况下,您都可以使用相同的代码免费清理:
self.assigned = nil; // this just nils the instance variable
self.copied = nil; // releases copy in ivar, nils instance variable
self.retained = nil; // releases ivar (same as original object),
// nils instance variable
这就是为什么你经常会看到本地属性:它允许编码器在每次想要分配给实例变量时跳过编写所有内存管理逻辑。这是一个主要优点,因为您只需更改@property
即可在整个班级中更改内存管理逻辑。
匿名属性的另一个用途是将声明为 readonly 的属性扩展为外部代码,将读/写扩展到类本身。
在.h:
@property (nonatomic, readonly, retain) NSError *lastError;
在.m中,在匿名类别中:
@property (nonatomic, readwrite, retain) NSError *lastError;
.m代码中的其他地方:
self.lastError = error;
同样,这主要是出于内存管理的原因。
以下是_lastError实例变量的每个赋值都没有属性。
假设我们在.h文件中定义了一个名为_lastError的NSError。
保留:
[_lastError release];
_lastError = [error retain];
副本:
[_lastError release];
_lastError = [error copy];
使用assign:
_lastError = error;
在前两种情况下,你需要在dealloc中使用它:
[_lastError release];
但是在最后一种情况下,你必须在dealloc中放置 nothing ,否则你会崩溃。
因此,让我们添加我们需要使用属性的内容:
在匿名类别中添加:
@property (nonatomic, readwrite, retain) NSError *lastError;
在@implementation中添加:
@synthesize lastError = _lastError;
另请注意,此时在“现代”Cocoa运行时(64位Mac或iOS)上,您可以从标头中删除NSError * _lastError。编译器可以根据@synthesize找出你想要的那个。
以下是改变我们代码的方式:
每项任务:
self.lastError = error; // works regardless of storage specifier
在daelloc:
self.lastError = nil; // works regardless of storage specifier
答案 3 :(得分:1)
首先,您通常无法导入.m文件 - 并非没有大量编译器/链接器错误。其次,这些属性是私有的,因此Apple可以在后续版本中自由更改它们。
是的,你可以通过反思找到他们。但这是一个滑坡,等等,你可以自担风险,除非你确切知道自己在做什么,否则将在以后的版本中打破等等。除非你确切知道自己在做什么。
答案 4 :(得分:1)
目标c中没有私有方法或变量,@ private标志主要是这样,当其他开发人员看到它时,他们知道它应该是私有的。你在苹果代码中看到的是一个类别的例子,一种在目标c中伪造私有方法和变量的方法。因为外部类只会导入.h文件,所以它们永远不会在.m文件中看到添加的方法和变量。
答案 5 :(得分:0)
使用匿名类别黑盒子内部属性和其他类不应该知道的方法。虽然编译器在从其他类引用此类时不知道它们,但您可以使用键值编码从技术上访问其他类中的任何属性。
答案 6 :(得分:0)
您无法导入实施文件TableViewController.m
,只能导入.h
TableViewController
个文件,
尽管如此,您可以在 TableViewController 类之外引用这些属性,并显示一条警告,显示“not response” note。