精华内容
下载资源
问答
  • Objective-C - 循环引用问题

    千次阅读 2015-04-21 09:06:49
    循环引用问题/* 1.@class的作用:仅仅告诉编译器,某个名称是一个类 @class Person; // 仅仅告诉编译器,Person是一个类 2.开发中引用一个类的规范 1> 在.h文件中用@class来声明类 2> 在.m文件中用#import来包含...

    循环引用问题

    /*
     1.@class的作用:仅仅告诉编译器,某个名称是一个类
     @class Person; // 仅仅告诉编译器,Person是一个类
    
     2.开发中引用一个类的规范
     1> 在.h文件中用@class来声明类
     2> 在.m文件中用#import来包含类的所有东西
    
     3.两端循环引用解决方案
     1> 一端用retain
     2> 一端用assign
    
     */
    
    #import <Foundation/Foundation.h>
    #import "Card.h"
    #import "Person.h"
    
    int main()
    {
        // p - 1
        Person *p = [[Person alloc] init];
        // c - 1
        Card *c = [[Card alloc] init];
    
        // c - 2
        p.card = c;
    
        // p - 1
        c.person = p;
    
        // c - 1
        [c release];
    
        // p - 0  c - 0
        [p release];
        return 0;
    }
    #import "Card.h"
    // @class仅仅是告诉编译器,Card是一个类
    //@class Card;
    
    @interface Person : NSObject
    
    @property (nonatomic, retain) Card *card;
    
    @end
    #import "Card.h"
    
    @implementation Person
    
    - (void)dealloc
    {
        NSLog(@"Person被销毁了");
        [_card release];
    
        [super dealloc];
    }
    
    @end
    
    @class Person;
    
    @interface Card : NSObject
    
    @property (nonatomic, assign) Person *person;
    
    @end
    
    @implementation Card
    
    
    - (void)dealloc
    {
        NSLog(@"Car被销毁了");
    
        // [_person release];
    
        [super dealloc];
    }
    
    @end
    
    展开全文
  • Block原理浅析,循环引用的产生方式

    千次阅读 2018-10-28 22:44:31
    经常在一些面试题里面或者其他规范里面看到,block里面不能用self,否则会产生循环引用,但是为什么不能用self,循环引用什么,如何产生的循环引用,这些总是一知半解。带着问题,查询了一些资料了解了一部分产生...

    经常在一些面试题里面或者其他规范里面看到,block里面不能用self,否则会产生循环引用,但是为什么不能用self,循环引用是什么,如何产生的循环引用,这些总是一知半解。带着问题,查询了一些资料了解了一部分产生原因,在这做一下记录,以防自己忘掉了,如果有大神有不同意见,欢迎提出~~

    1.block的内部是什么样的?

    LLVM Block_private.h上block的定义如下:

    /* Revised new layout. */
    struct Block_descriptor {
        unsigned long int reserved;
        unsigned long int size;
        void (*copy)(void *dst, void *src);
        void (*dispose)(void *);
    };
    
    
    struct Block_layout {
        void *isa;
        int flags;
        int reserved; 
        void (*invoke)(void *, ...);
        struct Block_descriptor *descriptor;
        /* Imported variables. */
    };

    可以看出block的结构式Block_layout上的方式,实际上我们可以将它理解成为一个对象,通俗点说,一个block就是一个对象。

     

    2.block的捕获变量

    block会自动的捕获变量,例如:

    int i = 2;
    void (^bloc)(void) = ^{
        NSLog(@"%d",i);
    };

    创建的bloc会讲i的值拷贝到block中,就会生成如下的结构体:

    struct Block_layout_imp_bloc {
        void *isa;
        int flags;
        int reserved; 
        void (*invoke)(void *, ...);
        struct Block_descriptor *descriptor;
        /* Imported variables. */
    
        int i;
    };

    这里的i是一个只读变量,因此在block中i是不可以被修改的。

    如何才能让i值可以修改呢?就是在i的声明时加入__block的关键字,这样有会生成如下结构体,并且赋值到descriptor字段中:

    struct Block_descriptor_imp_i {
        unsigned long int reserved;
        unsigned long int size;
        void (*copy)(void *dst, void *src);
        void (*dispose)(void *);
    };

    这里可以大致理解为,加了__block修饰符之后,会生成一个i变量的指针,放入到了block的对象中

    3.循环引用是如何产生的

    既然前面要介绍block的捕获变量,肯定是和这个有关系的。先看下如下的代码:

    detailVC* dvc1 = [[detailVC alloc] init];
    void (^ bloc)(void) = ^(void){
        NSLog(@"%@",dvc1);
    };

    根据捕获变量的方法,bloc对象会将dvc1指针拷贝到对象中,这样bloc中就含

    有一个和dvc1指向地址相同的指针,因此dvc1指向的对象,引用计数器就会+1,这样就完成了bloc中包含有dvc1的引用,这样的话,如果bloc不被销毁,dvc1就不会被销毁。

    此时,如果我们将这个block当作成员变量保存在dvc1中,如下:

    dvc1.callback = bloc;

    那么dvc1中也有了bloc的引用,这样就导致了循环引用,这两个对象谁都销毁不掉。

    4.如何避免block导致的循环引用

    只要将一方的指针改为弱指针就可以,将detailVC类的callback成员变量加上weak关键字,或者添加如下操作:

    detailVC* dvc1 = [[detailVC alloc] init];
    __weak detailVC* dvc1w = dvc1;
    void (^ bloc)(void) = ^(void){
        NSLog(@"%@", dvc1w);
    };

    这样block拥有的dvc1的指针就是弱指针,不会影响到dvc1的销毁。

     

    写这个主要是为了自己的一些学习计划,还有时间长了有个地方方便看,因为技术有限,有什么不对的地方,还望大神们指出~~

     

    参考资料:

    https://blog.csdn.net/u014205968/article/details/64478360

    展开全文
  • 循环引用的处理

    千次阅读 2013-12-09 19:41:10
    C++编程过程中经常遇到循环引用,此时应该怎么解决这类问题呢?本文通过详细的例子介绍循环引用解决方法。

    循环引用:两个类互相引用,导致单纯互相引用头文件,编译无法通过。

    解决方案:

    首先,要理解声明和实现之间的差别。声明只需要在使用类的前面添加class ***,而实现是包含具体成员函数和变量的类。

    如例1.

    class A {
    ...
    private:
        B b;
    }
    
    class B {
    ...
    private:
        A a;
    }


    1. 此时可在A的前面声明class B,就可以使用B了。在B中只需要正常引用A的头文件和命名空间即可。修改后如例2;

    class B;
    class A {
    ...
    private:
        B b;
    }
    
    
    #include <A.h>
    
    using A;
    class B {
    ...
    private:
        A a;
    }


    2. 修改之后,还是会报错:forward declaration ...

    这是为什么呢?

    这个声明,有时候被称为前向声明(forward declaration),在程序中引入了类类型的Screen.在声明之后,定义之前,类Screen是一个不完全类型(incompete type),即已知Screen是一个类型,但不知道包含哪些成员.不完全类型只能以有限方式使用,不能定义该类型的对象,不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数.

    因此,修改如例3.

    class B;
    class A {
    ...
    private:
        B* b;
    }
    
    
    #include <A.h>
    
    using A;
    class B {
    ...
    private:
        A* a;
    }


    展开全文
  • Newtonsoft.Json的循环引用解决方案

    千次阅读 2018-08-31 11:37:22
    网上有很多关于Newtonsoft.Json循环引用的解决方案,比如设置循环引用为Ignore,这样在输出JSON时就不会输出。 var setting = new JsonSerializerSettings(); setting.ReferenceLoopHandling = ...

    网上有很多关于Newtonsoft.Json循环引用的解决方案,比如设置循环引用为Ignore,这样在输出JSON时就不会输出。

      var setting = new JsonSerializerSettings();
      setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
      var json = JsonConvert.SerializeObject(data, setting);

    但是这个结果不是我想要的。我想要的是循环引用的数据得保留,以便后面反序列化时能还原数据,所以将循环引用设置为序列化。

    setting.ReferenceLoopHandling = ReferenceLoopHandling.Serialize

    这样设置后,在将对象序列化成JSON时却报错了,查了很多资料,做了很多尝试,于是找到了一种解决办法,只要加一个PreserveReferencesHandling的设置,代码如下

      var data = GenerateData();
      var setting = new JsonSerializerSettings();
      setting.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
      setting.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
      var json = JsonConvert.SerializeObject(data, setting);

    序列化的结果如下

    成功序列化成了JSON数据,注意观察数据会发现多了$id的引用。成功之后,迫不急待的将JSON反序列化成对象,要记得使用序列化时同样的setting,否则会出错。

     var setting = new JsonSerializerSettings();
     setting.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
     setting.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
     var node = JsonConvert.DeserializeObject<Node>(json, setting);

    经过这样的设置后,基本上循环引用的序列化和反序列化算是解决了。但是把这个方式应用到项目的时候,又遇到坑了。首先就是接口的坑,因为反序列化时要执行构造函数,接口是没有构造函数的,而我们在做类的属性的时候常常会用到接口类型,那这样怎么整?又是查资料测试,后面找到了答案,需要增加如下设置

    setting.TypeNameHandling = TypeNameHandling.All;

    TypeNameHandling说是可以设置为Auto和All,设置为Auto则会自动判断,但可能不可靠,所以设置为All比较可靠。设置后的内容如下

    {
      "$id": "1",
      "$type": "JsonConvertTest.Node, JsonConvertTest",
      "Name": "根",
      "Parent": null,
      "Childs": {
        "$type": "System.Collections.Generic.List`1[[JsonConvertTest.Node, JsonConvertTest]], mscorlib",
        "$values": [
          {
            "$id": "2",
            "$type": "JsonConvertTest.Node, JsonConvertTest",
            "Name": "子1",
            "Parent": { "$ref": "1" },
            "Childs": null,
            "Description": null
          },
          {
            "$id": "3",
            "$type": "JsonConvertTest.Node, JsonConvertTest",
            "Name": "子2",
            "Parent": { "$ref": "1" },
            "Childs": null,
            "Description": null
          },
          {
            "$id": "4",
            "$type": "JsonConvertTest.Node, JsonConvertTest",
            "Name": "子3",
            "Parent": { "$ref": "1" },
            "Childs": null,
            "Description": null
          }
        ]
      },
      "Description": {
        "$id": "5",
        "$type": "JsonConvertTest.Description, JsonConvertTest",
        "Content": "测试内容",
        "Author": "张三"
      }
    }

    从结果中会看到多了$type的字段,该字段包含了具体的类型,这样在反序列化的时候就会依据该类型找到对应的类,然后执行反序化。有人会问了,为什么有了类型后接口就可以反序列化了?因为接口只是定义了类型,但具体存什么数据是代码运行得到的,存数据时虽然这是接口,但是存的是数据的具体类型,接口是没办法直接作为数据的,必须是实现接口的类,既然是类,那就必定会有构造函数的。

    对于接口的坑,抽象类也会有相似的坑。

    接口的坑填上了,原以为已经圆满解决了,谁知道有些不需要序列化的数据也执行了序列化,原因是JSON序列化时会自动把公有的属性、字段这些都执行序列化,但是有的数据是不能序列化的,比如程序内部运行时的控件类型。那要怎么办?

    一般的解决方案是把不要序列化的属性标识为JsonIgnore,如果是项目初期是可行的,可是项目已经进展到一定程度,要把每个属性都标识一遍是不太可能了。经分析后,发现因为另一种保存数据的需求而在项目中对要保存的属性和字段作了一个Attribute的标识,那就想这个标识能不能用起来呢?答案是可以的。

    这时我们要用到IContractResolver接口,直接实现这个接口有难度,我们可以继承已经实现该接口的DefaultContractResolver类,然后对该类中的一些方法进行重写。这里我们要重写的是CreateProperty方法,代码如下

     public class MyContractResolver : DefaultContractResolver
        {
            protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
            {
                
                var saveDataAttribute = member.GetCustomAttribute<SaveDataAttribute>();
                if (saveDataAttribute == null)
                {
                    return null;
                }
                else
                {
                    return base.CreateProperty(member, memberSerialization);
                }
            }
        }

    其中SaveDataAttribute是继承自Attribute的类,没有任何代码,只是继承了而已,主要是做标识用的。

      public class SaveDataAttribute : Attribute
        {
        }

    这样在标识有SaveDataAttribute属性的字段就会被输出到json中。要序列化的类如下。

     [SaveData]
    public class Node
        {
            /// <summary>
            /// 名称
            /// </summary>
            [SaveData]
            public string Name { get;private set; }
    
            /// <summary>
            /// 父
            /// </summary>
            [SaveData]
            public Node Parent { get; set; }
    
            /// <summary>
            /// 子
            /// </summary>
            [SaveData]
            public List<Node> Childs { get; set; }
    
            /// <summary>
            /// 描述
            /// </summary>
            public IData Description { get; set; }
    
            /// <summary>
            /// 内部数据
            /// </summary>
            public string InnerData { get; set; }
        }

    其中Description和InnerData没有被标识为SaveData,所以序列化的时候这两个字段并没有序列化,结果如下

    {
      "$id": "1",
      "$type": "JsonConvertTest.Node, JsonConvertTest",
      "Name": "根",
      "Parent": null,
      "Childs": {
        "$type": "System.Collections.Generic.List`1[[JsonConvertTest.Node, JsonConvertTest]], mscorlib",
        "$values": [
          {
            "$id": "2",
            "$type": "JsonConvertTest.Node, JsonConvertTest",
            "Name": "子1",
            "Parent": { "$ref": "1" },
            "Childs": null
          },
          {
            "$id": "3",
            "$type": "JsonConvertTest.Node, JsonConvertTest",
            "Name": "子2",
            "Parent": { "$ref": "1" },
            "Childs": null
          },
          {
            "$id": "4",
            "$type": "JsonConvertTest.Node, JsonConvertTest",
            "Name": "子3",
            "Parent": { "$ref": "1" },
            "Childs": null
          }
        ]
      }
    }

    经过这样的处理后,数据是正常序列化成JSON了,但是反序列化成对象的时候,发现有的数据为空,就像上面的Name的数据总是为空,追查原因,发现是因为属性的set方法标识成了private,所以导致反序列化的时候没有写入数据,那要怎么办呢?这个就要看具体的业务需求,我们是不管标识成private还是其他的,反序列化时一定要还原数据来,为此,我们需要让json库还原的时候知道这个字段是要可写的,于是我们回到了刚刚的CreateProperty方法,将其Writable、Readable都设置为true,代码如下

     protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
            {
                
                var saveDataAttribute = member.GetCustomAttribute<SaveDataAttribute>();
                if (saveDataAttribute == null)
                {
                    return null;
                }
                else
                {
                    var property= base.CreateProperty(member, memberSerialization);
                    property.Writable = true;
                    property.Readable = true;
                    return property;
                }
            }

    这样设置后,数据就正常还原了。但是在还原的时候又碰到了新的问题,有的类还是不能正常还原,会报构造函数错误。经查,是因为没有空参数的构造函数。这时需要将构造函数标识为JsonConstructorAttribute,这样JSON库在反序列化的时候就会调用该构造函数。

     [JsonConstructor]
            public Node(string name)
            {
                this.Name = name;
            }

    但是这样处理后,在项目的应用中还是有问题,因为有好多含参的构造函数都有业务逻辑在里面,在反序列化时逻辑执行会出问题,从而导致还原数据失败。即便是无参构造函数,内部也有的有些逻辑,所以很不好处理。经分析后,发现原来为了另一种需求去保存数据时,也是有还原数据的需求,为了不参与原有的逻辑,只是纯粹的还原数据,于是对类作了标识,同时增加了特殊的构造函数,该构造函数有一个特殊的参数,于是还原数据时,执行该构造函数去创建实例。有了这样的思路,我们就考虑在JSON库中要怎么用起来。查资料后,得知继承DefaultContractResolver的类中通过重写CreateObjectContract方法可以实现,代码如下

      protected override JsonObjectContract CreateObjectContract(Type objectType)
            {
                var jsonObjectContract = base.CreateObjectContract(objectType);
                var saveDataAttribute = objectType.GetCustomAttributes(typeof(SaveDataAttribute), true);
                if (saveDataAttribute != null && saveDataAttribute.Length > 0)
                {
                    jsonObjectContract.DefaultCreator = () => Activator.CreateInstance(jsonObjectContract.CreatedType, new DataRestoreObjectType());
                }
    
                return jsonObjectContract;
            } 

    数据类的特殊构造函数

    public Node(DataRestoreObjectType dataRestoreObjectType)
            {
    
            }

    经过以上的处理后,序列化和反序化JSON数据的循环引用问题成功得到解决,同时也与原有的项目很好的兼容在一起。

    转载请注明出处。

    展开全文
  • 循环引用导致的json序列化失败

    千次阅读 2018-09-23 16:26:06
    昨天在给系统加日志后,系统就一直报 Stack Overflow错误,找了很久才发现问题,引入的日志工具使用 gson序列化,而打印的日志对象里包含循环引用,导致出错。 简单复现 /** * ClassName: SerializeModel &lt;...
  • 本文主要说明了retain循环的循环引用及解决方法。
  • 引用(weak):不会增加自动引用计数,必须为可选类型变量,因为弱引用引用计数为0的时候,会自动赋为nil。在swfit中,可以赋值为nil的为可选类型 无主引用(unonwed):不会增加自动引用计数,必须为非可选类型。在...
  • 问题背景 再使用SpringBoot+FastJson的时候,如果json里面的list,包含相同内容,会显示为$.ref[x]或者$.row[x].xxx[x],所以需要在...//禁用循环引用$ref.xxx[x] fastConverter.setFeatures(SerializerFeat...
  • 一、概述: Python的GC模块主要运用了“引用计数”(reference counting)来跟踪...在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题。通过“分代回收”(ge...
  • js 循环引用的解析和解决方法

    千次阅读 2018-04-14 12:55:11
    js 循环引用的解析和解决方法
  • VC++工程头文件重复和循环引用

    千次阅读 2013-11-04 09:21:39
    复杂工程中头文件众多,很容易发生包含顺序、重复引用以及循环引用导致的编译链接错误!最近整理工程中文件引用时遇到不少这方面的问题!一般来说,包含顺序问题会导致某些类型、函数等无定义,只要对工程有功能、...
  • c++ 智能指针及 循环引用问题

    万次阅读 多人点赞 2014-04-07 13:36:05
    循环引用的场景:如二叉树中父节点与子节点的循环引用,容器与元素之间的循环引用等。 智能指针的循环引用 循环引用问题可以参考 这个链接 上的问题理解,“循环引用”简单来说就是:两个对象互相使用一个...
  • 使用ARC时,如果对象自己包含的对象又包含自己,则有可能构成循环引用,导致内存泄漏。  判断循环引用导致了内存泄漏的方法:在dealloc方法中加一个断点。如果dealloc方法没有被调用, 则很有可能是循环引用导致...
  • Eclipse中Maven工程间循环引用错误

    千次阅读 2017-11-15 15:48:48
    如果我们的项目包含多个工程(project),而它们之间又是循环引用的关系,那么Eclipse在编译时会抛出如下一个错误信息: “A cycle was detected in the build path of project: XXX” 解决方法非常简单: Eclipse ...
  • 循环引用可以包含任何数量的对象。一个坏的连接会导致很多环的时候,这就复杂了。 在环中,A→B是一个坏连接,创建了两个环:A-B-C-D 和 A-B-C-E。 这有两个问题: 我们不想给一个坏连接导致...
  • 防止Block的循环引用(技巧)

    千次阅读 2015-01-19 19:05:17
    weakSelf是为了block不持有self,避免循环引用,而再声明一个strongSelf是因为一旦进入block执行,就不允许self在这个执行过程中释放。block执行完后这个strongSelf会自动释放,没有循环引用问题。 技巧2 ...
  • vue 解决循环引用组件报错

    千次阅读 2018-07-17 09:00:28
    做项目时遇到使用循环组件,因为模式一样,只有数据不一样。但是按照普通的组件调用格式来做时报错,错误信息为Unknown custom element: &lt;pop&gt; - did you register the component correctly? For ...
  • IE8 之前的浏览器不能对DOM和javascript之间的循环引用进行清理。这个问题相对更加的严重在ie6 windows xp sp3 之前的版本 因为内存没法释放在页面卸载之前。 所以 setHandler 泄露在ie 8 之前的浏览器...
  • 本文讨论的是在cxf下如何解决webservice中存在对象循环引用的问题 不说明cxf的用法和spring整合等等,这在官方文档里都有. 循环引用: Parent 和 Child是1:n的关系, Parent含有一个child的列表children,child对于...
  • 使用引用计数机制时,经常要注意的一个问题就是循环引用,就是程环形相互引用的多个对象。这将导致内存泄露,因为循环中的对象其引用计数不会将为0. 在垃圾收集环境中,通常将这种情况认定为“孤岛”...
  • C++头文件循环包含依赖

    千次阅读 2016-11-17 09:18:00
    1.最近刚好在写一个由java程序改写成c++的程序,其中类定义较多,改写成多个文件后,很多问题就...简单一点可以看出来A,B头文件的互相包含,远一点就会发现A,D的互相包含。2.其实不用自己找这种依赖关系的,很难找,
  • 如果我们的项目包含多个工程(project),而它们之间又是循环引用的关系,那么Eclipse在编译时会抛出如下一个错误信息: “A cycle was detected in the build path of project: XXX” 解决方法非常简单: ...
  • MVC中使用Json的时候:首先考虑运行HTTP中的Get请求和导航属性造成的循环引用(而循环引用使用匿名内部类)。
  • Internet Explorer Web 浏览器(在 IE 4 到 IE 6 中核实)的垃圾收集系统中存在一个问题,即如果 ECMAScript 和某些宿主对象构成了 “循环...如果在一个循环引用包含了一或多个这样的对象,那么这些对象直到浏览器关
  • (1)如果我们的项目包含多个工程(project),而它们之间又是循环引用的关系; (2)使用maven进行项目构建时,两个module之间存在相互依赖; 那么Eclipse在编译时会抛出如下一个错误信息: A cycle was ...
  • 结果,前台调用时,怎么也得不到想要的结果,每次都会报一个 序列化类型为XX的对象时检测到循环引用类似的错误。 第一反应,谷歌了一下,  有人说 将db.ContextOptions.ProxyCreationEnabled=false  也有人说 ...
  • 如何防止头文件被重复包含引用?

    万次阅读 多人点赞 2017-05-14 14:14:59
    看上去没什么问题。如果a.h 和b.h都包含了一个头文件x.h。那么x.h在此也同样被包含了两次,只不过它的形式不是那么明显而已。 多重包含在绝大多数情况下出现在大型程序中,它往往需要使用很多头文件,因此要...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 358,224
精华内容 143,289
关键字:

包含循环引用是什么意思