使用自定义getter和setter将消息发送到带有ARC的已释放实例的消息 [英] Message sent to deallocated instance with ARC using custom getter and setter
问题描述
我试图为我的自定义对象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
的自动获取和设置. firstName
和date
通过像这样利用@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
.另一方面,firstName
和date
是可以被释放的对象.
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屋!