OC语言 - 内存管理:字符串 | 容器 | 点语法
字符串
1 - 在使用 NSString、NSDate...等轻量数据类型时,它们的引用计数有时会受到 Tagged Pointer 影响,但这并不会影响内存管理原则
1 // 常量区字符串无须管理内存,于 retain/release 操作无关 2 NSString *strA = @"妇好"; 3 [strA retain]; 4 [strA retain];[strA retain];[strA retain]; 5 NSLog(@"%lu",[strA retainCount]);// 18446744073709551615 6 7 8 // 因 Tagged Pointer 有时创建的字符串对象并不在堆区:只要存储的数据有点大,就会跑到堆区 9 NSString *strB = [[NSString alloc] initWithFormat:@"你不是我,怎么知道我不快乐!我不是你,但是我知道你并不快乐!后面省略一万字"]; 10 [strB retain]; 11 NSLog(@"%lu",[strB retainCount]);// 2 12 [strB release];// 只要看到 alloc、retain、copy/mutableCopy 就要有与之对应的 release,不须关心在它在内存中如何分配 13 NSLog(@"%lu",[strB retainCount]);// 1 14 [strB release]; 15 16 17 // 便利构造器自带有 autorelease,无需手动 release 18 NSString *str12 = [NSString stringWithFormat:@"花花世界"]; 19 NSLog(@"%lu",[str12 retainCount]);// 1
容器
1 - 容器会影响其所管理对象的引用计数,下面我们以数组为例
1 NSArray *arrayA = [[NSArray alloc] initWithObjects:@"1", nil];// 1 被管理对象 2 NSMutableArray *arrayB = [[NSMutableArray alloc] initWithCapacity:1];// 1 管理者 3 4 // 谁污染谁治理原则 5 [arrayA retain];// 2 6 [arrayA retain];// 3 7 [arrayA retain];// 4 8 [arrayA retain];// 目前 arrayA 引用计数是 5 9 10 printf("------------------添加------------------\n"); 11 // 对于容器,当把对象添加进数组一次,被管理对象的引用计数就 +1一次 12 [arrayB addObject:arrayA]; 13 NSLog(@"%lu",[arrayA retainCount]);// 6 14 [arrayB addObject:arrayA]; 15 NSLog(@"%lu",[arrayA retainCount]);// 7 16 [arrayB addObject:arrayA]; 17 NSLog(@"%lu",[arrayA retainCount]);// 8 18 [arrayB addObject:arrayA]; 19 NSLog(@"%lu",[arrayA retainCount]);// 9 20 21 22 printf("\n------------------移除----------------\n"); 23 [arrayB removeLastObject]; // -1 24 NSLog(@"%lu",[arrayA retainCount]);// 8 25 [arrayB removeLastObject]; 26 NSLog(@"%lu",[arrayA retainCount]);// 7 27 28 // 当移除某个对象,则引用计数会还原到起始值(arrayA 被添加进容器 arrayB 之前时的计数) 29 [arrayB removeObject:arrayA]; 30 NSLog(@"%lu",[arrayA retainCount]);// 5 31 // 添加 32 [arrayB addObject:arrayA]; 33 NSLog(@"%lu",[arrayA retainCount]);// 6 34 35 36 printf("\n-------------对容器进行 retain、release------------\n"); 37 // 注:在容器没销毁前,对容器本身进行 retain、release 操作,被管理对象的引用计数并不会受到影响 38 [arrayB retain];// 2 39 NSLog(@"%lu",[arrayA retainCount]);// arrayA 依旧是 6 40 [arrayB release];// 1 41 NSLog(@"%lu",[arrayA retainCount]);// arrayA 依旧是 6 42 [arrayB addObject:arrayA];// 7 43 44 45 printf("\n-----------------移除某个对象------------------\n"); 46 47 [arrayB removeObject:arrayA]; 48 NSLog(@"%ld",arrayA.retainCount);// 从 7 变成 5 49 50 51 printf("\n-------------容器销毁或移除所有对象-------------\n"); 52 [arrayA retain];// 6 53 [arrayB addObject:arrayA];// 7 54 [arrayB addObject:arrayA];// 8 55 56 // 当容器销毁或移除所有对象时,对象的引用计数还原到起始值 57 [arrayB removeAllObjects]; 58 NSLog(@"移除所有对象:%lu",[arrayA retainCount]);// 6 59 60 [arrayB addObject:arrayA];// 7 61 [arrayB addObject:arrayA];// 8 62 [arrayB release];// 0 63 NSLog(@"容器已销毁:%lu",[arrayA retainCount]);// 6
点语法
1 - 点语法是否会影响对象引用计数的变化,决定性因素是看属性所使用何种语义特性
// - Student.h
1 #import <Foundation/Foundation.h> 2 @interface Student : NSObject 3 4 @property (nonatomic,retain)NSString *name; 5 @property (nonatomic,retain)NSArray *array; 6 7 - (void)printArray; 8 9 @end
// - Student.m
1 #import "Student.h" 2 @implementation Student 3 4 -(void)dealloc{ 5 6 self.name = nil; 7 self.array = nil; 8 [super dealloc]; 9 } 10 11 - (NSString *)name{ 12 13 return [[_name retain] autorelease];// 本质是为了延长对象的生命周期 14 } 15 16 - (void)printArray{ 17 18 19 self.array = [[NSArray alloc] initWithObjects:@"1",@"2", nil]; 20 NSLog(@"%lu",[_array retainCount]);// 2 21 22 // 在方法里边创建的对象:在出方法前一定要记得 release 或者 autorelease 23 [[_array autorelease] autorelease]; 24 [self textContent]; 25 } 26 27 - (void)textContent{ 28 29 NSLog(@"出了方法后的引用计数:%lu",[_array retainCount]);// 2:因为使用的是 autorelease,所以依旧是 2(实际上系统会帮你销毁,我们无需管理) 30 } 31 32 @end
// - main
1 #import <Foundation/Foundation.h> 2 #import "Student.h" 3 4 int main(int argc, const char * argv[]) { 5 6 Student *stu11 = [[Student alloc] init]; 7 [stu11 printArray]; 8 [stu11 release]; 9 10 return 0; 11 }