iOS 编码复习(一)—— OC内存管理、ARC、property属性、__strong、__weak、__block

首先来聊聊内存管理。因为是先有了内存管理这个东西,才慢慢的有了ARC,而后才会有@property的各种属性

聊到内存管理,我们就能知道iOS5之前,iOS的内存管理是MRC(手动内存管理)的。iOS5之后才有了ARC(自动内存管理)。

那我们就来看看MRC是怎么做的:

在iOS中,每创建一个对象,对象的RC(引用计数)都是自动为1。

MRC中,对象调用retain时,RC就会+1;对象调用release时,RC就会-1;当RC的值为0时,系统会调用dealloc方法来销毁对象。

所以MRC下的set 和 get方法是这样的:

@property (nonatomic, retain) NSString * name;

- (void) setter:(NSString *)name

{

if(_name != name){

[_name release];

_name = [name retain];//或者copy

}

}

-(NSString *)name{

if(!_name){

_name = @"xxx";

}

return [[_name retain] autorelease];

}

在MRC下,@property关键字有:(这里的使用都不是绝对的,只是一种选择策略,比如NSString也可以用retain,要据情况而定)

1:assign、retain 和 copy:copy只用于NSString/block;retain用于除NSString/block以外的OC对象;assign用于非OC对象(基本数据类型、枚举等),当两个对象相互引用的时候,一个要用retain,一个用assign。之所以NSString使用copy,就是因为NSMutableString的对象可以赋值给NSString,而父类指针可以指向子类对象,所以给这个属性赋值的时候,无论是传入可变对象还是不可变对象,那它都会是不可变的副本。如果使用strong,而传入的对象是可变对象,那如果外部修改了这个可变对象,则就会修改到该属性值。同理,NSArray、NSDictionary也应该使用copy。(copy会分配新的内存空间,retain或下面的strong只是对引用计数加一)

2:nonatomic 和 atomic:atomic的意思是原子的,它是指属性存储是线程安全(一次只有一个对象对它操作)的,但是atomic不一定就绝对线程安全了,比如一个可变数组arr是线程安全的(atomic),但是[arr objectAtIndex:index]就不是线程安全的了。

3:readwrite 和 readonly:(这个就很好理解了)

4:getter 和 setter

ARC下新加了以下几种@property属性:

1:strong 与MRC下的retain是类似。引用计数+1

2:  weak, unsafe_unretained这两个与assign差不多,不过也有区别,等下介绍;另外ARC下使用assign的概率也是非常高的。

总结起来就是:内存管理基本是对引用计数的操作。对于property关键字,在MRC下,OC对象通常使用retain,非OC对象使用assign,循环引用的时候,一个使用retain,一个使用assign;在ARC下,OC对象通常使用strong,非OC对象通常使用assign,而weak就是为了对对象进行弱引用的,如循环引用的时候,一端使用strong,一端使用weak。

好,到这里,本文的目的就基本达到了。不过,还想给大家分享点其他的干货,大部分也是看别人的总结的:

一:strong、weak、unsafe_unretained的区别

执行代码:

self.string1 = @"String 1";

   self.string2 = self.string1;

self.string1 = nil;

NSLog(@"String 2 = %@", self.string2);


1:strong:

@property (nonatomic, strong) NSString *string1;  

@property (nonatomic, strong) NSString *string2;

输出 String 2 = String 1;因为引用计数加一

2:weak:

@property (nonatomic, strong) NSString *string1;   

@property (nonatomic, weak) NSString *string2;

输出 String 2 = null因为wean的指针会指向同一个地址,引用计数不会加一,但是weak会将指针置为null,防止野指针出现。

3:unsafe_unretained:

@property (nonatomic, strong) NSString *string1;   

@property (nonatomic, unsafe_unretained) NSString *string2; 

 注意这里的程序会crash掉,不会自动将指针置为null,所以这就是它与weak的区别

二:__block、__weak、__strong的用法;避免循环引用:
其实我们都知道,这几个东西就是使用block时为了避免循环引用才会经常用到的,所以按上面看到的经验,一定要一端对象weak,才可以:
1)、__weak 与 __strong的结合使用避免循环引用
首先__weak是为了避免循环引用的,所以一般在使用block之前,可以使用__weak 来弱引用self,例如:

__weak  __typeof__(self)  weakSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

[weakSelf dosomthing];

});

这里没有任何问题;但是下面

__weak  __typeof__(self)  weakSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

[weakSelf doSomething];

[weakSelf doOtherSomething];

});

在执行完第一个doSomething之后,weakSelf有可能被释放,这个时候就需要用到__strong了;

__weak  __typeof__(self)  weakSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

__strong  __typeof__(self) strongSelf = weakSelf;

[strongSelf doSomething];

[strongelf doOtherSomething];

});

同上看到的,用__weak可以解决循环引用的问题。但是,如果block里要执行多个函数,最好就要加上 __strong;同样的这种巧妙的用法对变量也非常合适,使用过AFNetworking的人大概就见到过这样的对变量的修饰。这样即时block外部释放了该变量,在block的生命周期里,该变量还是可以使用的。

2)、问题来了,__block是干嘛的??__block就与__weak正好相反了,它可以改变变量的作用域,使得变量的作用域扩展到block里面。这个时候,就可以对block外部的变量进行操作了(__strong也有这个作用)。那么__block是否可以避免循环引用呢??答案是肯定的,上代码:

__block  __typeof__(self)  blockSelf = self;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{

[blockSelf doSomething];

[blockSelf doOtherSomething];

blockSelf = nil;

});

如上所示:把blockSelf置为nil是关键。

三、顺带说一下深拷贝和浅拷贝:copy就是浅拷贝,它只拷贝指针,mutableCopy是深拷贝,它会拷贝对象。就是不分父类子类。浅拷贝就是只拷贝父类和子类的指针地址,深拷贝就是父类和子类的对象也都会拷贝。所以,你会发现归档,用的就是深拷贝。经常面试的人会问你,如何让自定义的类具备拷贝功能,则只需要实现NSCoping协议就可以了。


好了。有点乱,希望后续可以多完善一下。也希望各位大牛指正


你可能感兴趣的:(ios,内存管理)