如何避免循环引用造成的内存泄漏呢:

  以delegate模式为例(viewcontroller和view之间就是代理模式,viewcontroller有view的使用权,viewcontroller同时也是view的代理(处理view中的事件)):
  

  1. UserWebService.h
  2.   #import
  3.   //定义一个ws完成的delegate
  4.   @protocol WsCompleteDelegate
  5.   @required
  6.   -(void) finished;//需要实现的方法
  7.   @end
  8.   @interface UserWebService:NSObject
  9.   {
  10.   id delegate;//一个id类型的dategate对象
  11.   }
  12.   @property (assign) id delegate;
  13.   -(id)initWithUserData:(User *)user;
  14.   -(void)connectionDidFinishLoading:(NSURLConnection *)connection;
  15.   @end
  16.   UserWebService.m:
  17.   #import
  18.   @systhesize delegate;//同步这个delegate对象
  19.   @implementation UserWebService
  20.   -(void)connectionDidFinishLoading:(NSURLConnection *)connection
  21.   {
  22.   [delegate finished]
  23.   }
  24.   @end

  LoginViewController.h:
  

  1. #import "UserWebService.h" //包含含有委托的头文件
  2.   @interface LoginViewController:UIViewController
  3.   -(void)submit;
  4.   @end
  5.   LoginViewController.m:
  6.   @implementation LoginViewController
  7.   -(void) submit
  8.   {
  9.   User *user = [[User alloc]init];
  10.   [user setUserId:@"username"];
  11.   [user setPassword:@"password"];
  12.   ws = [[UserWebService alloc] initWithUserData:user];
  13.   ws.delegate = self;//设置委托的收听对象
  14.   [user release];
  15.   [ws send];
  16.   }
  17.   //实现委托中的方法,
  18.   -(void) finished
  19.   {
  20.   NSAttry *users = [ws users];
  21.   }
  22.   @end


  可以看到,delegate声明为assign:
  

  1. @property (assign) id delegate;

复制代码

  如果声明为retain会如何?
  

  1. LoginViewController alloc了一个UserWebService,UserWebService的代理又是LoginViewController,这样就循环引用了:
  2.   ws = [[UserWebService alloc] initWithUserData:user]; //UserWebService对象引用计数加1
  3.   ws.delegate = self;//LoginViewController对象引用计数加1

  外部框架allocLoginViewController对象后,LoginViewController对象的引用计数为2 ,release后还是无法销毁,产生内存泄漏

  所以用assign而不是retain声明属性可以避免循环引用,ARC下用弱引用也可以解决

  内存检测可以用xcode继承的instrument工具,不过循环引用引起的内存泄露是检测不出来的

  对象release到引用计数为0后,如果对应指针没有赋值为nil,怎出现野指针
  

  1. ClassA *a = [[ClassA alloc] init];

  a = nil;//alloc的内存没有任何对象可以控制它了,引用计数永远为1,这就造成了内存泄露

  简单的赋值操作并不会改变对象的引用计数:
  

  1. ClassA *a = [[ClassA alloc] init];
  2.   ClassA *b = a;//a和b指向的对象的引用计数还是1

  @property

  默认为@property为@property(atomic,assign)

  nonatomic: 没有对应的atomic关键字,即使上面是这么写,但atomic叧是在你没有声明这个特性的时候系统默认,你无法主动去声明这一特性。nonatomic不支持多线程访问,atomic有同步机制,支持多线程访问,如果需要多线程访问,声明为atomic(维持默认),否则声明为nonatomic,因为nonatomic效率比atomic高得多

  关于assign、retain和copy: assign是系统默认的属性特性,它几乎适用亍OC的所有变量类型。对于非对象类型的变量,assign是唯一可选的特性。但是如果你在引用计数下给一个对象类型的变量声明为assign,那么你会在编译的时候收到一条来自编译器的警告。因为assign对于在引用计数下的对象特性,叧创建了一个弱引用(也就是平时说的浅复制)。返样使用变量会很危险。当你release了前一个对象的时候,被赋值的对象指针就成了无头指针了。因此在为对象类型的变量声明属性的时候,尽量少(或者不要)使用assign。

  关于assign合成的setter,看起来是这样的:
  

  1. -(void)setObjA:(ClassA *)a {
  2.   objA = a;
  3.   }


  在深入retain之前,先把声明为retain特性的setter写出来:
  

  1. -(void)setObjA:(ClassA *)a
  2.   {
  3.   If(objA != a)
  4.   {
  5.   [objA release];
  6.   objA = a;
  7.   [objA retain]; //对象的retain count 加1
  8.   }
  9.   }


  明显的,在retain的setter中,变量retain了一次,那么,即使你在程序中 self.objA = a; 只写了这么一句,objA仍然需要release,才能保证对象的retain count 是正确的。但是如果你的代码 objA = a; 叧写了这么一句,那么这里只是进行了一次浅复制,对象的retain count 并没有增加,因此这样写的话,你不需要在后面release objA。 这2句话的区别是,第一句使用了编译器生成的setter来设置objA的值,而第二句叧是一个简单的指针赋值
  

  1. NSString *str = [[NSString alloc] initwithstring @“abc”];
  2.   str = @“abcd”;‘
  3.   [str release];
  4.   NSLog("%@",str);//打印出abcd


  str为什么没有变成野指针呢?因为字符串常量(包括NSString和@“......”)的引用计数很大(100K+),基本上不会释放掉(由OC自己管理),所以字符串常量可以不用release

iOS 循环引用 委托 (实例说明)的更多相关文章

  1. iOS循环引用

    iOS循环引用 当前类的闭包/Block属性,用到了当前类,就会造成循环引用 此闭包/Block应该是当前类的属性,我们经常对Block进行copy,copy到堆中,以便后用. 单方向引用是不会产生循 ...

  2. iOS 循环引用解决方案

    一.BLOCK 循环引用 一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身.构成循环引用. // 定义 block 的时候,会对外部变量做一次 cop ...

  3. iOS循环引用问题

    今天面试问道了循环引用,所以就看了看,原来只是知道使用了Block容易造成循环引用.今天就来简单的介绍一些循环引用. 先来简单介绍一下什么是循环引用? 循环引用可以简单的理解成:A对象引用了B对象,B ...

  4. iOS循环引用常见场景和解决办法

    好多场景会导致循环引用,例如使用Block.线程.委托.通知.观察者都可能会导致循环引用. 1.委托 遵守一个规则,委托方持有代理方的强引用,代理方持有委托方的弱引用. 实际场景中,委托方会是一个控制 ...

  5. iOS 循环引用

    1.循环引用一般是指:A持有B,B同时持有A,从而导致死循环无法释放对象. 2.一般循环引用出现在block和delegate中,而一般解决方法就是将self变成weakSelf(强引用变成弱引用), ...

  6. iOS 循环引用讲解(中)

    谈到循环引用,可能是delegate为啥非得用weak修饰,可能是block为啥要被特殊对待,你也可能仅仅想到了一个weakSelf,因为它能解决99%的关于循环引用的事情.下面我以个人的理解谈谈循环 ...

  7. 【转】iOS学习之容易造成循环引用的三种场景

    ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是——循环引用.循环引用可以简单理解为A引用了B,而B又引用了A,双方都同 ...

  8. 【原】iOS容易造成循环引用的三种场景,就在你我身边!

    ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是——循环引用.循环引用可以简单理解为A引用了B,而B又引用了A,双方都同 ...

  9. iOS容易造成循环引用的三种场景

    iOS容易造成循环引用的三种场景  ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是--循环引用.循环引用可以简单理解为 ...

随机推荐

  1. SSH上传和下载文件

    备个份: 一,ssh上传文件 scp file username@hostIP:文件地址 例: [zhangy@BlackGhost ~]$ scp test.sql zhangying@192.16 ...

  2. LoadRunner做性能测试 从设计到分析执行

    项目简介:像百度知道系统类似的系统性能测试,是公司的自己产品. 对最近这个系统的性能测试进行总结下: 系统功能介绍: 前台用户可以根据自己的需要对不同的区域提问,提问包括匿名和登陆用户提问 后台不同区 ...

  3. SpringBoot实战(四)之使用JDBC和Spring访问数据库

    这里演示的是h2databse示例,所以简单的介绍普及下h2database相关知识 H2数据库是一个开源的关系型数据库. H2是一个嵌入式数据库引擎,采用java语言编写,不受平台的限制,同时H2提 ...

  4. unity之UGUI屏幕分辨率調整

    1.Canvas的屬性配置: 2.Canvas Scaler的屬性配置: 3.根據不同的屏幕比例動態寫改碩放基準: public float standard_width = 800f; //初始宽度 ...

  5. Visual Studio快捷键大全

    快捷键的使用可以简化大家的操作,在一定程度上提高工作的效率,下文中将为大家介绍一些VS中经常用到的快捷键,希望对大家有用. 方法/步骤   关于解决方案和项目   用于快速跳转   用于代码的文本编辑 ...

  6. django时区设置(timezone)

    django时区设置(timezone): 默认: TIMEZONE:'America/Chicago'(以前的版本,现在的版本默认的都是UTC时间.) Chicago时间,为UTC/GMT -6 小 ...

  7. Java正则表达式的使用和详解(下)

    1.常用正则表达式 规则 正则表达式语法   一个或多个汉字 ^[\u0391-\uFFE5]+$  邮政编码 ^[1-9]\d{5}$ QQ号码 ^[1-9]\d{4,10}$  邮箱 ^[a-zA ...

  8. CentOS 7中添加一个新用户并授权

    Linux 创建web用户组及用户: groupadd www-data useradd -g www-data www-data 笔记本安装了一个CentOS,想要让别人也可以登录访问,用自己的账号 ...

  9. linux环境中通过useradd命令,创建用户的时候指定用户的base-dir

    需求说明: 今天一个同事,问了一个这样的问题,在linux环境中,创建用户的时候,默认的是在/home目录下创建一个与用户名相同的家目录, 如何能够将这个/home更换成一个其他的,比如/opt/ap ...

  10. SpringBoot------thymeleaf的使用

    1.pom.xml添加相应依赖 <dependency> <groupId>org.springframework.boot</groupId> <artif ...