@property 和@synthesize

在Objective-C中,类的属性默认是protected的,也就是说只有该类以及它的子类才能存取它,如果要给外部使用的话,则需要来帮它加个setter/getter。
例如:
@property 和@synthesize_第1张图片
需要注意的是,在 Objective C 中, get 有着特殊的含义,所以 getter 方法直接使用属性名,而不是使用 get 然后再加上属性名。
假定在非ARC环境下,用户包含书籍属性,那么直接这么写的 setter 方法存在内存泄露的危险, 怎么才能很好的避免这个问题呢?
Person类中:

#import "Book.h"
{
    Book *_book;
}
- (void)setBook:(Book *)book{
    _book = book;
}
- (Book *)book{
    return _book;
}

这样在人引用了book后, 如果book释放, 人没有释放,那么就会出现野指针错误(Book object 0x100102940 overreleased while already deallocating; break on objc_overrelease_during_dealloc_error to debug),如:
@property 和@synthesize_第2张图片
因此,应该在setter方法中,对使用的对象进行引用计数加1操作,释放的时候,对其引用计数减1, 改为:
@property 和@synthesize_第3张图片
这样才能保证内存的有效性.

当然, 上面仅仅只是三个Book属性,如果有10个、20个其他类属性,是不是也需要写大量这样的代码呢?
答案当然是不用了.
Objective C 2.0 为提供了@property和@synthesize。它大大简化了我们创建数据成员读写函数的过程,更为关键的是它提供了一种更为简洁,易于理解的方式来访问数据成员。
上面的类可以简化为:
@property 和@synthesize_第4张图片
注意:
@property(.h文件)声明一个属性,自动生成setter 和 getter方法
@synthesize(.m文件)实现setter 和 getter方法(Xcode不用写,是因为在.h文件声明property,自动完成synthesize的功能)。

当然这样写也是存在内存泄露的,拿 Book 举例:

@property Book *book;

生成的getter 和 setter代码为:

- (void)setBook:(Book *)book{
    _book = book;
}
- (Book *)book{
    return _book;
}

上面我们已经提到这种写法的错误性. 那应该怎么更改呢? 其实property为我们提供了控制setter生成的操作(非ARC的retain, ARC的strong), 将book属性改为:

@property (retain) Book *book;

生成的setter方法变为:

- (void)setBook:(Book *)book{
    //传进来的book和_book不一样的时候
    if (book != _book){
        //对旧书(当前正在用的书)做一次release操作
        [_book release];
        //对新书做一次retain操作
        _book = [book retain];
    }
}

这样就可以保证内存的有效性,避免内存泄露.

最后,对property提供的关键字进行总结(不同种类的可以一起用,同种类的只能选一个)
控制set方法的内存管理
retain : release旧值,retain新值(用于OC对象)在setter方法中,需要对传入的对象进行引用计数加1的操作。简单来说,就是对传入的对象拥有所有权,只要对该对象拥有所有权,该对象就不会被释放。

assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型,如int、float、double和NSInteger,CGFloat等表示单纯的复制。还包括不存在所有权关系的对象,比如常见的delegate)

strong:strong 是在 IOS 引入 ARC 的时候引入的关键字,是 retain 的一个可选的替代。表示实例变量对传入的对象要有所有权关系,即强引用。strong 跟 retain 的意思相同并产生相同的代码,但是语意上更好更能体现对象的关系。

weak:在setter方法中,需要对传入的对象不进行引用计数加1的操作。简单来说,就是对传入的对象没有所有权,当该对象引用计数为0时,即该对象被释放后,用weak声明的实例变量指向nil,即实例变量的值为0。
注:weak关键字是IOS5引入的,IOS5之前是不能使用该关键字的。delegate 和 Outlet 一般用weak来声明

copy : release旧值,copy新值(一般用于NSString *)与strong类似,但区别在于实例变量是对传入对象的副本拥有所有权,而非对象本身

控制需不需生成set方法

readwrite :同时生成set方法和get方法(默认)
readonly :只会生成get方法

多线程管理
atomic :性能低(默认) atomic意为操作是原子的,意味着只有一个线程访问实例变量。atomic是线程安全的,至少在当前的存取器上是安全的。它是一个默认的特性,但是很少使用,因为比较影响效率,这跟ARM平台和内部锁机制有关。

nonatomic:性能高 nonatomic 跟 atomic刚好相反。表示非原子的,可以被多个线程访问。它的效率比atomic快。但不能保证在多线程环境下的安全性,在单线程和明确只有一个线程访问的情况下广泛使用。

控制set方法和get方法的名称
setter : 设置set方法的名称,一定有个冒号:
getter : 设置get方法的名称

你可能感兴趣的:(iOS开发,内存管理,ios开发笔记)