浅析objective-c中的strong和weak

2024-06-22 13:08
文章标签 浅析 objective strong weak

本文主要是介绍浅析objective-c中的strong和weak,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


在才开始学习oc时,搞不懂什么时候用strong,什么时候用weak,经过一段时间的学习,我谈谈我对strong和weak的理解。

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

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

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

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


看下面的例子:

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

@interface Person : NSObject
@property(nonatomic,copy) NSString *name;
@end

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

int main(int argc, const char * 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方法,查看对象什么时候被销毁

#import "myView.h"@implementation myView-(void)dealloc
{NSLog(@"对象被销毁");
}@end

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

- (void)viewDidLoad {[super viewDidLoad];//创建自定义viewmyView *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,然后从父控件中移除它,

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

-(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又对一点了解了

这篇关于浅析objective-c中的strong和weak的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1084373

相关文章

浅析std::ref

目录 1 为什么需要std::ref 2 std::ref使用示例 2.1 std::thread调用 2.1.1 不使用std::ref,编译失败 2.1.2 使用std::ref修饰输入变量 2.2 stl库调用(以for_each 为例) 2.3 std::bind 2.3.1 使用std::ref 2.3.2 使用placeholders::_x同样可以达到同样效果 3

SQL--浅析,开窗函数,聚合开窗函数,排序开窗函数。

作为一名开发人员来讲,我感觉在职场白混了好多年,可能是自己真的没有进取的精神吧,看了《程序员的SQL金典》这本电子书,真的让我学到了不少知识,真心喜欢这本电子书,书中讲解的内容比较好懂,也比较实用。谢谢作者的辛勤汗水:)。 今天将要介绍SQL Sever的开窗函数,何谓开窗函数,不懂吧。反正对于我来说,我是摸不着头脑了,第一次听说过。那么,什么是开窗函数,其实可以理解为是聚合函数的一个加强版

Xamarin.iOS使用Objective-C静态类库.a(Linking Native Libraries)

Xamarin静态类库的binding实际上是一个C#与Objective-C方法间映射过程,由于第三方SDK对iOS开发至关重要,因此官方文档中也对这块也做了完整的介绍(Binding Objective-C Libraries),但对于一个完全入门级的程序员来说,这块还是有诸多麻烦,并且部分Api类型文档上也未曾提到。下面将以百度地图作为案例,全面解析静态类库binding工程的知识与问题

浅析遗传算法

1 初探遗传算法   Ok,先看维基百科对遗传算法所给的解释: 遗传算法是计算数学中用于解决最优化的搜索算法,是进化算法的一种。进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择以及杂交等。   遗传算法通常实现方式为一种计算机模拟。对于一个最优化问题,一定数量的候选解(称为个体)的抽象表示(称为染色体)的种群向更好的解进化。传统上,解用二进制表示

linux中Java程序调用C程序中方法的实现方式浅析

在Linux中,Java程序可以通过JNI(Java Native Interface)来调用C程序的方法。 Linux系统环境,Java调用C的主要流程如下: 1、创建Java类文件,如NativeLibrary.java 2、编写Java代码,加载.so共享库(C程序生成该名称的.so共享库),并声明本地方法 3、使用javac编译Java类,生成.class文件 4、使用java

【Android】我的手机在...自己下载...那个(浅析Intent基础运用)

【Android】我的手机在…自己下载…那个(浅析Intent基础运用) 在Android开发中,Intent(意图)是一个非常重要的概念。它不仅仅是用于在应用程序的各个组件之间进行通信的工具,也是启动新的Activity、Service,或者广播信息的关键机制。本文将深入探讨Intent的作用、类型以及使用方法。 什么是Intent? 简单来说,Intent是一种消息对象,用于在应用程序的

一类带观测传感器延时修正(时间同步)的融合算法举例浅析(节选至售后群问答回复)

一类带观测传感器延时修正(时间同步)的融合算法举例浅析(节选至售后群问答回复) 2018年6月13日  无名小哥  交流群:540707961 可以设想一个场景,比如你工资是一个日结制,每天下午5点半下班,这个钱每天晚上6点钟会打到你这个银行卡上,但实际到账的话,是会到第二天晚上6点,你的工资卡归你老婆管,家庭日常开支、理财、利息等都来自此卡。 你每天下午7点都会对你的卡上总财富进行估计,因

关于B/S模式的web服务交互过程中的中文乱码问题浅析

Web服务是服务端和浏览器之间的交互,两者之间因为中文编码的问题很容易导致乱码出现。 站在服务端(servlet)角度,乱码分成两种接收请求(request)和响应浏览器(response)。 有关乱码的问题主要是下图中的四个组件之间的引起的。 (1)request请求产生的乱码: 乱码产生的大概原理: 解决思路就是:IE浏览器和request的编码方式要一致。 因

调度系统浅析

1、struct sched_class 调度类有四种,按照优先级依次为:stop_sched_class、rt_sched_class、fair_sched_class、idle_sched_class   2、Scheduling policies #define SCHED_NORMAL  0 #define SCHED_FIFO  1 #define SCHED_RR  2 #de

CGROUP浅析

1、CGROUP数据结构分析 struct cgroup struct cgroupfs_root struct css_set struct cgroup_subsys cgroup:把一组任务和设定特定参数集的子系统资源组合起来; subsystem:利用cgroup的分组机制对待不同的任务组采用不同的对待机制,