在我接触过的所有编程语言中,obj-c的语法无疑是最独特的,(其次可能就是Python了吧,因为没有花括号),尤其是其中的@property,@synthesize。今天就对在这过程中遇到的几个让我迷惑过的关键字进行总结:
1,@property
@property关键字是在声明成员属性时使用的一个关键字,使用方式通常为
@property(属性1,属性2,属性3)成员类型 成员名,三个属性字段的含义分别为
赋值方式、读写权限、和原子性(可不完全指定,也可不按顺序指定),比如在某个类中看到这样一段声明:
@property(copy,readwrite,nonatomic)NSString *value1;
意思就是这个类里有一个NSString*型的成员变量value1,当对其赋值时采用copy的方式(copy),对外界可读可写(readwrite),对其操作是非原子性的(nonatomic)。在你通过@property关键字为成员指定了一些合法属性之后编译器能够自动的根据你指定的属性为你做很多事(比如生成get,set方法,进行内存管理等)。
1.1 赋值方式
赋值方式取值有三个
assign,
retain和
copy,在不显式指定时系统默认的方式是
assign;
1.1.1 assign
assign可以简单的理解成为浅拷贝,比如下面这段代码:
@interface MyClass : NSObject
@property(assign,readwrite,nonatomic) NSMutableString *value1;
@end
@implementation MyClass
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSMutableString *str= [[NSMutableString alloc] initWithString:@"Hello "];
MyClass *myClass = [[MyClass alloc] init];
myClass.value1 = str;
[myClass.value1 appendString:@"world!"];
NSLog(@"%@",str);
}
return 0;
}
这段代码会输出什么呢?str的值为“Hello ”啊,那就输出“Hello ”呗。这样想就错了,因为我们在声明中有这样一句
@property(assign,readwrite,nonatomic) NSMutableString *value1;
所以在执行
myClass.value1 = str;
时只是简单的将str的地址赋值给了myClass.value1,这就是我们之前说的浅拷贝,所以接下来对myClass.value的操作自然会影响到str。简而言之就是assign就是简单的按位拷贝,除此之外什么都不做。因此上面的代码应该输出“Hello world!”
那么这样到头来就导致了一个问题,在这个例子里如果我们在外界释放了str指向的内存,那么myClass.value1就指向了一个被释放了得空间。我们如果在这种情况下使用myClass.value1就会导致意想不到的结果。所以这儿就引入了一个约定成俗的说法,一般我们只对基础数据类型(比如NSIteger,int,float等)采用assign的方式赋值,对于NSObject及其子类由于引用计数的存在,如果只是单纯的按位拷贝(对于指针而言就是简单的赋给地址),当其指向的对象引用计时器清零之后,并不会及时的将指针赋值为nil,此时向一个已经被释放的对象发送信号,就会导致错误。所以我们就引入了ratain得赋值方式。
1.1.2 ratain
我们将上面代码中的assign改变为ratain运行看看会是什么结果,其实还是输出Hello world!。ratain其实也是直接赋给地址,但是在赋值的时候会
将指针所指对象的引用计数器加一。
因此采用这种方式及时在外部str出了生命周期,他也只是将其指向的对象的引用计数器减了一。此时由于其引用计数任然为一,所以不会呗销毁,在内部任然可以使用myClass.value1。因此通常而言对于类型为NSObject或其子类的成员我们一般都用retain(NSString除外)。
1.1.3 copy
copy是三种方式中唯一一种生成新地址的拷贝方式,使用copy方式的成员需要实现NSCoping协议(比如NSString)。在拷贝的过程中就会去调用等号右边对象的copy方法,生成新对象,然后将新对象的地址赋给等号左边,并将其引用计数器置为1。通常而言我们拷贝NSString时使用copy方式。
1.2 读写权限
读写权限分为两类,readonly和readwrite,如果不写的话默认为readwrite。即编译器会为其生成get和set函数,如果是readonly的话则只会为其生成get函数。在这里顺便提一下oc里面的"."操作符会自动的去调用get和set函数(如果存在的话)。
1.3 原子性
原子性只有两个取值
nonatomic
和
atomic
表示对其操作是原子性和非原子性的。所谓原子性就可以粗暴的理解为当前线程在对其进行操作的时候不允许其他线程对其进行操作,避免出现数据异常,用来在一定程度上保证并发结果的正确性,然而要保证并发的正确性还需要用到一些同步机制,所以单靠atomic是远远不够的,而且atomic影响程序的执行效率,所以我基本都是用nonatomic。
后记
在写这篇笔记之前参考了很多写得很棒的博文,在此对各位作者表示真心的感谢,如果您在文章里发现有长得特别想您文章的片段或句子的话请留言告知。另外本人才接触ios不久,文章难免有疏漏,错误之处,还望各位斧正!