ios修饰符

1:assgin

简单的赋值 不更改索引计数  一般修饰的是基本的数据类型 如:NSIntger,CGFloat,int,float,double,char 这里要知道 基本的数据类型是分配在栈上的 栈的内存会由系统自己处理

//写法:
@property (nonatomic,assign) float number;

//setter方法:
-(void)setNumber:(float)num{
  number = num;
}

注:assgin 也可以修饰对象;一般情况下不会使用,是因为被assgin 修饰的对象在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,从而引起也指针的问题。对象一般分配在堆上的某块内存,如果在后续的内存分配中,刚好分配到了这块地址,程序就会crash

2:copy

一般情况下,copy可以用于对不可变的属性修饰中,主要是NSArray /NSDictionary/NSString, 也可以用来修饰block。

//写法
@property (nonatomic, copy) NSString* name;
@property (nonatomic, copy) void(^typeBlock)(BOOL selected);
@property (nonatomic, copy) void(^cancelBlock)();

//setter方法
-(void)setName: (id)newName {
      if (name != newName) {
        [name release];
        name = [newName copy];
     }
}

注:使用copy这个属性修饰符是浅拷贝,给新的对象B赋值该name属性后,B对象值更改后name属性的值不会改变。(如果使用strong修饰了name属性,B对象的值被修改了以后name的值也会变)

3:retain

retain修饰的对象,引用计数会+1,retain一般用来修饰非NSString 的NSObject类和其子类,retain只能修饰oc对象,不能修饰非oc对象,比如说CoreFoundation对象就是C语言框架,它没有引用计数,也不能用retain进行修饰

//定义
@property (nonatomic, retain) PopObject *popObject;

//setter方法
-(void) setName: (id) nameStr
{
      if (name != nameStr) {
        [name release];
        name = [nameStr retain];
     }
}

注:两个对象A和B,如果A对象中引用B对象,并且用retain修饰;B对象中引用A对象,并且也用retain修饰。这个时候就是A和B相互引用,无法释放,造成内存泄漏。当泄漏严重时将会出现崩溃等问题。

解决办法:相互引用,一端用retain,一端用assign

4:strong

strong表示对对象的强引用,引用计数也会+1,用于可变的数组字典字符串,或者view控件等

两个对象之间相互强引用造成循环引用,内存泄漏。

//使用
@property (nonatomic, strong) NSArray  *arr;
@property (nonatomic, strong) NSMutableArray *mArray;
@property (nonatomic, strong) UILabel *label;
@property (nonatomic ,strong) NSString *str;
5:weak

weak 表示对对象的弱引用,被weak修饰的对象随时可被系统销毁和回收,引用计数不会加1,比较常用的地方就是delegate属性的设置。

常见的修饰符问题:

assign和weak的区别:当它们指向的对象释放以后,weak会被自动设置为nil,而assign不会,所以会导致野指针的出现,可能会导致crash。

strong和weak的区别:

  • strong :表明是一个强引用,相当于MRC下的retain,只要被strong引用的对象就不会被销毁,当所有的强引用消除时,对象的引用计数为0时,对象才会被销毁。
  • weak : 表明是一个弱引用,相当于MRC下的assign,不会使对象的引用计数+1。

两个不同对象相互strong引用对象,会导致循环引用造成对象不能释放,造成内存泄漏。


6:nonatomic/atomic
  nonatomic 非原子属性。它的特点是多线程并发访问性能高,但是访问不安全;与之相对的就是atomic,特点就是安全但是是以耗费系统资源为代价,所以一般在工程开发中用nonatomic的时候比较多。
  系统默认的是atomic,为setter方法加锁,而nonatomic 不为setter方法加锁。
使用atomic加锁后setter函数会变成这样,之所以这么做,是因为防止在写未完成的时候被另外一个线程读取,造成数据错误
{lock}
    if (property != newValue) {
         [property release];
         property = [newValue retain];
     }
{unlock}

  为什么nonatomic要比atomic快。原因是:它直接访问内存中的地址,不关心其他线程是否在改变这个值,并且中间没有死锁保护,它只需直接从内存中访问到当前内存地址中能用到的数据即可(可以理解为getter方法一直可以返回数值,尽管这个数值在cpu中可能正在修改中)

  为什么也经常听到有人说atomic也不是绝对安全的呢。因为:atomic的安全只是在getter和setter方法的时候是原子操作,是安全的。但是其他方面是不在atomic管理范围之内的,例如变量cnt的++运算。这个时候不能保证安全。

@property  int height;
    @synthesize height = _height;
    self.height = 0;
    for (i = 0; i < n; i++) {
      self.height ++;
    }

  常见问题

  1。block为什么使用copy?block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在ARC中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。

 
原文地址:https://www.cnblogs.com/huangzhenwei/p/9929548.html