weak 安全性很好!一旦没有强引用,自动将地址设置为 nil,OC中可以向 nil 发送任何消息都不会抱错!
autorelease 作用就是延迟释放
,给对象添加延迟释放的标记
声明变量
@property (nonatomic, assign) UIButton *btn;
向控制器View中添加按钮:
// alloc / init - 应该出了作用域才会被释放
//
self.btn = [[UIButton alloc] init];
self.btn.frame = CGRectMake(40, 40, 100, 100);
self.btn.backgroundColor = [UIColor orangeColor];
[self.view addSubview:self.btn];
NSLog(@"%@", self.view.subviews);
// 类方法创建的 - 是 ‘autorelease’ 的
// 出了作用域,会被添加到自动释放池中
// 自动释放池被销毁前,才释放对象!
self.btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
[self.view addSubview:self.btn];
NSLog(@"%@", self.view.subviews);
// ARC 上述演练不好使!以 weak 为主!
运行结果:
2015-03-25 10:31:20.055 09-自动释放池[27279:718327] (
"<_UILayoutGuide: 0x7fc5d0d346b0; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fc5d0d2d810>>",
"<_UILayoutGuide: 0x7fc5d0e77950; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fc5d0e77790>>",
"<UIButton: 0x7fc5d0e7b230; frame = (40 40; 100 100); opaque = NO; layer = <CALayer: 0x7fc5d0e07910>>"
)
2015-03-25 10:31:20.063 09-自动释放池[27279:718327] (
"<_UILayoutGuide: 0x7fc5d0d346b0; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fc5d0d2d810>>",
"<_UILayoutGuide: 0x7fc5d0e77950; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fc5d0e77790>>",
"<UIButton: 0x7fc5d0e7b230; frame = (40 40; 100 100); opaque = NO; layer = <CALayer: 0x7fc5d0e07910>>",
"<UIButton: 0x7fc5d0f2f650; frame = (0 0; 22 22); opaque = NO; layer = <CALayer: 0x7fc5d0f2f830>>"
)
可以看到,无论是alloc还是buttonWithType: 都是可以添加到控制器的View上的,也就意味着,创建出来的button并没有立刻销毁
野指针
错误autorealease
的,出了作用域,会自定添加到自动释放池
中,自动释放池销毁前,才会释放对象,同样assign声明的变量会持有该对象的地址,一直不肯放~Person.h
@interface Person : NSObject
+ (instancetype)person;
@end
Person.m
@implementation Person
+ (instancetype)person {
// autorelease 作用就是延迟释放
// 给对象添加延迟释放的标记
Person *p = [[Person alloc] init] ;
return p;
}
- (void)dealloc {
NSLog(@"我去了");
[super dealloc];
}
@end
声明Persion变量:
@property (nonatomic, assign) Person *p;
测试Demo:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.p = [Person person];
NSLog(@"%@", self.p);
}
运行结果:
2015-03-25 10:44:16.652 10-ARC自动释放[27546:726446] <Person: 0x7fb74b45c770>
在MRC下,如果提供的类方法没有autorelease,那么在调用的时候,用assign变量接收,仍然会打印出对象的地址,当然对象并没有销毁(dealloc没有输出
)。
Person *p = [[[Person alloc] init] autorelease];
打印结果:
2015-03-25 10:56:04.224 10-ARC自动释放[27690:732059] <Person: 0x7f8c48f23d90>
2015-03-25 10:56:04.238 10-ARC自动释放[27690:732059] 我去了
可以看到对象被释放了,说明autorelease给对象添加了延迟释放
的标记,让对象在自动是释放池销毁,或者出了离它最近的自动释放池作用域的时候,自动释放。
变量的声明:
@property (nonatomic, weak) Person *p;
@property (nonatomic, weak) UIButton *button;
测试Demo:
// ARC 中,如果给 weak 做 alloc / init 的设置数值,Xcode 会提示!
self.p = [[Person alloc] init];
// 对于 Xcode 编译器而言,只要是类方法,就不会提示!
// 如果使用 MRC 开发,所有 返回 instancetype 的类方法,返回的对象都是 autorelease 的!
// 因为没有强引用,会被立即释放
self.p = [Person person];
// ARC中之所以为 null,是因为 weak,跟autorelease没有关系!
NSLog(@"%@", self.p);
// 之所以会这样是因为苹果框架的底层是用 MRC 写的,buttonWithType返回的对象是带有 autorelease
self.button = [UIButton buttonWithType:UIButtonTypeContactAdd];
NSLog(@"%@", self.button);
打印结果:
2015-03-25 11:00:58.756 10-ARC自动释放[27778:735123] (null)
2015-03-25 11:00:58.769 10-ARC自动释放[27778:735123] <UIButton: 0x7f96e9763af0; frame = (0 0; 22 22); opaque = NO; layer = <CALayer: 0x7f96e97668a0>>
autorelease
的,意味着会延迟销毁,仅仅是被添加到自动释放池而已,等待着出自动释放池作用域或者自动释放池销毁。而不会立刻销毁。问题:以下代码是否有问题?如果有,如何解决?
for (long i = 0; i < largeNumber; ++i) {
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"hello - %ld", i];
str = [str uppercaseString];
str = [str stringByAppendingString:@" - world"];
}
}
答案:如果 largeNumber 非常大,会创建太多自动释放的对象,有可能会把自动释放池"撑满" 提示:经常一次用户交互,远远不止一个 for,在 for 的前后,会有很多的代码,但是这个 for 会占用大量的自动释放池空间
引入自动释放池,网络上有两种解决方案!
1> 外面加自动释放池(快):能够保证for循环结束后,内部产生的自动释放对象,都会被销毁
需要等到 for 结束后,才会释放内存
2> 里面加自动释放池(慢):能够每一次 for 都释放产生的自动释放对象!
提问:那种方式效率高!速度差不多!大多数测试内部比外部外!
如果面试中问道:要说里面的略快,“亲测”!!!
提示:在日常工作中!有的时候,真的会出现代码内存飙升的情况!要知道解决办法!
设置largeNumner的数值:
long largeNumber = 5 * 1000 * 1000;
测试Demo:
NSLog(@"内部 start");
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
for (long i = 0; i < largeNumber; ++i) {
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"hello - %ld", i];
str = [str uppercaseString];
str = [str stringByAppendingString:@" - world"];
}
}
NSLog(@"end - %f", CFAbsoluteTimeGetCurrent() - start);
[self answer1];
answer1方法:
NSLog(@"外面 start");
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
@autoreleasepool {
for (long i = 0; i < largeNumber; ++i) {
NSString *str = [NSString stringWithFormat:@"hello - %ld", i];
str = [str uppercaseString];
str = [str stringByAppendingString:@" - world"];
}
}
NSLog(@"end - %f", CFAbsoluteTimeGetCurrent() - start);
测试结果:
2015-03-25 11:18:50.663 12-自动释放池的面试题[28015:743360] 内部 start
2015-03-25 11:19:03.996 12-自动释放池的面试题[28015:743360] end - 13.332371
2015-03-25 11:19:03.996 12-自动释放池的面试题[28015:743360] 外面 start
2015-03-25 11:19:18.227 12-自动释放池的面试题[28015:743360] end - 14.230752
由测试结果可以知道,对于500w次循环,内部、外部添加autorelease,速度其实差不多,内部略微快一点,但这是取决于编译器。 但是,在外部添加autorelease会占用极大的内存(注意,这里跟不加autorelease不一样,不加autorelease开辟的内存是不会释放的)。 开发中,通常在内部添加。
原文:http://blog.csdn.net/u010590318/article/details/44629341