打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
iOS 循环引用 委托 (实例说明)
如何避免循环引用造成的内存泄漏呢:
以delegate模式为例(viewcontroller和view之间就是代理模式,viewcontroller有view的使用权,viewcontroller同时也是view的代理(处理view中的事件)):
UserWebService.h
#import
//定义一个ws完成的delegate
@protocol WsCompleteDelegate
@required
-(void) finished;//需要实现的方法
@end
@interface UserWebService:NSObject
{
id delegate;//一个id类型的dategate对象
}
@property (assign) id delegate;
-(id)initWithUserData:(User *)user;
-(void)connectionDidFinishLoading:(NSURLConnection *)connection;
@end
UserWebService.m:
#import
@systhesize delegate;//同步这个delegate对象
@implementation UserWebService
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[delegate finished]
}
@end
LoginViewController.h:
#import "UserWebService.h" //包含含有委托的头文件
@interface LoginViewController:UIViewController
-(void)submit;
@end
LoginViewController.m:
@implementation LoginViewController
-(void) submit
{
User *user = [[User alloc]init];
[user setUserId:@"username"];
[user setPassword:@"password"];
ws = [[UserWebService alloc] initWithUserData:user];
ws.delegate = self;//设置委托的收听对象
[user release];
[ws send];
}
//实现委托中的方法,
-(void) finished
{
NSAttry *users = [ws users];
}
@end
可以看到,delegate声明为assign:
@property (assign) id delegate;
复制代码
如果声明为retain会如何?
LoginViewController alloc了一个UserWebService,UserWebService的代理又是LoginViewController,这样就循环引用了:
ws = [[UserWebService alloc] initWithUserData:user]; //UserWebService对象引用计数加1
ws.delegate = self;//LoginViewController对象引用计数加1
外部框架allocLoginViewController对象后,LoginViewController对象的引用计数为2 ,release后还是无法销毁,产生内存泄漏
所以用assign而不是retain声明属性可以避免循环引用,ARC下用弱引用也可以解决
内存检测可以用xcode继承的instrument工具,不过循环引用引起的内存泄露是检测不出来的
对象release到引用计数为0后,如果对应指针没有赋值为nil,怎出现野指针
ClassA *a = [[ClassA alloc] init];
a = nil;//alloc的内存没有任何对象可以控制它了,引用计数永远为1,这就造成了内存泄露
简单的赋值操作并不会改变对象的引用计数:
ClassA *a = [[ClassA alloc] init];
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,看起来是这样的:
-(void)setObjA:(ClassA *)a {
objA = a;
}
在深入retain之前,先把声明为retain特性的setter写出来:
-(void)setObjA:(ClassA *)a
{
If(objA != a)
{
[objA release];
objA = a;
[objA retain]; //对象的retain count 加1
}
}
明显的,在retain的setter中,变量retain了一次,那么,即使你在程序中 self.objA = a; 只写了这么一句,objA仍然需要release,才能保证对象的retain count 是正确的。但是如果你的代码 objA = a; 叧写了这么一句,那么这里只是进行了一次浅复制,对象的retain count 并没有增加,因此这样写的话,你不需要在后面release objA。 这2句话的区别是,第一句使用了编译器生成的setter来设置objA的值,而第二句叧是一个简单的指针赋值
NSString *str = [[NSString alloc] initwithstring @“abc”];
str = @“abcd”;‘
[str release];
NSLog("%@",str);//打印出abcd
str为什么没有变成野指针呢?因为字符串常量(包括NSString和@“......”)的引用计数很大(100K+),基本上不会释放掉(由OC自己管理),所以字符串常量可以不用release
分类: object-c iOS
绿色通道:   与我联系
tangbinblog
关注 - 5
粉丝 - 57
0
0
(请您对文章做出评价)
 上一篇:【iOS】自动引用计数 (循环引用)
 下一篇:IOS 企业级应用无线部署 详解
posted @ 2013-10-21 11:01 tangbinblog 阅读(2521) 评论(3)  编辑 收藏
评论列表
#1楼  2014-09-22 16:36 断云残阳  
你上面的循环引用的例子是不对的,因为一般retain的属性,都会在dealloc函数里面有一条release语句。所以你上面的例子不存在循环引用的问题。可以这样修改一下:
1.UserWebService实现WsCompleteDelegate协议;
2.LoginViewController增加一个属性id<WsCompleteDelegate> delegate;
UserWebService *uws = [UserWebService new];
LoginViewController *login = [LoginViewController new];
uws.delegate = login; #login.retainCount = 2;
login.delegate = uws; #uws.retainCount = 2;
[uws release]; #uws.retainCount = 1;
[login release]; #login.retainCount = 1;
因为uws的retianCount = 1,所以其dealloc函数无法执行,也就无法执行 [delegate release]语句,所以login也无法执行dealloc函数。
#2楼[楼主]  2014-10-18 15:54 tangbinblog  
@断云残阳
没看懂你啥意思。
首先 LoginViewController 是 UserWebService 的委托对象。
LoginViewController 实现 WsCompleteDelegate 协议。在 UserWebService connectionDidFinishLoading 方法中 回调 LoginViewController 实现的 委托方法。
如果 用 retain delegate.
LoginViewController 中释放 UserWebService 时 , UserWebService 回去释放强引用的 delegate ,也就是LoginViewController。
这么不就死循环啦。两个都不回释放。
#3楼  2014-10-29 12:17 yun453162  
@断云残阳
@implementation LoginViewController
-(void) submit
{
User *user = [[User alloc]init];
[user setUserId:@"username"];
[user setPassword:@"password"];
ws = [[UserWebService alloc] initWithUserData:user];
ws.delegate = self;//设置委托的收听对象
[user release];
[ws send];
}
//实现委托中的方法,
-(void) finished
{
NSAttry *users = [ws users];
}
--------------------------------
他没有把ws的释放代码写出来,,如果把[ws release] 写在login的 dealloc里,那么它就不会被释放
因为ws retain了login这个控制器,那么login要释放要求ws先释放,如果写在dealloc里,逻辑上是释放了login时去释放ws...它们的释放逻辑是冲突的,导致谁也无法释放
不过按他的代码来看,在submit调用时alloc,就必须在finished里面把ws 释放,要不每次点submit 都alloc ws,却只是dealloc里释放ws一次,明显是不行的,如果加上了,那么这个retain cycle就不存在了,因为这样一来ws 的释放就不对login释放形成依赖。 按照道理,这个是要加的,所以赞了你一个。。。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
IOS atomic与nonatomic,assign,copy与retain的定义和区别...
终于有大佬把'计算机底层原理'全部总结出来了
ios面试题
C++侵入式智能指针的实现
[转载]DebugAssertionFailed!
指针和引用的区别
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服