使用自定义getter和setter将消息发送到带有ARC的已释放实例的消息 [英] Message sent to deallocated instance with ARC using custom getter and setter

查看:274
本文介绍了使用自定义getter和setter将消息发送到带有ARC的已释放实例的消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图为我的自定义对象HFObject实现一个自定义的getter和setter方法,尽管使用了ARC,我的应用还是崩溃了,出现了Message sent to deallocated instance错误.

I'm trying to implement a custom getter and setter for my custom object HFObject and my app crashed with a Message sent to deallocated instance error despite using ARC.

我已经阅读了每一个相关的帖子,不适用于ARC之前写的帖子,其他所有内容也无济于事.我打开了僵尸对象调试器选项.

I've read every single related post, the ones that were written pre-ARC don't apply, and everything else didn't help. I have the zombie object debugger option turned on.

在HObject.h中,我已经声明了这四个属性:

Within HObject.h I have declared these four properties:

@property (retain) NSString *email;        //Will use custom getter/setter
@property (retain) NSString *firstName;    //Will use custom getter/setter
@property (retain) NSDate *date;           //Will use custom getter/setter
@property (nonatomic, retain) NSMutableDictionary *values;

在HObject的实现中,我删除了email的自动获取和设置. firstNamedate通过像这样利用@dynamic

In the implementation of HObject, I have removed the automatic getting and setting of email. firstName, and date by utilizing @dynamic like so

@dynamic email;
@dynamic firstName;
@dynamic date;

我还在我的HObject init中分配了values字典

I also allocate the values dictionary in my HObject init

- (id)init {
    self = [super init];

    if (self) {
        self.values = [NSMutableDictionary dictionary];
    }

    return self;
}


实施自定义Getter&发件人

对于我的自定义获取/设置者.我已覆盖


Implementing Custom Getter & Sender

For my custom getter/setter. I have overridden

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector

- (void)forwardInvocation:(NSInvocation *)invocation

如下所示:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    NSString *sel = NSStringFromSelector(selector);
    if ([sel rangeOfString:@"set"].location == 0) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    } else {
        return [NSMethodSignature signatureWithObjCTypes:"@@:"];
    }
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    NSString *key = NSStringFromSelector([invocation selector]);
    if ([key rangeOfString:@"set"].location == 0) { 
        key = [key substringWithRange:NSMakeRange(3, [key length]-4)]; 

        id obj;   
        [invocation getArgument:&obj atIndex:2];   

        [self.values setObject:obj forKey:key];
    } else {
        id obj = [self.values objectForKey:key];

        [invocation setReturnValue:&obj];
    }
}

我要在此处执行的操作是将该属性的所有值存储到我的values字典中,并从那里也检索它们.

What I'm trying to do here is store all of the values of the property into my values dictionary and retrieve them from there as well.

在实现视图控制器的过程中,我尝试创建一个HObject并为属性设置值,然后登录值字典以查看所有值.

In the implementation of my view controller, I try to create a HObject and set values for my properties, and then I log the values dictionary to see all of my values.

- (void)buttonPressed:(id)sender {
    HObject *obj = [[HObject alloc] init];

    NSString *name = @"this is a string object";
    obj.date = [NSDate date];
    obj.email = @"email@website.com";
    obj.firstName = [NSString stringWithFormat:@"%@", name];


    NSLog(@"Values %@", [obj values]);
}

那时应用程序崩溃了,这是我的控制台日志

At that point the app crashes and this is my console log

2014-07-27 04:12:37.899 App[61501:60b] Values {
    Date = "2014-07-27 08:12:37 +0000";
    Email = "email@website.com";
    FirstName = "this is a string object";
}
2014-07-27 04:12:37.901 HeadsUp[61501:60b] *** -[CFString release]: message sent to deallocated instance 0x109473fe0

如果您能从这里帮助我,我将不胜感激.我还将包括我的调试过程,以帮助您

If you can help me from here, I would greatly appreciate it. I am also including my debugging process in case that will help you

我最初创建了许多这样的对象并将它们存储在数组中,而当我这样做时,与创建单个对象相反.我的应用崩溃了.

I originally created many of these objects and stored them in an array, and when I do that, as opposed to creating a single object. my app crashed a bit different.

我的数组:

@property (nonatomic, strong) NSArray *array;

方法:

- (void)createArray
{
    int i = 1; //number of testobjs

    NSMutableArray *objects = [NSMutableArray arrayWithCapacity:i];

    for (int j = 0; j<i; j++) {
        HFObject *obj = [[User alloc] init];

        NSString *name = @"this is a string object";
        [obj setObject:[NSDate date] forKey:@"Date"];
        obj.email = @"email@website.com";
        obj.firstName = [NSString stringWithFormat:@"%@", name];

        [objects addObject:obj];
    }


    self.array = [NSArray arrayWithArray:objects];

}

- (void)buttonPressed:(id)sender {
    HObject *object = [self.array objectAtIndex:0];

    NSLog(@"Values %@", [object values]);
}

崩溃日志:

2014-07-27 04:34:02.893 App[61623:60b] *** -[CFString isNSString__]: message sent to deallocated instance 0x1094988f0
(lldb) 

现在,该崩溃日志与之前的崩溃日志几乎相同,除了它没有记录[object values]

Now this crash log is almost the same as the one before, except this didn't log the values inside of [object values]

稍微研究一下这个问题,我看着调试器的左窗口(不确定它的实际名称),我看到了:

Investigating the issue a bit, I looked at the left window (not sure what it is actually called) of the debugger and I saw this:

(将HFObject用作HObject,将dirtyValues用作values;我出于演示目的将其重命名)

(Treat HFObject as HObject and dirtyValues as values; I renamed them for presentational purposes)

您会看到键@"FirstName"下没有任何值.

You can see that under the key @"FirstName" there is no value.

我做了一些类似的测试,在这些测试中,我更改了所设置的属性的值并更改了数据类型.通常,不仅FirstName没有值,Date也没有值.但是,电子邮件的价值始终存在.

I did several similar tests where I changed the values of the properties I was setting and changed the data types. More often than not, not only did FirstName not have a value, neither did Date. However, the value of email was always present.

研究了dataTypes之后,我意识到这是因为email是无法释放的string literal.另一方面,firstNamedate是可以被释放的对象.

After researching about dataTypes, I realized it was because email was a string literal which can't deallocated. On the other hand firstName and date were objects, which can be deallocated.

崩溃日志引用了CFString属性,据我了解,该属性不使用ARC.我从未创建过Core Foundation对象,所以我着手通过记录[obj class]:

The crash log refers to a CFString property, which I learned doesn't use ARC. I never created a Core Foundation object, so I set out to found out it was being created in setter by logging the [obj class]:

- (void)forwardInvocation:(NSInvocation *)invocation
{
    NSString *key = NSStringFromSelector([invocation selector]);
    if ([key rangeOfString:@"set"].location == 0) { 
        key = [key substringWithRange:NSMakeRange(3, [key length]-4)]; 

        id obj;   
        [invocation getArgument:&obj atIndex:2];   

        NSLog(@"%@", [obj class]);  //I ADDED THIS LOG

        [self.values setObject:obj forKey:key];
    } else {
        id obj = [self.values objectForKey:key];

        [invocation setReturnValue:&obj];
    }
}

再崩溃一次后,我得到了obj

After crashing one more time, I got the obj classes

2014-07-27 04:58:03.893 HeadsUp[61765:60b] __NSDate
2014-07-27 04:58:03.894 HeadsUp[61765:60b] __NSCFConstantString
2014-07-27 04:58:03.894 HeadsUp[61765:60b] __NSCFString
2014-07-27 04:58:03.904 HeadsUp[61765:60b] *** -[__NSDate release]: message sent to deallocated instance 0x109554370
(lldb) 

在这里您可以看到Date由于某种原因被释放,而我的字符串现在是__NSCF字符串.

Here you can see Date is being deallocated for some reason, and my string are now __NSCF strings.

我尝试使用(__brigde NSString *)obj将字符串重置为NSStrings,以及将CF对象桥接到ARC的所有其他可能方式,但这也不起作用.

I tried resetting the strings to NSStrings using (__brigde NSString *)obj and every other possible way you can bridge a CF object to ARC, however that didn't work either.

这是我所做的一切.非常感谢您的帮助.

Here is everything I've done. I appreciate any and all help.

推荐答案

问题在这里:

id obj;   
[invocation getArgument:&obj atIndex:2];

getArgument只是将对象指针复制到obj中而不保留它. 但是,由于obj(默认情况下)是__strong变量,因此它将在以下位置释放 当前方法的结尾.要解决此问题,请使用

getArgument simply copies the object pointer into obj without retaining it. However, since obj is (by default) a __strong variable, it will be released at the end of the current method. To solve the problem, use

__unsafe_unretained id obj;   
[invocation getArgument:&obj atIndex:2];   

还请注意,您的getter实现无效.例如,setFirstName: 使用键"FirstName"将键存储在字典中,但getter firstName 尝试读取键名字"的值.

Note also that your getter implementation does not work. For example, setFirstName: stores the key in the dictionary using the key "FirstName", but the getter firstName tries to read the value for the key "firstName".

(如评论中已经提到的那样,这可能会更容易且更不易出错 只是分别覆盖这三个属性的访问器方法 动态转发.)

(As already mentioned in a comment, it would probably easier and less error-prone to just override the accessor methods for the three properties separately, instead of dynamic forwarding.)

这篇关于使用自定义getter和setter将消息发送到带有ARC的已释放实例的消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆