A message sent to a freed instance using ARC using a custom getter and setter

I am trying to implement a custom getter and setter for my custom HFObject , and my application crashed with a Message sent to deallocated instance error, despite using ARC.

I read every single entry, those that were written before ARC do not apply, and everything else did not help. I have the option to debug a zombie object enabled.


Custom HObject Setup

Inside HObject.h, I 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 HObject implementation, I removed the automatic receipt and configuration of email . firstName and date using @dynamic so

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

I also put the values dictionary in my init init

 - (id)init { self = [super init]; if (self) { self.values = [NSMutableDictionary dictionary]; } return self; } 

Custom getter and sender implementation

For my custom getter / setter. I redefined

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector

and

 - (void)forwardInvocation:(NSInvocation *)invocation 

As 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 to save all property values ​​in my values dictionary and get them from there.


Application crash

In the implementation of my view controller, I try to create a HObject and set the values ​​for my properties, and then I write a dictionary of values ​​to see all 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 this point, the application 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, I would really appreciate it. I also include a debugging process in case this helps you


My debugging process (long, skip if you can already help me)

I initially created many of these objects and saved them in an array, and when I do this, as opposed to creating a single object. my application crashed a little differently.

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]); } 

Failure 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 previous one, except that it did not record the values ​​inside [object values]

Having studied the problem a bit, I looked in the left window (not sure what it really is called) of the debugger, and I saw this:

()

(Treat HFObject as HObject and dirtyValues as values , I renamed them for presentation purposes)

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

I did some similar tests where I changed the property values ​​that I set and changed the data types. More often than not, the value of firstName did not matter, but not date . However, the value of email has always been present.

After examining the Types data, I realized that this was because email was a string literal that could not be freed. On the other hand, firstName and date were objects that could be freed.

The crash log refers to the CFString property, which I learned doesn't use ARC. I never created a Core Foundation object, so I decided to find out that it was created in setter by running [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 again I got 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 that date freed for some reason, and my line is now __NSCF lines.

I tried dropping strings to NSStrings using (__brigde NSString *)obj and any other possible way to associate the CF object with ARC, however that didn't work either.

That is all I have done. I appreciate any help.

+2
ios objective-c iphone automatic-ref-counting core-foundation
source share
1 answer

The problem is here:

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

getArgument simply copies the object pointer to obj without saving it. However, since obj is (by default) the __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 getter firstName tries to read the value for the key "firstName".

(As mentioned in the commentary, this would probably be easier and less error prone to simply override the access methods for the three properties separately, instead of dynamically redirecting them.)

+4
source share

All Articles