我继承了一个不使用ARC的旧Objective C项目,并且由于第三方库的使用,可以使用ARC。
我试图解决因访问un / deallocated内存导致的一些随机崩溃。
我的首要任务之一是运行Xcode"分析"工具,看看它发现了什么问题。在大多数情况下,解决这些问题非常有用且最常见。
但是,我有一些课程(即自定义UITableViewCell
)引起了一些关注,我不知道如何解决这些问题
实际课程
#import "userListView.h"
@implementation userListView
@synthesize userCustomCelltextlabel,userCustomDetailtextlabel;
@synthesize unreadIdentifierImg;
-(void)dealloc {
[userCustomCelltextlabel release];
[userCustomDetailtextlabel release];
[unreadIdentifierImg release];
[super dealloc];
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.unreadIdentifierImg=[[UIImageView alloc]initWithFrame:CGRectMake(165,1,12,38)];
self.userCustomCelltextlabel=[[UILabel alloc]initWithFrame:CGRectMake(12,5,150,20)];
self.userCustomCelltextlabel.font=[UIFont fontWithName:@"TrebuchetMS-Bold" size:13.0f];
self.userCustomCelltextlabel.backgroundColor=[UIColor clearColor];
self.userCustomDetailtextlabel=[[UILabel alloc]initWithFrame:CGRectMake(12,22,150,15)];
self.userCustomDetailtextlabel.backgroundColor=[UIColor clearColor];
self.userCustomDetailtextlabel.textColor=[UIColor grayColor];
self.userCustomDetailtextlabel.font=[UIFont fontWithName:@"Trebuchet MS" size:12.0];
self.userCustomDetailtextlabel.numberOfLines=1;
self.userCustomDetailtextlabel.lineBreakMode=NSLineBreakByTruncatingTail;
//self.unreadIdentifierImg.image=[UIImage imageNamed:@"MessageEntrySendButton.png"];
//self.unreadIdentifierImg.hidden=YES;
[self.contentView addSubview:self.unreadIdentifierImg];
[self.contentView addSubview:self.userCustomDetailtextlabel];
[self.contentView addSubview:self.userCustomCelltextlabel];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
标题
#import <UIKit/UIKit.h>
@interface userListView : UITableViewCell
@property (retain, nonatomic) UILabel *userCustomCelltextlabel;
@property (retain, nonatomic) UILabel *userCustomDetailtextlabel;
@property (retain, nonatomic) UIImageView *unreadIdentifierImg;
@end
扩展错误显示......
// 2. Method returns an instance of UIImageView with a +1 retain count
self.unreadIdentifierImg=[[UIImageView alloc]initWithFrame:CGRectMake(165,1,12,38)];
// Seems to point to UIImageView init
// 3. Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1
self.userCustomCelltextlabel=[[UILabel alloc]initWithFrame:CGRectMake(12,5,150,20)];
// Which seems to point to the UILabel init
重复userCustomDetailtextlabel
。我在这里遇到的问题是allocated object is not referenced later in this execution path
,因为它已添加到contentView
,所以不是真的。
现在,显然,我们希望将对象保留为类的属性,并且只在取消分配对象时才处理它们,但我似乎无法对消息做出正面或反面。
我应该忽略它们吗?还有什么我应该考虑尝试解决它们吗?
答案 0 :(得分:2)
使用retain声明属性,因此编译器将生成一个保留值的setter方法。
您使用alloc / init创建标签,为您提供保留计数为+1的标签,然后使用self.userCustomCelltextlabel
将其分配给您的属性,这将调用发送保留的相应setter方法标签,现在它的保留计数为+2。
在dealloc中,您发送版本,标签的保留计数为+1并且正在泄漏。
将autorelease
添加到您的alloc / init或直接使用_userCustomCelltextlabel
将其分配给ivar。
答案 1 :(得分:2)
如果这是您第一次在Objective-C中遇到手动内存管理 - 也称为&#34;手动保留释放&#34; - 如果这个项目无法迁移到ARC,那么我只能建议您花时间学习手动内存管理。 the Cocoa Core Competencies guide中的Memory-Management页面和the Advanced Memory Management Programming Guide中的Practical Memory Management页面是两个很好的起点。
不幸的是,整个手动内存管理太大而不适合Stack Overflow的答案,但我会解释其中一个对象发生了什么 - 在这一行:
self.unreadIdentifierImg = [[UIImageView alloc] initWithFrame:CGRectMake(165,1,12,38)];
当你致电[[UIImageView alloc] initWithFrame: ... ];
时,你会分配内存并创建一个新对象。根据Cocoa 所有权政策,您拥有&#34;拥有&#34;自从您调用alloc
以来,此对象负责其内存。此时,这个新创建的对象的保留计数为1。
当您将该对象分配给self.unreadIdentifierImg
时,它将保留分配给它的对象。发生这种情况是因为该属性定义为@property (retain, nonatomic) ...
。这保留了对象保留计数,这意味着它现在处于2。
由于图像视图既未保留也未在该范围的其余部分中释放,因此最终得到的图像视图的保留计数为2(一个来自创建时,一个来自引用它的属性)。
稍后当取消分配单元格并释放图像视图(显式调用release或将属性设置为nil
)时,图像视图的保留计数会减少,这意味着它现在处于1 (从创建时起)由于没有对此图像视图的其他引用,并且由于它的保留计数不为0,因此该对象现已泄露。
要修复它,您需要在将其分配到保留属性后将其释放一次。你最有可能通过&#34;自动释放&#34;来做到这一点。它,这意味着该对象将被添加到当前的自动释放池中 - 以便在池耗尽时释放:
self.unreadIdentifierImg = [[[UIImageView alloc] initWithFrame:CGRectMake(165,1,12,38)] autorelease];
请注意,该行末尾添加了autorelease
次调用。
根据我的经验,当静态分析仪警告这样的事情时,它几乎总是正确的,因此建议仔细检查这些警告并彻底调查它们。