Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

tronthomas

macrumors newbie
Original poster
Sep 21, 2008
2
0
What can people tell me about why this program is crashing:

Code:
#import <Foundation/Foundation.h>

@interface Action : NSObject 
+ (void)execute;
@end

@implementation Action
+ (void)execute
{
	NSLog(@"The action was executed.");
}
@end

@interface ActionPerformer : NSObject {
@private
	NSMutableDictionary* _namedActions;
}

+ (ActionPerformer*) performer;
- (void)addAction:(NSString*)action withClass:(Class)class andSelector:(SEL)selector;
- (void)performAction:(NSString*)action;
@end

@implementation ActionPerformer

typedef void(^ActionBlock)();

+ (ActionPerformer*) performer
{
	ActionPerformer* performer = [[ActionPerformer alloc] init];
	performer->_namedActions = [NSMutableDictionary dictionary];
	return performer;
}

- (void)addAction:(NSString*)actionName withClass:(Class)class andSelector:(SEL)selector
{
	ActionBlock block = ^(){ [class performSelector:selector]; };
	// Verify things work
	block();
	[_namedActions setObject:block forKey:actionName];
}

- (void)performAction:(NSString*)actionName
{
	ActionBlock block = [_namedActions objectForKey:actionName];
	// Crash happens here!!!
	block();
}

@end

int main()
{
	@autoreleasepool {
		ActionPerformer* performer = [ActionPerformer performer];
		
		[performer addAction:@"action" withClass:[Action class]
			andSelector:@selector(execute)];
			
		[performer performAction:@"action"];	    
	}
    return 0;
}

I am building it on Mac OS X 10.6.8 using Xcode 4.2 with Apple LLVM compiler 3.0
 

chown33

Moderator
Staff member
Aug 9, 2009
10,747
8,420
A sea of green
Since you didn't post the crash log or stack trace, I'm not going to bother guessing.

Instead, I'm just going to say "Use NSInvocation". Seriously, trying to do what you're doing with blocks is silly. Especially when NSInvocation already exists and is well-tested (hint: it's instrumental in Distributed Objects).

And I'm also going to suggest NOT using class-methods. Use instance methods, even if it means targeting an instance of the Action class instead of targeting the Action class itself. So:
Code:
@interface Action : NSObject 
- (void)execute;
@end

@implementation Action
- (void)execute
{
	NSLog(@"The action was executed.");
}
@end
 

kpua

macrumors 6502
Jul 25, 2006
294
0
You need to explicitly copy the block to allow it to live beyond the scope it's declared in.

Blocks live on the stack by default, unlike every other object that starts off in the heap. Adding a stack-based block to an array will call -retain on it, sure, but that doesn't actually have any effect on its lifetime. The only way to get the block to the heap is to -copy it. Once there, it will respond properly to -retain and -release. (don't forget to balance the -copy too!)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.