OC学习11——循环引用与@class
转载自 OC学习篇之---@class关键字的作用以及#include和#import的区别
一、#import和#include的区别
当我们在代码中使用两次#include的时候会报错:因为#include相当于拷贝头文件中的声明内容,所以会报重复定义的错误
但是使用两次#import的话,不会报错,所以他可以解决重复导入的问题,他会做一次判断,如果已经导入一次就不导入了
二、关键字@class的作用
在来看一下OC中的关键字@class的作用,在看他的作用之前,先来看一个问题:
现在有一个课程类Classes和学生类Student,他们两之间需要相互引用(导入),直接看代码比较直接:
//
// Classes.h
// 08_@class
//
// Created by jiangwei on 14-10-11.
// Copyright (c) 2014年 jiangwei. All rights reserved.
// #import <Foundation/Foundation.h> #import "Student.h" //不会将Student.h拷贝过来,只是告诉编译器Student这个类在别的地方中有定义,这样就不知道这个类中任何信息(哪些属性和方法)
//@class Student; @interface Classes : NSObject{ @public
Student *_student;
} - (void)t1; @end
Classes.h
//
// Classes.m
// 08_@class
//
// Created by jiangwei on 14-10-11.
// Copyright (c) 2014年 jiangwei. All rights reserved.
// #import "Classes.h" //#import "Student.h" @implementation Classes - (void)t1{
[_student work];
} @end
Classes.m
// Student.h
// 08_@class
//
// Created by jiangwei on 14-10-11.
// Copyright (c) 2014年 jiangwei. All rights reserved.
// #import <Foundation/Foundation.h> #import "Classes.h" @interface Student : NSObject{
Classes *_classes;
} - (void)work; @end
Student.h
//
// Student.m
// 08_@class
//
// Created by jiangwei on 14-10-11.
// Copyright (c) 2014年 jiangwei. All rights reserved.
// #import "Student.h" @implementation Student - (void)work{
NSLog(@"work");
} @end
Student.m
我们可以看到,课程类Classes和学生类Student中分别由成员变量指向对方的一个对象,即相互引用,并用#import进行导包了,下面我们进行测试一下有没有问题:
// main.m #import <Foundation/Foundation.h> #import "Classes.h"
#import "Student.h" //Classes和Student相互导入会出现问题
//这时候我们就可以使用@class解决这样的问题
//我们一般在.h文件中使用@class,因为在.h文件中一般是不会使用类的属性和方法的
//在.m文件中可以导入.h文件
int main(int argc, const charchar * argv[]) {
@autoreleasepool {
Classes *cls =[[Classes alloc] init];
Student *stu = [[Student alloc] init];
cls->_student = stu;
[cls t1]; }
return ;
}
这里有一个问题注意一下:我们看到了这里是如何使用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文件即可
// Classes.h #import <Foundation/Foundation.h> //不用import导入,如用@class导入
//#import "Student.h" //不会将Student.h拷贝过来,只是告诉编译器Student这个类在别的地方中有定义,这样就不知道这个类中任何信息(哪些属性和方法)
@class Student; @interface Classes : NSObject{ @public
Student *_student;
} - (void)t1; @end
@class Student:这段代码的作用就是不会将Student.h文件拷贝过来,只是告诉编译器Student这个类在别的地方中有定义,这样就不知道这个类中的任何信息了(哪些属性和方法),然后在Class.m文件中需要导入Student.h的头文件
// Classes.m #import "Classes.h" //之前由于在Class.h中导入了,不需要导入Student.h
//现在由于Class.h中没有导入,所以现在必须导入 Student.h
#import "Student.h" @implementation Classes - (void)t1{
[_student work];
} @end
这时候编译就不会报错了,同样就可以正常的运行了:

这一篇文章就介绍了#import关键字和@class的作用,特别是@class关键字的使用,为了解决相互导入的问题,在此回顾一下我们是怎么操作的:Student类中的导入Classes.h方式不变,在Classes.h头文件中使用@class关键字引入Student类型,使其编译通过,然后在Classes.m文件中导入Student.h文件,使其运行通过。
以后遇到这样的问题解决方法就是这样操作的。
三、循环引用导致的内存泄漏问题
大部分时候,ARC可以很好地处理程序中对象的内存回收,但如果两个对象之间存在双相关联,即循环引用时,两个对象都使用强引用互相指向对方,此时两个对象的引用计数都等于1。但它们实际上并没有被真正的引用变量所引用,ARC也无法真正地回收他们,这时依然会导致内存泄漏。
为了解决这个问题,必须有一方做出让步,允许对方先释放。因此,只要程序中将强引用循环中的strong指示符改为weak即可,使用weak指示符定义的属性属于弱引用,弱引用不会增加对方的引用计数,因此,不会阻止ARC回收被引用的实例,这样就可以避免形成强引用循环了。
OC学习11——循环引用与@class的更多相关文章
- OC ARC之循环引用问题(代码分析)
// // main.m // 03-arc-循环引用 // // Created by apple on 13-8-11. // Copyright (c) 2013年 itcast. All ri ...
- OC MRC之循环引用问题(代码分析)
// // main.m // 07-循环引用 // // Created by apple on 13-8-9. // Copyright (c) 2013年 itcast. All rights ...
- swift闭包中解决循环引用的问题
swift中可以通过三种方法解决循环引用的问题 利用类似oc方法解决循环引用weak var weakSelf = self weak var weakSelf = self loadData = { ...
- swift中闭包的循环引用
首先我们先创造一个循环引用 var nameB:(()->())? override func viewDidLoad() { super.viewDidLoad() let bu = UIBu ...
- OC学习篇之---循环引用问题
在之前的一片文章中,我们介绍了数组操作对象的时候引用问题以及自动释放池的概念: http://blog.csdn.net/jiangwei0910410003/article/details/4192 ...
- spring源码学习(三)--spring循环引用源码学习
在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...
- 【转】iOS学习之容易造成循环引用的三种场景
ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是——循环引用.循环引用可以简单理解为A引用了B,而B又引用了A,双方都同 ...
- 小结OC中Retain cycle(循环引用)
retain cycle 的产生 说到retain cycle,首先要提一下Objective-C的内存管理机制. 作为C语言的超集,Objective-C延续了C语言中手动管理内存的方式,但是区别于 ...
- 【IOS学习基础】weak和strong、懒加载、循环引用
一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...
随机推荐
- 在SQL Server Express版本中没有代理功能如何自动备份数据库
因为是免费的且单个数据库可以支持到10GB,对于一般企业完全足够了,也就将就使用了,备份将分为两步: 1.创建备份脚本 2.创建系统的计划任务进行每天的备份 详细做法如下: 1.创建备份脚本 打开SS ...
- RecyclerView 加入一个滑动控件bug处理 GridView只显示第一行
如果RecyclerView 多样式布局,比如要加入一个展示多个图看的需求.自然想到用gridview给嵌套一下. 想法当然是可以的,但是发现,嵌套出来的效果是,gridview只显示一行. 想想原因 ...
- 记录项目版本升级angular4 ~ angular5
前言: 在上一篇ng4文章<angular4--实际项目搭建总结>中说过,等到ng5正式发布,并且蚂蚁的NG ZORRO兼容ng5之后,我会对ng4项目进行升级.这篇文章就是大概说下升级的 ...
- F - Capture
F - Capture 题链 题意 给你两种颜色的物品,有n组,每组有第一种颜色有w个,第二种为d个,每组必须选一种,求最后第一种颜色占的比值不低于K的最少需要选第一种的组数. 思路 首先没组都选第一 ...
- sqlserver的四种分页方式
第一种:ROW_NUMBER() OVER()方式 select * from ( select *, ROW_NUMBER() OVER(Order by ArtistId ) AS RowId f ...
- Pythonh中的zip()与*zip()函数详解
前言 实验环境: Python 3.6: 示例代码地址:下载示例: 本文中元素是指列表.元组.字典等集合类数据类型中的下一级项目(可能是单个元素或嵌套列表). zip(*iterables)函数详解 ...
- ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十六节--SignalR与ABP框架Abp.Web.SignalR及扩展
SignalR简介 SignalR是什么? ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指 ...
- layui使用心得
表单控件样式没生效, 因为没引入form. layui.use('form', function(){ var form = layui.form; }); radio改变事件没生效, 需要手动fil ...
- QQ互联申请及配置
今天要说的只是针对QQ互联的操作,其他的互联请参考相关网站. 第一步:需要申请API接口的两码 自行登录QQ互联https://connect.qq.com/index.html,然后按照要求申请就O ...
- Linux中如何恢复rm命令误删除的文件之extundelete编译安装及使用
1.下载extundelete包,安装依赖 我用的是Centos系统,在安装extundelete之前需要安装e2fsprogs,e2fsprogs-libs,e2fsprogs-devel. yum ...