对于我们.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 对象。这个引用变量然后调用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手动内存管理、内存泄漏、弱引用等知识。