ios应用开发Objective-C内存管理基础

9158APP 0

对于我们.net开发者来说,net为我们提供了自动内存管理机制,我们不需要关心内存管理。但这在iPhone 开发过程中是不可能的。本文将简要介绍Objective-C的内存管理机制和方法以及一些特性。

手动内存管理

Cocoa 和Objective-C 类都是NSObject 的子类。 NSObject中有多种方法用于内存管理。 alloc方法为对象分配内存空间。 dealloc方法用于释放对象的空间。但是dealloc方法永远不会在我们的代码中使用,因为运行时会通过调用这个方法为你释放内存空间。您所需要做的就是引用计数。稍后我会介绍什么是引用计数。

除了alloc和dealloc之外,NSObject还有retain和release方法用于引用计数。其中retain方法将retainCount变量加1,release方法将retainCount变量减1。当使用alloc为对象分配内存空间时,retainCount将为1。在该对象的生命周期内,该对象可能会继续被其他变量引用。但是当有新的变量指向这个对象时,就应该调用retain方法,这样运行时就会知道有一个新的引用指向这个变量,并且在这个对象的生命周期内有权使用它。这就是Objective-C 开发人员所说的“拥有”。例如: Foo*myFooOne=[[Fooalloc]init];//retaincount为1Foo*myFooTwo=myFooOne;//myFooTwo指向这个对象//retaincount仍然是1[myFooTworetain];//调用retain方法,会运行时可知myFooTwo指向该对象,retaincount为2

在上面的代码中,myFooTwo通过调用retain方法获取了Foo对象的所有权。在这个对象的生命周期中,会有很多变量指向和引用它。指向这个对象的变量也可以通过release方法释放这个所有权。 release方法会告诉运行时我已经使用完这个变量,不再需要它,并且retainCount会减1。

当对象的retainCount大于等于1时,运行时会继续维护该对象。当对象的retainCount为0时,运行时将释放该对象并回收其占用的内存空间。

下图展示了Foo对象的生命周期。 Foo对象首先在内存中分配一块内存空间,并被myFooOne引用。此时Foo对象的retainCount为1。

Foo * myFooOne=[[Foo alloc] init];

Foo对象的生命周期

第二个引用变量指向Foo 对象。这个引用变量然后调用retain方法,这实际上是调用Foo对象的retain方法。 Foo 对象的保留计数变为2。 Foo*myFooTwo=myFooOne;[myFooTworetain];

然后当不再需要myFooOne引用时,通过调用release方法释放Foo对象的所有权,Foo对象的retainCount变为1。

但是当不再需要myFooTwo时,它也会调用release方法释放Foo对象的所有权,并且Foo对象的retainCount变为0。

内存泄漏

我们经常在方法中声明对象,看下面的例子: -(void)myMethod{//in CorrectmethodNSString*myString=[[NSStringalloc]init];//retainCount=1Foo*myFoo=[[Fooalloc]initWithName:myString] ; //retainCount=1NSLog(@'Foo'sName:%@',[myFoogetName]);}

在上面的方法中,我们为myString和myFoo分配了内存空间。方法执行结束后,两个变量超出了作用域,不再有效。但是这个方法并没有释放这两个对象。因此,这两个变量占用的内存空间在运行时并没有被释放。除非你的应用程序结束,否则这两个变量占用的内存空间始终不可用。我们称之为内存泄漏。

以防止内存泄漏。每当我们创建一个对象,或者创建一个对象的副本时,我们必须通过release方法释放它。 -(void)myMethod{NSString*myString=[[NSStringalloc]init];//retainCount=1Foo*myFoo=[[Fooalloc]initWithName:myString];//retainCount=1NSLog('Foo'sName:%@',[ myFoogetName]);[myFoorelease];//retainCount=0sodeallocate[myStringrelease];//retainCount=0sodeallocate}

弱引用

看下面的例子: -(void)myMethod{//anin CorrectmethodFoo*myFooOne=[[Fooalloc]initWithName:@'James'];//retainCount=1Foo*myFooTwo=myFooOne;//retainCountstill1[myFooOnerelease];//retaincount=0sodeallocatedNSLog('名称:%@',[myFooTwoprintOutName]);//运行时错误}

nyFooTwo 指向Foo 对象,但是没有调用retain方法,属于弱引用。上面的代码运行时会报错。因为myFooOne调用了release方法。 keepcount变为0,运行时,对象的内存空间被回收。那么myFooTwo在调用printPutName的时候自然会报错,如下图所示。

运行时报错

摘要:本文简单介绍了Objective-C手动内存管理、内存泄漏、弱引用等知识。