• OC学习11——循环引用与@class


    转载自 OC学习篇之---@class关键字的作用以及#include和#import的区别

    一、#import和#include的区别

    当我们在代码中使用两次#include的时候会报错:因为#include相当于拷贝头文件中的声明内容,所以会报重复定义的错误

    但是使用两次#import的话,不会报错,所以他可以解决重复导入的问题,他会做一次判断,如果已经导入一次就不导入了

     

    二、关键字@class的作用

    在来看一下OC中的关键字@class的作用,在看他的作用之前,先来看一个问题:

    现在有一个课程类Classes和学生类Student,他们两之间需要相互引用(导入),直接看代码比较直接:

     1 //  
     2 //  Classes.h  
     3 //  08_@class  
     4 //  
     5 //  Created by jiangwei on 14-10-11.  
     6 //  Copyright (c) 2014年 jiangwei. All rights reserved.  
     7 //  
     8   
     9 #import <Foundation/Foundation.h>  
    10   
    11 #import "Student.h"  
    12   
    13 //不会将Student.h拷贝过来,只是告诉编译器Student这个类在别的地方中有定义,这样就不知道这个类中任何信息(哪些属性和方法)  
    14 //@class Student;  
    15   
    16 @interface Classes : NSObject{  
    17       
    18 @public  
    19     Student *_student;  
    20 }  
    21   
    22 - (void)t1;  
    23   
    24 @end  
    Classes.h
     1 //  
     2 //  Classes.m  
     3 //  08_@class  
     4 //  
     5 //  Created by jiangwei on 14-10-11.  
     6 //  Copyright (c) 2014年 jiangwei. All rights reserved.  
     7 //  
     8   
     9 #import "Classes.h"  
    10   
    11 //#import "Student.h"  
    12   
    13 @implementation Classes  
    14   
    15 - (void)t1{  
    16     [_student work];  
    17 }  
    18   
    19 @end  
    Classes.m
     1 //  Student.h  
     2 //  08_@class  
     3 //  
     4 //  Created by jiangwei on 14-10-11.  
     5 //  Copyright (c) 2014年 jiangwei. All rights reserved.  
     6 //  
     7   
     8 #import <Foundation/Foundation.h>  
     9   
    10 #import "Classes.h"  
    11   
    12 @interface Student : NSObject{  
    13     Classes *_classes;  
    14 }  
    15   
    16 - (void)work;  
    17   
    18 @end  
    Student.h
     1 //  
     2 //  Student.m  
     3 //  08_@class  
     4 //  
     5 //  Created by jiangwei on 14-10-11.  
     6 //  Copyright (c) 2014年 jiangwei. All rights reserved.  
     7 //  
     8   
     9 #import "Student.h"  
    10   
    11 @implementation Student  
    12   
    13 - (void)work{  
    14     NSLog(@"work");  
    15 }  
    16   
    17 @end  
    Student.m

    我们可以看到,课程类Classes和学生类Student中分别由成员变量指向对方的一个对象,即相互引用,并用#import进行导包了,下面我们进行测试一下有没有问题:

     1 //  main.m  
     2   
     3 #import <Foundation/Foundation.h>  
     4   
     5 #import "Classes.h"  
     6 #import "Student.h"  
     7   
     8 //Classes和Student相互导入会出现问题  
     9 //这时候我们就可以使用@class解决这样的问题  
    10 //我们一般在.h文件中使用@class,因为在.h文件中一般是不会使用类的属性和方法的  
    11 //在.m文件中可以导入.h文件  
    12 int main(int argc, const charchar * argv[]) {  
    13     @autoreleasepool {  
    14         Classes *cls =[[Classes alloc] init];  
    15         Student *stu = [[Student alloc] init];  
    16         cls->_student = stu;  
    17         [cls t1];  
    18           
    19     }  
    20     return 0;  
    21 }  

    这里有一个问题注意一下:我们看到了这里是如何使用Classes中的属性_student的,因为在Classes类中属性_student是@public的,所以可以直接使用,用的是箭头符号,和C/C++中的指针变量调用差不多。记住了,这里就说到了如何直接访问一个类中的@public修饰符的属性变量

    我们编译运行:

    看到了,编译错误,说在Student类中的Classes类找不到指定类型,这就奇怪了,我们不是导入了Classes.h文件了,为什么还是找不到类型呢?

    这就是OC中类的相互引用的问题,我们在Student.h文件中导入了Classes.h,又在Classes.h文件中导入了Student.h,OC中在相互导入的时候编译是不通过的,这样就会导致错误。当两个类之间存在相互引用时,两个类的头文件部分不能都是用import来导入对方的头文件,这样会导致编译错误,程序中只要在其中某个类的头文件部分使用@class来声明关联类即可,然后在实现部分用import导入相应的类

    当然解决办法就是使用@class关键字,我们修改一下Classes类的Class.h文件即可

     2 //  Classes.h  
     8   
     9 #import <Foundation/Foundation.h>  
    10   
    11 //不用import导入,如用@class导入
    12 //#import "Student.h"  
    13   
    14 //不会将Student.h拷贝过来,只是告诉编译器Student这个类在别的地方中有定义,这样就不知道这个类中任何信息(哪些属性和方法)  
    15 @class Student;  
    16   
    17 @interface Classes : NSObject{  
    18       
    19 @public  
    20     Student *_student;  
    21 }  
    22   
    23 - (void)t1;  
    24   
    25 @end 

    @class Student:这段代码的作用就是不会将Student.h文件拷贝过来,只是告诉编译器Student这个类在别的地方中有定义,这样就不知道这个类中的任何信息了(哪些属性和方法),然后在Class.m文件中需要导入Student.h的头文件

     1 //  Classes.m  
     2   
     3 #import "Classes.h"  
     4  
     5 //之前由于在Class.h中导入了,不需要导入Student.h
     6 //现在由于Class.h中没有导入,所以现在必须导入 Student.h
     7 #import "Student.h"  
     8   
     9 @implementation Classes  
    10   
    11 - (void)t1{  
    12     [_student work];  
    13 }  
    14   
    15 @end  

    这时候编译就不会报错了,同样就可以正常的运行了:

    这一篇文章就介绍了#import关键字和@class的作用,特别是@class关键字的使用,为了解决相互导入的问题,在此回顾一下我们是怎么操作的:Student类中的导入Classes.h方式不变,在Classes.h头文件中使用@class关键字引入Student类型,使其编译通过,然后在Classes.m文件中导入Student.h文件,使其运行通过。

    以后遇到这样的问题解决方法就是这样操作的。

     

    三、循环引用导致的内存泄漏问题

      大部分时候,ARC可以很好地处理程序中对象的内存回收,但如果两个对象之间存在双相关联,即循环引用时,两个对象都使用强引用互相指向对方,此时两个对象的引用计数都等于1。但它们实际上并没有被真正的引用变量所引用,ARC也无法真正地回收他们,这时依然会导致内存泄漏。

      为了解决这个问题,必须有一方做出让步,允许对方先释放。因此,只要程序中将强引用循环中的strong指示符改为weak即可,使用weak指示符定义的属性属于弱引用,弱引用不会增加对方的引用计数,因此,不会阻止ARC回收被引用的实例,这样就可以避免形成强引用循环了。

     

  • 相关阅读:
    vue样式的动态绑定
    vue表单选项框
    vue简单逻辑判断
    vue的选项卡功能
    简单vue的监听属性(单位换算)
    简单的Vue计算属性
    vue.js 入门
    head元素的内容
    HTML实体
    CSS元素的盒类型
  • 原文地址:https://www.cnblogs.com/mukekeheart/p/7373054.html
Copyright © 2020-2023  润新知