消息发送到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
的自动获取和设置。 firstName
和date
这样利用@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
。 另一方面, firstName
和date
是可以被释放的对象。
崩溃日志引用一个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现在是__NSCF
string。
我尝试使用(__brigde NSString *)obj
和其他所有可能的方式将string重置为NSStrings
(__brigde NSString *)obj
将CF对象连接到ARC,但是这也不起作用。
这是我所做的一切。 我感谢任何和所有的帮助。
问题在这里:
id obj; [invocation getArgument:&obj atIndex:2];
getArgument
只是将对象指针复制到obj
而不保留它。 但是,由于obj
(默认情况下)是__strong
variables,因此它将在当前方法结束时释放。 要解决这个问题,请使用
__unsafe_unretained id obj; [invocation getArgument:&obj atIndex:2];
还要注意,你的getter实现不起作用。 例如, setFirstName:
使用键“FirstName”将键存储在字典中,但getter firstName
尝试读取键“firstName”的值。
(正如在评论中已经提到的那样,这可能更容易,也更容易出错,只是分别替代三个属性的访问器方法,而不是dynamic转发。)