问题
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.
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.
Setting up the custom HObject
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;
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;
I also allocate the values
dictionary in my HObject init
- (id)init {
self = [super init];
if (self) {
self.values = [NSMutableDictionary dictionary];
}
return self;
}
Implementing Custom Getter & Sender
For my custom getter/setter. I have overridden
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
and
- (void)forwardInvocation:(NSInvocation *)invocation
As shown below:
- (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];
}
}
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.
App Crashing
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
My debugging Process (Long, skip if you can already help me)
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.
My array:
@property (nonatomic, strong) NSArray *array;
Methods:
- (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]);
}
Crash log:
2014-07-27 04:34:02.893 App[61623:60b] *** -[CFString isNSString__]: message sent to deallocated instance 0x1094988f0
(lldb)
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:
(Treat HFObject
as HObject
and dirtyValues
as values
; I renamed them for presentational purposes)
You can see that under the key @"FirstName"
there is no value.
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.
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.
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];
}
}
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)
Here you can see Date
is being deallocated for some reason, and my string are now __NSCF
strings.
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.
回答1:
The problem is here:
id obj;
[invocation getArgument:&obj atIndex:2];
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];
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.)
来源:https://stackoverflow.com/questions/24979501/message-sent-to-deallocated-instance-with-arc-using-custom-getter-and-setter