views:

147

answers:

3

Alright, so I'm running into an issue with my code. What I have done is subclassed UIButton so I can give it some more infomormation that pertain to my code. I have been able to create the buttons and they work great. Capiche.

However, one of the things I want my subclass to hold is a reference to a NSMangedObject. I have this code in my header file:

@interface ButtonSubclass : UIButton {
    NSManagedObjectContext *context;
    NSManagedObject *player;
}

@property (nonatomic, retain) NSManagedObject *player;
@property (nonatomic, retain) NSManagedObjectContext *context;

- (id)initWithFrame:(CGRect)frame andTitle:(NSString*)title;
//- (void)setPlayer:(NSManagedObject *)aPlayer;

@end

As you can see, it has a instance variable to the NSMangedobject I want it to hold (as well as the Context). But for the life of me, I can't get it to hold that NSManagedObject. I run both the @synthesize methods in the Implementation file.

@synthesize context;
@synthesize player;

So I'm not sure what I'm doing wrong. This is how I create my button:

ButtonSubclass *playerButton = [[ButtonSubclass alloc] initWithFrame:frame andTitle:@"20"]; //works

        playerButton.context = self.context; //works
        playerButton.player = [players objectAtIndex:i]; //FAILS

And I have initilaized the players array earlier, where I get the objects. Another weird thing is that when it gets to this spot in the code, the app crashes (woot) and the the console output stops. It doesn't give me any error, and notification at all that the app has crashed. It just... stops. So I don't even know what the error is that is crashing the code, besides it has to do with that line up there setting the "player" variable. Thoughts and ideas? I'd love your wisdom!

+1  A: 

Try adding some debug code first

ButtonSubclass *playerButton = [[ButtonSubclass alloc] initWithFrame:frame andTitle:@"20"]; //works
playerButton.context = self.context; //works
NSLog(@"total players: %d", players.count);
NSLog(@"players: %@", [players objectAtIndex:i]);
playerButton.player = [players objectAtIndex:i]; //FAILS

this probably reveals the error

Martin Brugger
+1 This is a good way to find the presumed out of bounds error.
TechZen
+1  A: 

There is no particular reason why the code you have shouldn't work. You can assign a NSManageObject instance as an attribute. The simplest explanation for the crash is an out of bounds error for the array. When you don't get an error from the consoles its usually because the debugger has crashed. That is usually caused by having some kind of recursion that causes the debugger stack to overflow.

However, putting data logic in a view element like a button is very, very poor practice. This completely breaks the MVC design pattern and will make your code fragile and hard to maintain. UI elements should be "dumb" and only understand how to display any data handed to them, they shouldn't be involved in actually tracking the data itself. That is the function of the controller and the data model respectively.

Ideally, the "player" object should be tracked by the data model which the controller then links to the appropriate UI button or other UI element. Putting the tracking of the player in the data model makes the design flexible which makes it easy to expand, reuse and maintain.

TechZen
I was trying to figure out a way to do this, when I finally decided that I could use the Tag attribute on the buttons to keep track of them. Thanks!
Wayfarer
A: 

You can't create the managed object context simply by declaring it a property and adding @synthesize. The managed object context is created by the application delegate and you call it like this:

[[NSApp delegate] managedObjectContext];

I have no idea how you initialize the players array, but I have a suspicion that it does not contain the objects you think it does: NSManagedObjectContext only has methods that return NSSet's and while

[[[NSApp delegate] managedObjectModel] entities];

does return an array, it contains instances of NSEntityDescription. I suggest you start by looking at the code of your application's application delegate (AppDelegate.m) to learn more about the entry points to the Core Data store.

Elise van Looij