为什么 iOS 开发中,控件一般为 weak 而不是weakself strongself

为什么 iOS 开发中,控件一般为 weak 而不是 strong_百度知道/ask/questions/show/108308
ARC提供四种所有权修饰符:
unsafe_unretained
autoreleasing
其中前三个可以用于属性中声明所有权。对于这三个用于属性声明的修饰符,下面分别讲讲他们对应的使用场景。
strong与之前的retain差不多,可以增加属性引用计数的值。在不需要的时候,需要手动设置属性为nil。
weak是iOS5及以上才支持的修饰符。它被称为“归零弱引用”。可以只是持有指针而不增加引用计数来避免循环保留。当指针指向的内存被销毁后,声明weak的属性指针会自动置为nil,这也是它被称为归零弱引用的原因。
3.unsafe_unretained
对于iOS5以下版本,并不支持ARC中的weak声明,可以用unsafe_unretained声明来代替weak。unsafe_unretained同样也是不增加引用计数的值,但它没有“归零”的动作,需要手动操作,一般作为支持iOS5以下weak的替代方案。
解释了3种属性的意义,下面说说对于属性声明为IBOutlet时3种所有权修饰符的取舍以及使用技巧。
由于我自己很熟悉Interface Bulider中的操作,所以非常喜欢那种拉控件然后连线并直接声称属性代码的操作。对于直接从xib或者storyboard拉出来生成的IBOutlet属性,一般是选择strong还是weak呢?
这里有个原则:
如果该控件位于控件树的顶部,比如UIViewController下的view,那就应该选择strong,因为viewcontroller直接拥有该view。例如右图中的View。
而如果控件是viewcontroller中view的子视图,对于这个子视图,它的所有者是它的父视图,代码中只是想引用一下这个子视图的指针而已,那么就应该选择weak(iOS5以下选择unsafe_unretained)。例如左图中的UILabel。
对于以上的概念,我用一张图表来说明:
最后一句,记忆规则,理解规则,善用规则。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:83301次
积分:1446
积分:1446
排名:千里之外
转载:291篇
(3)(5)(4)(4)(1)(2)(2)(2)(12)(32)(8)(21)(14)(23)(66)(72)(24)为什么苹果建议使用weak属性连接IBOutlet,而在xcode storeboard设计时连接时IBOutlet默认采用strong属性呢?
注意我拖放了一个输出口默认它是strong.
苹果也没有完全建议用weak qualifier。当那些本来不在你的view hierarchy里(例如,你的view在nib里不是一个subview),或者你想那个view离开了view hierarchy后仍可以不被销毁的话,应该用strong。详细可以参考一下文档。但其实所有用strong的话也没有什么错,只是有点多余而已。所以,weak和strong都是有存在的可能的。对于”默认是strong“这个问题,估计算是一个考虑不周到吧。我将主要那部分摘抄下来了,From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create should will therefore typically be weak by default, because:Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).
如果你想让框架在内存紧张时自动释放视图,然后需要时自动加载,就用weak。不然你就要在viewDidUnload里面自个把视图放了。不过viewDidUnload新版给去掉了。。。如果用weak,你还需要考虑view为空时候的处理,有时候系统会把视图释放掉,会有一些莫名其妙的视图nil问题(内存原因产生的)。
已有帐号?
无法登录?
社交帐号登录iOS开发中weak和strong的用法和错误示例 - 简书
下载简书移动应用
写了1754字,被0人关注,获得了3个喜欢
iOS开发中weak和strong的用法和错误示例
以下是ViewController中的两个方法,大家觉得有没有问题呢?
- (void)removeRect {
@weakify(self);
//动画执行三秒后删除视图
[UIView animateWithDuration:3 animations:^{
@strongify(self);
self-&_rect.center = CGPointMake([UIScreen mainScreen].bounds.size.width + self-&_rect.center.x, self-&_rect.center.y);
} completion:^(BOOL finished) {
@strongify(self);
[self-&_rect removeFromSuperview];
self-&_rect =
- (void)testPrint2 {
if (!self-&_printBlock) {
@weakify(self);
self-&_printBlock = ^{
@strongify(self);
NSLog(@"self.name = %@", _name);
NSLog(@"self.title = %@", self.title);
self-&_printBlock();
没错编译的时候不会出错误,但是运行的时候第一个方法可能会导致crash,第二个方法会导致循环引用
大家在iOS开发中无可避免的会使用到weak和strong这两个关键字,说的简单就是弱引用和强引用,但是当你没有真正搞清楚怎么用的时候就可能在使用中有一些困扰,本篇文章着重讲述weak和strong的使用场景和基本原理,至于oc底层的语言级别的实现原理这里不作阐述(底层原理请自行度娘),请注意文中的代码都是ARC模式下的,大伙儿和大神们如果有更多的见解欢迎拍砖回复。
一. weak和strong语法使用
1.使用weak在定义属性的地方修饰属性,表示对该属性赋值(obj.property1=newValue)的时候不会对newValue进行retain,引用计数不会增加,并且当所引用的对象newValue=nil的时候该属性也将自动置为nil。
@property (nonatomic, weak) NSString *property1;
2.使用strong在定义属性(object type)的地方修饰属性,表示对该属性赋值(obj.property2=newValue)的时候会对newValue进行retain,引用计数增加1。对于对象类型(object type)的属性,strong是默认的缺省值。
@property (nonatomic, strong) NSString *property2;
// 等价于 @property (nonatomic) NSString *property2;
3.使用__weak在定义变量的时候用来修饰变量,表明对该变量进行赋值(tempName1 = newValue)的时候不会对newValue进行retain,引用计数不会增加,并且当所引用的对象newValue=nil的时候该变量也将自动置为nil。
__weak NSString *tempName1;
tempName1 = newV
4.使用\strong在定义变量(object type)的时候用来修饰变量,表明对该变量进行赋值(tempName1 = newValue)的时候会对newValue进行retain,引用计数会增加1。对于对象类型(object type)的变量,strong是默认的缺省值。
__strong NSString *tempName2; // 等价于 NSString *tempName2;
tempName2 = newV
二. 在开发中weak和strong使用的场景
1. 使用weak打破属性的循环引用
在2个对象相互之间的属性可能相互是对方的话,可能会引发循环引用而导致这2个对象都不能被释放,这时候只要把其中一个对象的属性用weak修饰即可打破可能的循环引用;
使用场景a:两个对象有从属关系,例如班级和学生,班级拥有学生的引用,学生拥有班级的引用;
使用场景b:两个对象是代理和被代理的关系,iOS开发中的代理模式就是如此,例如UITableView类中的代理属性
@property (nonatomic, weak, nullable) id&UITableViewDataSource& dataS
@property (nonatomic, weak, nullable) id&UITableViewDelegate&
2. 使用__weak打破block的循环引用
在调用block的时候是采用copy的方式,所以block的外部变量都会被copy,所以引用计数会+1。如果一个对象object对某个block持有引用,并且这个block中又使用了这个object那么就会造成循环引用,就会导致这个对象无法释放,这时候只需要在block外部重新定义一个采用__weak修饰的变量,这个变量指向object,然后在block里面使用这个新定义的变量即可。
- (void)testPrint1 {
if (!self-&_printBlock) {
self-&_printBlock = ^{
NSLog(@"self.name = %@", self.name);
self-&_printBlock();
- (void)testPrint2 {
if (!self-&_printBlock) {
__weak typeof(self) wself =
self-&_printBlock = ^{
NSLog(@"self.name = %@", wself.name);
self-&_printBlock();
上述方法testPrint1会引起循环引用,testPrint2的block中使用了__weak修饰的变量wself所以不会出现循环引用;
3. 在block中使用\strong用来保证\外部weak的一致性
block是objc语言一个很棒的特性,在实际的开发当中block的使用场景会很多也可能会很复杂,有一点要关注的是,虽然我们使用\weak解决了循环引用的问题,但也正是因为使用了\weak所以这个\weak变量可能随时被释放掉,如果block中多次使用weak,就有可能出现一开始有值,中途\weak变量被释放,导致后续使用\weak变量会出错,这时候可以在block内部最开始的地方定义一个\strong的变量,这个\strong变量指向外部定义的\__weak变量;
- (void)testPrint3 {
if (!self-&_printBlock) {
__weak typeof(self) wself =
self-&_printBlock = ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
wself.name = @"testPrint3";
NSLog(@"self.name = %@", wself.name);
[NSThread sleepForTimeInterval:10];
NSLog(@"self.name = %@", wself.name);
self-&_printBlock();
- (void)testPrint4 {
if (!self-&_printBlock) {
__weak typeof(self) wself =
self-&_printBlock = ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__strong typeof(wself) sself =
sself.name = @"testPrint4";
NSLog(@"self.name = %@", sself.name);
[NSThread sleepForTimeInterval:10];
NSLog(@"self.name = %@", sself.name);
self-&_printBlock();
当testPrint3执行以后,会立即打印出self.name = testPrint3,此时如果self如果释放,第二句打印将会是self.name = (null);而执行testPrint4则不会,它会等block执行完以后才释放,里面的那一句__strong typeof(wself) sself = self;保证了整个block中一直被强引用而不会释放;
所以很多情况下我们使用block的时候都会采用\weak和\ strong成对出现,因为使用的比较多所以RAC库中作者为我们准备了一个宏定义,在库中的RACEXTScope.h头文件中,我们可以以最快的方式书写上述语句,而且支持多个对象;
上面代码可以改写为如下:
@weakify(self);
self-&_printBlock = ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@strongify(self);
self.name = @"testPrint4";
NSLog(@"self.name = %@", self.name);
[NSThread sleepForTimeInterval:10];
NSLog(@"self.name = %@", self.name);
三. 容易出现的错误或者被忽视的使用方式
1. 滥用\weak+\strong
~请看下面代码:
- (void)removeRect {
@weakify(self);
[UIView animateWithDuration:3 animations:^{
@strongify(self);
self-&_rect.center = CGPointMake([UIScreen mainScreen].bounds.size.width + self-&_rect.center.x, self-&_rect.center.y);
} completion:^(BOOL finished) {
@strongify(self);
[self-&_rect removeFromSuperview];
self-&_rect =
点击界面中的一个按钮,会让界面中的一个rect做动画,这时候让界面返回上一级,该动画立即会终止,并执行completion的block,但是这时候self指针已经为nil,调用一个nil指针的成员变量会怎样,会EXC_BAD_ACCESS,(当然把代码中的self-&_rect改为self.rect就不会报错了)
所以总结起来:\weak+\strong虽然可以应对大多数情况(看起来是万能的呀),但是我们每次使用block的时候还是得自己注意,不要一股脑都写上\weak+\strong,需要使用的时候才使用,有很多情况下本身就是需要block中强引用外部变量,以达到block执行完之后才可以去释放外部变量的目的,这时候你使用\weak+\strong反而是多余的。
2. 使用@weakify(self)和@strongify(self)宏的时候block中使用类成员变量_var前面没有使用self-&前缀
~使用RAC这对宏确实可以省去不少编码时间,但是RAC的这对宏对block中类似“_var.age = 88"的代码并不起作用,因为@strongify(self)宏仅仅是在block内部定义了一个和self一样的名称的变量,所以如果没有写成self-&_var这种样式,编译器应该会认为是外部的self指针,从而对外部self有强引用,极易导致让你莫名的循环引用;
- (void)testPrint2 {
if (!self-&_printBlock) {
@weakify(self);
self-&_printBlock = ^{
@strongify(self);
// 会引起循环引用,将_name 改为 self-&_name即可;
NSLog(@"self.name = %@", _name);
NSLog(@"self.title = %@", self.title);
self-&_printBlock();
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
如果你是程序员,或者有一颗喜欢写程序的心,喜欢分享技术干货、项目经验、程序员日常囧事等等,欢迎投稿《程序员》专题。
专题主编:小...
· 180518人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:为什么 iOS 开发中,控件一般为 weak 而不是 strong?
按时间排序
问一下,对于这种情况:@property(nonatomic,weak) UIButton *
_button = [[UIButton alloc]init];
// 这里注释掉_btn =
[self.view addSubview:_btn];
对于这种情况为什么_btn还是被干掉了
上图,如果父控件view消灭后子控件是不会消灭的,因为强指But还指向But对象,如果强指But改成弱指,则view对象消灭后子控件But对象也一同消灭。要从合理性上理解。父对象view都已消灭了子对象But留在这世上也只是浪费内存,还不如给Arc收了。
不同控件,不同使用环境,都不一样的
初学iOS,刚看到控件的strong&weak问题,如果答的如果不对还请指正。首先有一点,在OC中,如果对象没有强引用,就会被自动释放,那么为什么控件还可以设为weak?1. 从storyboard或者xib上创建控件,在控件放在view上的时候,已经形成了如下的引用关系,以UIButton为例:UIViewController-&UIView-&subView-&UIButton然后你为这个UIButton声明一个weak属性@property(nonatomic,weak) IBOOutlet UIButton *btn;
相当于xib/sb对这个Button是强引用,你声明的属性对它是弱引用。2.手动创建控件a). 将控件声明成strong@property(nonatomic,strong) UIButton *btn;
那么你在实现这个控件时只需这样:_btn = [[UIButton alloc]init];
[self.view addSubview:_btn]
b). 将控件声明成weak@property(nonatomic,weak) UIButton *
那么你在实现这个控件时需要这样:UIButton *button = [[UIButton alloc]init];
[self.view addSubview:_btn];
============================最近看的黑马iOS视频上给的建议的是:1.如果用Stroyboard拖线,用weak2.如果自定对象,用strong(但我还是习惯用weak暂时=_=)其实不管声明的属性是强引用还是弱引用,在控制器消失的时候,这个属性消失,View消失,subViews消失,控件也就消失了。=============================之前专门搜过相关的问题,贴上来:IBOutlet的属性一般可以设为weak是因为它已经被view引用了,除非view被释放,否则IBOutlet的属性也不会被释放,另外IBOutlet属性的生命周期和view应该是一致的,所以IBOutlet属性一般设为weak。可参考如下:From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create will therefore typically be weak by default, because:Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).简单的说,如果IBOutlet对象是nib/sb scene的拥有者(File’s owner)所持有的对象,那么很显然拥有者必须“拥有”对象的指针,因此属性应设置为strong。而其他的IBOutlet对象的属性需要设置为weak,因为拥有者并不需要“拥有”他们的指针。举例来说,UIViewController的view属性是strong,因为controller要直接拥有view。而添加到view上的subviews,作为IBOutlet只需要设置为weak就可以了,因为他们不是controller直接拥有的。直接拥有subviews的是controller的view,ARC会帮助管理内存。紧接着,又提到:Outlets should be changed to strong when the outlet should be considered to own the referenced object:As indicated previously, this is often the case with File’s Owner—top level objects in a nib file are frequently considered to be owned by the File’s Owner.You may in some situations need an object from a nib file to exist outside of its original container. For example, you might have an outlet for a view that can be temporarily removed from its initial view hierarchy and must therefore be maintained independently.第一种情形前面已经解释过了,对于第二种,通俗点将,就是controller需要直接控制某一个subview并且将subview添加到其他的view tree上去。单纯从ARC的角度思考,用weak也是很显然的:因为subview添加到view上时,view会“拥有”subview。当然,给IBOutlet属性设置为strong也没有错,“纠结谁对谁错“的问题可能需要上升到模式或者编码习惯的问题,已经超出本文的范围。
因为控件他爹( view.superview )已经揪着它的小辫了( strong reference ),你( viewController )眼瞅着( weak reference )就好了。当然,如果你想在 view 从 superview 里面 remove 掉之后还继续持有的话,还是要用 strong 的( 你也揪着它的小辫, 这样如果他爹松手了它也跑不了 )。
已有帐号?
无法登录?
社交帐号登录

我要回帖

更多关于 ios strong weak 的文章

 

随机推荐