views:

224

answers:

1

Cocoa newbie here. I am working on an iPhone UITableViewController-based widget that can be used to edit date and text properties in an object set during initiation. Currently, I am attempting to do this with a @selector and NSInvocation as below. Note: the "targetObject" is the object set when the controller is initialized.

- (IBAction)saveDate:(id)sender {
      //The selector below would normally be passed in when the controller is initialized
      [self setDoneSelector:@selector(setDate:)];
      NSMethodSignature * sig = nil;
      sig = [[targetObject class] instanceMethodSignatureForSelector:[self doneSelector]];
      NSInvocation * myInvocation = nil;
      myInvocation = [NSInvocation invocationWithMethodSignature:sig];
      [myInvocation setTarget:targetObject];
      [myInvocation setSelector:doneSelector];
      NSDate * myDate = [datePicker date];
      [myInvocation setArgument:&myDate atIndex:2];
      NSString * result = nil; 
      [myInvocation retainArguments]; 
      [myInvocation invoke];
}

This works fine on most objects, but I am running into trouble when passing in a Core Data (NSManagedObject) as the targetObject. The object looks like this:

Transaction.h

#import <CoreData/CoreData.h>

@interface Transaction :  NSManagedObject  
{
}

@property (nonatomic, retain) NSString * message;
@property (nonatomic, retain) NSDate * date;

@end

Transaction.m

#import "Transaction.h"

@implementation Transaction 

@dynamic message;
@dynamic date;

@end

If I set this object in my controller as the targetObject, I can call the "setDate:" method directly without issue.

[targetObject setDate:[datePicker date]];

But when I try to invoke it with the @selector, I get 'Program received signal: "EXC_BAD_ACCESS”.'

I imagine this has something to do with the @dynamic methods used in the NSManagedObject and when they are created, but I don't know enough about that process to know how to or if I can workaround this to get it working. I have tried explicitly creating the "setDate:(NSDate *)aDate" method in the Transaction object, and that works, but I am wondering if I should do that and how it might the NSManagedObject.

Can I access these setter methods with a @selector without explicitly defining them?

+1  A: 

Agreed w/ NSD here. You should start by simplifying this code to the much simpler -performSelector:withObject: version:

- (IBAction)saveDate:(id)sender {
      [self.targetObject performSelector:self.doneSelector withObject:[self.datePicker date]];
}

If that still has trouble, we can start debugging where the real problem is. NSInvocation is a very fancy object for solving this kind of simple problem.

If you still get the crash, then you'll want to look at the actual stacktrace to see what variable is not being correctly initialized or being over-released.

Rob Napier
Seconded. And EXEC_BAD_ACCESS is almost always calling a method on an object that's been released. (Maybe a pointer that's outlived its Managed Object Context or something?)
Sixten Otto
Wow, I can't believe I didn't dig a little deeper to find that much simpler method. It seemed overly complicated, but I got locked in on NSInvocation. This method appears to eliminate the EXC_BAD_ACCESS error. Simple, elegant, and working. I like it! Thanks to you all.
kevindayton