zoukankan      html  css  js  c++  java
  • iOS 循环引用 委托 (实例说明)

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

      以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

  • 相关阅读:
    复旦大学数学学院18级高等代数II期中考试第七大题的三种证法及其推广
    复旦大学2019--2020学年第一学期高等代数I期末考试情况分析
    复旦大学2019--2020学年第一学期(19级)高等代数I期末考试第六大题解答
    复旦大学2019--2020学年第一学期(19级)高等代数I期末考试第七大题解答
    复旦大学2019--2020学年第一学期(19级)高等代数I期末考试第八大题解答
    复旦高等代数I(19级)每周一题
    复旦大学数学学院 18 级本科生对每周一题的评价
    复旦大学2018--2019学年第二学期高等代数II期末考试情况分析
    复旦大学2018--2019学年第二学期(18级)高等代数II期末考试第六大题解答
    CentOS7安装MySQL
  • 原文地址:https://www.cnblogs.com/DamonTang/p/3380193.html
Copyright © 2011-2022 走看看