消息发送到ARC使用自定义getter和setter释放实例

我试图为我的自定义对象HFObject实现自定义getter和setter,并且尽pipe使用ARC,我的应用程序崩溃了Message sent to deallocated instance错误的Message sent to deallocated instance

我已经阅读了每一个相关的文章,那些在ARC之前编写的文章并不适用,其他一切都没有帮助。 我打开了僵尸对象debugging器选项。


设置自定义HObject

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

 @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

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

我也在HObject init中分配values字典

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

实现自定义Getter和发件人

对于我的自定义getter / setter。 我已经覆写

- (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字典中,并从那里检索它们。


应用程序崩溃

在我的视图控制器的实现中,我尝试创build一个HObject并为我的属性设置值,然后logging值字典以查看我的所有值。

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

在这一点上,应用程序崩溃,这是我的控制台日志

 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 

如果你能从这里帮助我,我将不胜感激。 我也包括我的debugging过程,以帮助你


我的debugging过程(长,跳过,如果你已经可以帮我)

我最初创build了许多这些对象,并将它们存储在一个数组中,当我这样做时,而不是创build一个单一的对象。 我的应用程序崩溃了一点点不同。

我的arrays:

 @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) 

现在这个崩溃日志与之前的崩溃日志几乎是一样的,除了没有logging[object values]

调查一下这个问题,我看了一下debugging器的左边窗口(不知道实际调用的是什么),我看到了这个:

()

(将HFObject视为HObject ,将dirtyValues视为values ;我将其重命名为表示目的)

你可以看到在@"FirstName"键下没有任何值。

我做了几个类似的testing,我改变了我设置的属性的值,并改变了数据types。 多数情况下,不仅FirstName不具有价值, Date也不具有价值。 但是,电子邮件的价值始终存在。

在研究了dataTypes之后,我意识到这是因为email是一个不能被释放的string literal 。 另一方面, firstNamedate是可以被释放的对象。

崩溃日志引用一个CFString属性,我学到了不使用ARC。 我从来没有创build过一个Core Foundation对象,所以我开始通过logging[obj class]来发现它是在setter中创build的:

 - (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

 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由于某种原因被解除分配,而我的string现在是__NSCFstring。

我尝试使用(__brigde NSString *)obj和其他所有可能的方式将string重置为NSStrings (__brigde NSString *)obj将CF对象连接到ARC,但是这也不起作用。

这是我所做的一切。 我感谢任何和所有的帮助。

问题在这里:

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

getArgument只是将对象指针复制到obj而不保留它。 但是,由于obj (默认情况下)是__strongvariables,因此它将在当前方法结束时释放。 要解决这个问题,请使用

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

还要注意,你的getter实现不起作用。 例如, setFirstName:使用键“FirstName”将键存储在字典中,但getter firstName尝试读取键“firstName”的值。

(正如在评论中已经提到的那样,这可能更容易,也更容易出错,只是分别替代三个属性的访问器方法,而不是dynamic转发。)