过去几年我一直在为iOS平台编程,但主要是使用swift。在最近的几个月里,我一直在使用Objective C负责一个项目,虽然我喜欢它并且发现它很容易学习,但是有一些问题主要是我仍然不太了解的变量。
1)声明实例变量和属性有什么区别?由于编译器会自动为每个属性创建一个实例变量,除了能够传递一些参数(如原子,非原子,强,弱,赋值等)之外,还有什么真正的优势吗?
2)在@implementation中声明变量或在.m文件中的属性@interface之间有什么区别? 根据我的理解,在@implementation中声明它使它成为一个静态变量并在@interface中声明它使它成为一个实例变量,这是正确的吗?另外,为什么从UIViewController继承的类(例如)已经在.m文件中有一个@interface,而继承自NSObject的类不是?
3)(个人问题)您通常将财产设置为原子或非原子?我发现原子是更好的,因为虽然它可能更慢,但它是线程安全的,但我看到大多数人使用非原子。现在我们拥有的动力量速度差异是否仍然明显?
4)每当我在两个不同的类中的@implementation中声明两个具有相同名称的实例变量时,我得到一个"重复的符号"错误。为什么会这样?
出于好奇,只是另一个简单的问题: 我看到许多问题在代码中@interface有花括号,但在我的代码中我从未见过它,而是以@endmentation文件结束@End结尾。这是在早期版本的Obj-C中还是有任何真正的区别?
非常感谢,我知道这些是4或5个问题,但我很快就跳进了一个项目,我认为我真的需要学习基础知识,因为我找不到这些问题的答案而跳过了。 / p>
答案 0 :(得分:2)
1)声明实例变量和属性有什么区别?由于编译器会自动为每个属性创建一个实例变量,除了能够传递一些参数(如原子,非原子,强,弱,赋值等)之外,还有什么真正的优势吗?
属性可能由实例变量支持也可能不由实例变量支持。默认情况下它们是,但您可以声明属性并显式提供getter和setter(如果不是只读)。然后该属性将没有隐式声明的ivar。属性可以很容易地指示它是否是原子的,是否是只读的,并且它允许您指示内存管理(强,弱,复制,分配)。属性还为键值观察提供支持。
如果你想私下使用一个简单的变量,而不需要任何这些功能,那么没有属性的直接ivar就会过于高效。
有关详细信息,请参阅Is there a difference between an "instance variable" and a "property" in Objective-c?。
2)在@implementation中声明变量或在.m文件中的属性@interface之间有什么区别?根据我的理解,在@implementation中声明它使它成为一个静态变量并在@interface中声明它使它成为一个实例变量,这是正确的吗?另外,为什么从UIViewController继承的类(例如)已经在.m文件中有一个@interface,而继承自NSObject的类不是?
.m中的私有@interface Whatever ()
称为类扩展。它基本上是一个特殊的未命名类别。在那里或在@implementation
区块中声明ivars之间没有区别。
我个人使用类扩展来私有地遵守协议并声明私有属性。我使用@implementation
块来声明私有ivars。
@implementation
块中的变量是普通的实例变量,如果它们放在大括号中。
@implementation {
// ivars here
}
// variables here are globals. Same as before @implementation or after @end
// methods
@end
如果没有花括号,那些变量就会变成全局变量。
有关详细信息,请参阅Difference between variables in interface Object() {} and @implementation Object @end和Difference Between Declaring a Variable Under @Implementation And @Interface Under .m file。
3)(个人问题)您通常将财产设置为原子或非原子?我发现原子是更好的,因为虽然它可能更慢,但它是线程安全的,但我看到大多数人使用非原子。现在我们拥有的动力量速度差异是否仍然明显?
原子属性并不是真正的线程安全。它只是意味着赋值是原子的,读取是原子的,但它在广义上并不真正意味着线程安全。
请参阅What's the difference between the atomic and nonatomic attributes?进行更全面的讨论。
4)每当我在两个不同的类中的@implementation中声明两个具有相同名称的实例变量时,我得到一个"重复的符号"错误。为什么会这样?
见#2。您不能在@implementation
块花括号中包含变量。将变量放在它们所属的位置,问题就会消失。
如果您确实希望变量是静态文件,请将其放在@implementation
之前,以明确它不是该类的一部分,并使用static
作为变量声明的前缀。然后,如果您碰巧在不同的文件中有两个具有相同名称,如果它们是静态的,则不会出现重复问题。
答案 1 :(得分:1)
1)声明实例变量和属性有什么区别?由于编译器会自动为每个属性创建一个实例变量,除了能够传递一些参数(如原子,非原子,强,弱,赋值等)之外,还有什么真正的优势吗?
属性实际上只是包含在语法中的方法。假设它们是公开提供的,它们的目的是被其他类别调用。实例变量更像是C中的字段访问。您应该默认使用属性(它们支持KVO,在nil上是安全的,等等)。您当然应默认使用属性进行获取/设置,除非可能在初始化程序中使用。
但请注意,编译器不总是创建实例变量。如果同时提供getter和setter,则需要使用@synthesize foo=_foo;
告诉它。
2)在@implementation中声明变量或在.m文件中声明@interface之间有什么区别?根据我的理解,在@implementation中声明它使它成为一个静态变量并在@interface中声明它使它成为一个实例变量,这是正确的吗?另外,为什么从UIViewController继承的类(例如)已经在.m文件中有一个@interface而从NSObject继承的类没有?
历史上,实例变量只能在@interface
。
3)(个人问题)您通常将财产设置为原子或非原子?我发现原子是更好的,因为虽然它可能更慢,但它是线程安全的,但我看到大多数人使用非原子。现在我们拥有的动力量速度差异是否仍然明显?
使用nonatomic
的原因是atomic
并没有像您想象的那样真正解决线程安全问题。例如,即使该属性设置为atomic
,这仍然是线程不安全的(因为foo
的值可能在读取和写入之间发生变化):
self.foo = self.foo + 1;
出于这个原因,我认为最有利于nonatomic
并在需要时专门处理线程安全。