ios中strong和weak的区别

ios中strong和weak的区别,第1张

首先strong和weak这两个关键字是用来修饰变量,表示这个变量是强(strong)引用禅誉和弱(weak)引用

我们在程序中经常会用到“[[class alloc]init]” 这样的代码,我想你对它已经很熟。这是在开辟一块内存,并初始化。那么系统开辟了档孙这块内存,我们怎么去拿到它呢?

显然是将刚分配好的内存赋值到一个变量,以后我们就可以利用这个变量直接 *** 作这块内存了。那么把刚分配的内存赋值给一个strong变量和weak变量是有区别的:

赋值给weak变量后这块内存会马上被释放。而分配给strong变量的会等到这个变量的生命周期结束后,这块内存才被释放(不用关键字weak修饰的变量默认为strong变量)。

看下面的例子:

添加一个Person类,只有一个name属性

[objc] view plain copy

@interface Person : NSObject

@property(nonatomic,copy) NSString *name

@end

main函数中定义了一个weak的zhangSan和一个strong的李四,很明显zhangSan指定的内存在“zhangSan=[[Person alloc]init]”执行后就立即被释放了。我们分别打印出两个变量的地址和name属性,可以看到zhangSan的确被释放了,而liSi一直到程序的结尾。

[objc] view plain copy

int main(int argc, const charchar * argv[]) {

@autoreleasepool {

__weak Person* zhangSan=[[Person alloc]init]

zhangSan.name=@"张三"

Person *liSi=[[Person alloc]init]

liSi.name=@"李四"

NSLog(@"%p----%p",zhangSan,liSi)

NSLog(@"%@----%@",zhangSan.name,liSi.name)

}

return 0

}

我们可以这样理解,分配出来的内存像一头牛,得用一条结实、强壮(strong)的绳子才能把它牵住,用纤细、弱小(weak)的绳子的话,这头牛随时会把绳子挣断逃脱。行袭链

而绳子的另一端是被固定到我们能够看得见够得着的物体(就是我们的变量)上面,我们顺着这个物体上面的绳子摸索过去,你的那头牛还在不在就看你用的上面绳子了。

那既然weak类型的变量内存分配出来就被释放了,它还有什么用呢?我们再看下面的例子

先将分配好的内存赋值给一个strong变量,然后再将这个strong变量赋值给一个weak变量,这样两个Person的地址都一样,显然name属性也一样。这样就好比先用结实的绳子拴住牛,这样牛就不会跑了,然后在用一根弱小的绳子拴住这头牛,这样顺着这根弱小的绳子也能找到这头牛。很明显如果当我们把结实的绳子弄断时,弱小的绳子自然也拉不住这头牛了。比如下面的例子:

“liSi”声明在一对大括号内,表明它只在大括号内有效,除了大括号,这个拴绳子的物体就不在了,那么牛自然挣脱弱小绳子的束缚跑掉,所以你再拿到“wangWu”想找到那头牛(内存及内存中的值)就不可能了。那如果有多条结实的绳子拴住牛,想必你也知道是怎么回事了。

用两条结实的绳子拴住一头牛,即使一根不在了,利用另一根还是能找到这头牛。

说到这里其实也没有说到weak类型的变量这种机制到底有什么用,我们看下面的例子

1.自定义一个VIew继承自UIView,重写dealloc方法,查看对象什么时候被销毁

[objc] view plain copy

#import "myView.h"

@implementation myView

-(void)dealloc

{

NSLog(@"对象被销毁")

}

@end

2.我们在程序要主视图的时候,将自定义视图添加到主视图上,并且添加按钮,监听点击事件。

[objc] view plain copy

- (void)viewDidLoad {

[super viewDidLoad]

//创建自定义view

myView *view=[[myView alloc]init]

view.frame=CGRectMake(50, 50, 200, 200)

view.backgroundColor=[UIColor redColor]

UILabel *msgLabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 20)]

msgLabel.text=@"这是一个视图"

[view addSubview:msgLabel]

//添加到视图

[self.view addSubview:view]

//添加按钮

UIButton *btn=[[UIButton alloc]initWithFrame:CGRectMake(100, 260, 100, 80)]

[btn setTitle:@"移除子视图" forState:UIControlStateNormal]

[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]

[btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside]

[self.view addSubview:btn]

}

-(void)btnClick

{

NSLog(@"点击了按钮")

}

我想要的效果是:点击按钮移除 子视图 ,并且程序以后的运行永远也不会用到这个view。

这里我想到有两种方式拿到这个view,然后从父控件中移除它,

第一种:这种方式显然能实现这样的要求,我们能看到打印结果,在子视图被移除父控制器之后对象也被销毁了。然而这不是我们最常用的方式,有可能父控件上有很多子视图,这样效率很低,而且代码不简洁。

[objc] view plain copy

-(void)btnClick

{

for (UIView *subView in self.view.subviews) {

if ([subView isKindOfClass:[myView class]]) {

[subView removeFromSuperview]

}

}

NSLog(@"点击了按钮")

}

第二种:我们给控制器增加一个属性,指向我们的子视图。这个属性有两种可能,一种是strong,一种是weak。我们先来试试strong。

从结果可以看出,点击按钮子视图是移除了,但是对象没有被销毁。它仍然在内存中(你可以再添加一个按钮打印一下self.testView试试),这不是我们想要的效果。

我们在来试试weak,只需要将声明变量的地方的strong改为weak即可,其他地方不变。从运行结果可以看出:子视图被移除了,且变量被销毁了。

为什么我们没有添加strong属性的时候分配出来的内存没有被释放,仍然能通过for循环找到它?需要注意的是:当一个视图A被添加到另一个视图B时,A就被B的subViews强引用了(有一个结实的绳子拉着它了),所以我们再用一个强属性去拉着它的话,自然要两条绳子都断了,它才会被释放。

也许现在你对strong和weak又对一点了解了

1、strong表示指向并拥有该对象。其修饰的对象引用计数会增加1。该对象只要引用计数不为0则不会被销毁。当然强行将其设为nil可以销毁它。

strong表示对一块内存强引用,当strong类型的指针指向一块内存,这块内存的引用计数就加1,相反则减1。当一块内存的引用计数为0时则销毁这块内存。

2、weak表示指向但不拥有该对象。其修饰的对象引用计数不会增加。无需手动设置,该对象会自行在内存中销毁。

weak表示一个指针对一块内存进行弱引用。弱引用就是不增加所指向内存的引用计数。

3、assign主要用于修饰基本数据类型,如NSInteger和CGFloat,这些数值主要存在于栈上。不涉及内存管理,内存计数不变化,如果修饰对象类型的话会出现野指针或者EXC_BAD_ACCESS错误。

4、weak 一般用来梁扒芹修饰对象,assign一般用来修饰基本数据类型。原因是assign修饰的对象被释放后,指针的地址依然存在,造成野指针,在堆上容易造成崩溃。而栈上的内存系统会自动处理,不会造成野指针。

5、copy与strong类似。不同之处是strong的复制是多个指针指向同一个地址,而copy的复制每次会在内存中拷贝一份对象,指针指向不同地址。copy一般用在修饰有此此可变对应类型的不可变对象上,如NSString, NSArray, NSDictionary。

6、@property 这个关键词的唯一作用就是声明getter、setter方法接口

7、@synthesize 实现setter、getter方法,找不到实例变量则主动创建一个

8、@dynamic 语义是用户要求自动生成setter getter方法,系统不会自动生成,所以此时调用setter或getter方法会crash,编译不报错(oc的动态绑定机制),而且调用对应的实例变量会报错

9、atomic 默认属性。当前进程进行到一半,其他线程来访问当前线程,可以保证先执行完毕当前线程。只是保证setter/getter完整,不是线程安全。atomic修饰的设值、取值方法使用了自旋锁,确保线程同步。虽然设值、取值方法是原子 *** 作,但不代表是线程安全。

10、nonatomic 非默认属性。两个线程同时访问同一个属性将会导致无法预计的结果。优点是程序运行速度快。

11、橡毕unsafe_unretained类型指针指向一块内存时,内存的引用计数也不会增加,这一点与weak一致。但是与weak类型不同的是,当其所指向的内存被销毁时,unsafe_unretained类型的指针并不会被赋值为nil,也就是变成了一个野指针。对野指针指向的内存进行读写,程序就会crash。

浅拷贝即指针拷贝,

深拷贝不但拷贝了对象的指针,还在系统中在分配了一块内存用来存放拷贝对象的内容


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12294519.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存