内存管理
程序员文章站
2022-06-25 18:25:47
...
1.内存的创建和释放
让我们以Object-c世界中最最简单的申请内存方式展开,谈谈关于一个对象的生命周期。首先创建一个对象:
id tt= [[test alloc]initWithName:@"百合不是茶" setLike:2];
对于test来说他的引用计数就增加了+1,原因就是他调用了alloc来创建了一块只属于他的内存,这样对象的引用计数 就得+1. 另外,Object-c中的另两个关键字retain和copy也会将对象的引用计数+1.根据Object-c的内存管理机制,我们在使用完 “testObject”后,需要释放它。
[test release];
3.属性关键字
@property (nonatomic, assign) int sex;
@property (nonatomic, retain) NSString* name;
可以看到关键之@property后的括号出现了四个特征性关键字:nonatomic , assign , retain , settet, 这些关键字直接告诉编译器后面的变量用何种方式
assign 赋值方式 不复制不保留,直接赋值 默认值 基本数据类型和本类不直接拥有的对象 retain +1 赋值方式 将新值保留一份赋覆盖原值 不是默认值 大部分对象可使用 copy +1 赋值方式 将新值复制一份赋覆盖原值 不是默认值 字符串选择性使用 readwrite 读写权限 生成getter和setter两个方法 默认值 变量可读取可修改 readonly 读写权限 只生成getter方法 不是默认值 变量只读不可修改 atomic 原子性 原子操作 默认值 可以保留在多线程环境下,能安全的存取值 nonatomic 原子性 非原子操作 不是默认值 不生成多线程同步内容 getter 存取方法 自定义取方法 不是默认值 setter 存取方法 自定义赋值方法 不是默认值 关于nonatomic,如果我们能确定不需要多线程访问时,强烈推荐使用这个关键字,因为atomic对于性能的损失相对较大 如果是类的delegate,推荐使用assign关键字,原因是避免了retain的死循环造成的对象无法真正的释放
下面的内容时来自网络,
3.ARC新增关键字 ARC新增两个武功高强的左右护法:strong 和 weak strong的含义和retain相同,weak和assign相同,修饰完的属性变量用法也是完全没有改变,不过strong和weak只能修饰对象。 苹果官方对于ARC机制中对象的内存引用规则: (1)任何对象,如果仍有持有者,就不会销毁 (2)任何对象,已经没有任何持有者,即自动销毁 持有者就是指向对象的指针,如果是strong修饰的,即是对象的持有者,如果是weak属性的,则不是持有者 4.ARC机制的使用规则 对于ARC机制的使用,苹果发布了几条重要的规则需要开发者遵守。单单看那些生搬硬套的东西难免生涩,根据开发经验将规则总结如下: (1)不能调用dealloc,不能重写和调用retain,release,retainCount 和autorelease,同理,@selector(retain),@selector(release)这些曲线救国的方法也不能调用。 dealloc虽然能够重写,但是不能调用[super dealloc]之类的方法,CoreFoundation框架由于非从属cocoa框架,所以CFRetain和CFRelease仍然正常使用。 (2)不能使用NSAllocateObjec或NSDeallocateObject函数来创建对象 (3)不能在C语言的结构体中使用对象指针,同时建议用object-c的类来管理数据而不是结构体 (4)不得使用NSAutoreleasePool对象。ARC中,全部使用@autorelease关键字代替,且比NSAutoreleasePool更高效 (5)不得使用内存Zone,那些牵涉NSZone的方法都不得使用。 (6)不得对一个属性变量的取值方法命名以new开头 (7)outlet均用weak关键字修饰,除非他是xib中最顶部的界面元素,则需要strong。 (8)Core Foundation不适合ARC,该创建的仍创建,该释放的仍释放。 property中的strong 、weak、copy 、assign 、retain 、unsafe_unretained 与autoreleasing区别和作用详解 iOS5中加入了新知识,就是ARC,其实我并不是很喜欢它,因为习惯了自己管理内存。但是学习还是很有必要的。 在iOS开发过程中,属性的定义往往与retain, assign, copy有关,我想大家都很熟悉了,在此我也不介绍,网上有很多相关文章。 现在我们看看iOS5中新的关键字strong, weak, unsafe_unretained. 可以与以前的关键字对应学习strong与retain类似,weak与unsafe_unretained功能差不多(有点区别,等下会介绍,这两个新 关键字与assign类似)。在iOS5中用这些新的关键字,就可以不用手动管理内存了,从java等其它语言转过来的程序员非常受用。 strong关键字与retain关似,用了它,引用计数自动+1,用实例更能说明一切 1 @property (nonatomic, strong) NSString *string1; 2 @property (nonatomic, strong) NSString *string2; 有这样两个属性, 1 @synthesize string1; 2 @synthesize string2; 猜一下下面代码将输出什么结果? 1 self.string1 = @"String 1"; 2 self.string2 = self.string1; 3 self.string1 = nil; 4 NSLog(@"String 2 = %@", self.string2); 结果是:String 2 = String 1 由于string2是strong定义的属性,所以引用计数+1,使得它们所指向的值都是@"String 1", 如果你对retain熟悉的话,这理解并不难。 接着我们来看weak关键字: 如果这样声明两个属性: 1 @property (nonatomic, strong) NSString *string1; 2 @property (nonatomic, weak) NSString *string2; 并定义 1 @synthesize string1; 2 @synthesize string2; 再来猜一下,下面输出是什么? 1 self.string1 = @"String 1"; 2 self.string2 = self.string1; 3 self.string1 = nil; 4 NSLog(@"String 2 = %@", self.string2); 结果是:String 2 = null 分析一下,由于self.string1与self.string2指向同一地址,且string2没有retain内存地址,而 self.string1=nil释放了内存,所以string1为nil。声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为 nil。这样的好处能有效的防止野指针。在c/c++开发过程中,为何大牛都说指针的空间释放了后,都要将指针赋为NULL. 在这儿用weak关键字帮我们做了这一步。 接着我们来看unsafe_unretained 从名字可以看出,unretained且unsafe,由于是unretained所以与weak有点类似,但是它是unsafe的,什么是unsafe的呢,下面看实例。 如果这样声明两个属性: 并定义 1 @property (nonatomic, strong) NSString *string1; 2 @property (nonatomic, unsafe_unretained) NSString *string2; 再来猜一下,下面的代码会有什么结果? 1 self.string1 = @"String 1"; 2 self.string2 = self.string1; 3 self.string1 = nil; 4 NSLog(@"String 2 = %@", self.string2); 请注意,在此我并没有叫你猜会有什么输出,因为根本不会有输出,你的程序会crash掉。 原因是什么,其实就是野指针造成的,所以野指针是可怕的。为何会造成野指针呢?同于用unsafe_unretained声明的指针,由于 self.string1=nil已将内存释放掉了,但是string2并不知道已被释放了,所以是野指针。然后访问野指针的内存就造成crash. 所以尽量少用unsafe_unretained关键字。 strong,weak, unsafe_unretained往往都是用来声明属性的,如果想声明临时变量就得用__strong, __weak, __unsafe_unretained, __autoreleasing, 其用法与上面介绍的类似。 还是看看实例吧。 1 __strong NSString *yourString = @"Your String"; 2 __weak NSString *myString = yourString; 3 yourString = nil; 4 __unsafe_unretained NSString *theirString = myString; 5 //现在所有的指针都为nil 再看一个: 1 __strong NSString *yourString = @"Your String"; 2 __weak NSString *myString = yourString; 3 __unsafe_unretained NSString *theirString = myString; 4 yourString = nil; 5 //现在yourString与myString的指针都为nil,而theirString不为nil,但是是野指针。 __autoreleasing的用法介绍: 在c/c++,objective-c内存管理中有一条是:谁分配谁释放。 __autoreleasing则可以使对像延迟释放。比如你想传一个未初始 化地对像引用到一个方法当中,在此方法中实始化此对像,那么这种情况将是__autoreleasing表演的时候。看个示例: 1 - (void) generateErrorInVariable:(__autoreleasing NSError **)paramError{ 2 NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil]; 3 NSArray *keys = [[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil]; 4 NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys]; 5 *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary]; 6 } 7 -(void)test 8 { 9 NSError *error = nil; 10 [self generateErrorInVariable:&error]; 11 NSLog(@"Error = %@", error); 12 } 这样即便在函数内部申请的空间,在函数外部也可以使用,同样也适合谁分配谁释放的原则。 同样下面的代码也是类似原因, 只不过在没有开启ARC的情况下适用: 1 -(NSString *)stringTest 2 { 3 NSString *retStr = [NSString stringWithString:@"test"]; 4 5 return [[retStr retain] autorelease]; 6 } 开启ARC后,应改为: 1 -(NSString *)stringTest 2 { 3 __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"]; 4 5 return retStr; 6 }