I'm writing a simple card game for iPhone. The cards are in cardset containers which are subclasses of UIScrollView. The cardsets are in a desk container which is a UIViewController. In the cards i overrode the touchesEnded method but I cannot access the main class which contains the desk. How to do it? Should I give a pointer to all the cards to reach the main? Or can I get the parent container?
You can store a reference in the cards.
In the cards interface, define something like
#interface cards
{
DeskController *deskp;
}
#property (nonatomic, assign) DeskController *deskp;
When you create cards, assign the desk reference
- (void) setupCards
{
CardController *card = // allocate card
card.deskp = self;
}
In cards dealloc() or viewDidUnload, set it to nil
self.deskp = nil;
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
My View Controllers are holding my object properties and iVars etc. They shouldn't hold any at all.
** The rest of this post has been heavily edited for clarity as requested. **
My Class Object using the example given by NSBum that seeks to show data handled by one method, is able to continue being used in another.
#import <Foundation/Foundation.h>
#interface MYEmployee : NSObject
#property (nonatomic, strong) NSString *firstName;
#end
now for my VC interface file
#import <UIKit/UIKit.h>
#import "MYEmployee.h"
#interface MYEmployeeDetailViewController : UIViewController
#property ( nonatomic,strong) MYEmployee *employee; // as suggested
// UI elements
// a button that picks up from a textfield
- (IBAction)getName:(UIButton *)sender;
#property (strong, nonatomic) IBOutlet UITextField *inputField;
// a button that puts the names in a label
- (IBAction)showName:(UIButton *)sender;
#property (strong, nonatomic) IBOutlet UILabel *employeeNameLabel;
// a second label shows how i've been doing it so far
#property (strong, nonatomic) IBOutlet UILabel *contractorNameLabel;
#end
and the relevant essentials in my VC implementation file where i've used a private contractor property of the VC.
#import "MYEmployeeDetailViewController.h"
#interface MYEmployeeDetailViewController ()
#property (nonatomic, strong) NSString *contractor;
#end
#implementation MYEmployeeDetailViewController
// MYEmployee *employee; // use of an iVar has no effect
- (IBAction)getName:(UIButton *)sender {
// MYEmployee *employee = [[MYEmployee alloc] init]; // no effect except only within the method
// employee.firstName = self.inputField.text; //
self.employee.firstName = self.inputField.text; // class object picks up text from a textField
self.contractor = self.inputField.text; // self does exactly the same
}
- (IBAction)showName:(UIButton *)sender {
// MYEmployee *employee = [[MYEmployee alloc] init]; // resets contents of the iVar to nil
// self.employeeNameLabel.text = employee.firstName; //
self.employeeNameLabel.text = self.employee.firstName; // no joy using the property in .h file as suggested
self.contractorNameLabel.text = self.contractor; // this actually displays the text
}
#end
the employee is not to be seen while the contractor shows up for work (typical, we call them 'Blisters' they only show up when the work is done ;)
Back to serious stuff, the [alloc[init]] and iVar lines are commented out as they had no effect, but left in anyway for the sake of completeness. I didn't think I should edit the title, but my quandry is more or less the same in that "..why can't I use the model simply as a substitution of self?" After all, I outsourced the function
I might try to narrow the focus of the question somewhat; but I'll take a shot at what I think the issues are:
My View Controllers are holding my object properties and iVars etc.
They shouldn't hold any at all.
If you're following good MVC principles, then your view controllers should not have properties that would more correctly belong to the model layer. But given that view controllers are the conduit between the model and the view, certain exposed properties on the controller are essential.
Let's say you have a view controller that displays details about an employee - first name, last name, salary, department, etc. You'll probably want a model object that represents the employee. Let's call it MYEmployee. Next think about what other classes need to know about instances of MYEmployee. Those are the properties exposed in the class interface.
Now, how will our controller work with an instance of MYEmployee? Here, the view controller - let's call it MYEmployeeDetailViewController - needs to know what employee to display, so we need to expose the represented employee in the view controller's interface, e.g.
#property (nonatomic, strong) MYEmployee *employee;
Now MYEmployeeDetailViewController class users can pass an employee to display.
then how does one use Class Objects with the expectation i outlined?
I think your uncertainties revolve around questions like "who owns what data?" etc. My recommendation is to take a step back and really read the documentation on Apple's take on MVC and tap into some resources on object-oriented design. It always helps me to think first about interfaces (class interfaces, not UI) and less about implementation. Mapping out the relationships between classes before coding also helps.
You should be calling init on your new myClass object item instead of just alloc for starters. I doubt you really need to only allocate memory but not actually initialize the object.
Beyond that, your question is a bit hard to follow. You use objects to encapsulate data, and then you expose that data to other objects that might need it. Your view controllers will have objects that handle views, and objects that handle data. The controller will get what it needs from the data objects and pass it as needed to view objects. In this way, the controller will hold the data model itself (if you are doing a proper MVC design).
You say you want your class object to hold data between methods: well, that's what instance variables are for.
I am quite new to Obj C and iOS development and I have come across an issue to which I have no understanding why it is happening.
So to set the scene, I have 2 model classes, Player and Computer Player and a Controller.
Player:
#interface Player : NSObject
-(void) playerMessage;
#end
ComputerPlayer:
#interface ComputerPlayer : Player
-(void) computerPlayerOnlyMessage;
#end
Controller:
#interface viewController : UIViewController{
Player *p1;
Player *p2;
Player *currentPlayer;
}
#implmentation ViewController
-(void)viewDidLoad
{
p1 = [[Player alloc]init];
p2 = [[ComputerPlayer alloc]init];
[p1 playerMessage];
currentPlayer = p2;
[currentPlayer computerPlayerOnlyMessage];
}
However the issue with the above is [currentPlayer computerPlayerOnlyMessage] gives a complier error when ARC is turned on. When ARC is turned off it gives a compiler warning but will run as I would expect it too.
Any help is appreciated to get help me figure why this behaviour is happening.
Isn't it better to define:
- (void)playerMessage;
method in ComputerPlayer class and:
-(void)playerMessage {
[super playerMessage];
[self computerOnlyPlayerMessage];
}
That's a point of inheritance, isn't it? You defined (expecting) your class variable as Player but NOT ComputerPlayer, and if it is ComputerPlayer it will execute specific work only for "computer".
Of course then you execute:
[Player playerMessage]; // Warning should gone
You can test, if it is a computer player
if ([currentPlayer isKindOfClass:[ComputerPlayer class]])
[(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];
It gives you an error because p2 is subclass of Player and you haven't for such a method as computerPlayerOnlyMessage in Player class. This method exists in ComputerPlayer class so you should declare p2 as a object of this type. Chenge line where you declare p2 to:
ComputerPlayer *p2;
First instead of declaring them as ivars like
#interface viewController : UIViewController{
Player *p1;
Player *p2;
Player *currentPlayer;
}
do it with #properties. The reason being is that ivars don't have any getters or setters whereas they are automatically generated if you use '#properties so change to
#interface viewController : UIViewController
// This will auto generate the ivars, getters and setters
#property (nonatomic, strong) Player *p1;
#property (nonatomic, strong) Player *p2;
#property (nonatomic, strong) Player *currentPlayer;
#end
then you can do
#implmentation ViewController
-(void)viewDidLoad
{
p1 = [[Player alloc]init];
p2 = [[ComputerPlayer alloc]init];
[p1 playerMessage];
currentPlayer = p2;
// Could also replace below with [currentPlayer isKindOfClass:[ComputerPlayer class]] use which ever fits best for you and what you want.
// If using below, if you decided to subclass ComputerPlayer class anything that subclassed
// from ComputerPlayer will also make it into this if statement. If iskindOfClass: is used
// Only objects that are kind of class will make it into this if statement.
if([[currentPlayer class] isSubclassOfClass:[ComputerPlayer class]]) {
[(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];
}
}
As #Greg said, computerPlayerOnlyMessage is a method exposed by the ComputerPlayer class, not the class it inherits from, so even if the compiler reports a warning when ARC is disabled, it would be a bad practice to use it.
Explicitly asking the class instance if it implements that method it's a workaround that works though. However in my opinion that solution lacks of good OO design, and I wouldn't use it unless I have a good reason (there are cases when it is handy) - in other OO languages that wouldn't event be possible.
Polymorphism allows an instance of a class to be used as if it were one of its super classes, but not the opposite. You can override and specialize the superclass methods, but you cannot expect a superclass to be aware of methods implemented by any of its subclasses.
I suggest 2 possible solutions:
declare computerPlayerOnlyMessage in the Player class as abstract (with empty body or throwing an exception, acting as a reminder that the method should be overriden in subclasses)
remove computerPlayerOnlyMessage from ComputerPlayer and instead override playerMessage. Thanks to polymorphism, the correct implementation will be called, regardless of whether you are accessing to the class instance as Player or ComputerPlayer
If computerPlayerOnlyMessage is meant to do what playerMessage does, just in a different way, I'd choose option no. 2
This seems like a good place to use protocols.
Here's how I might write your example, where I need to send "player" messages to all instances of Players, specialize on occasion, and send specific "npc" messages other times.
#protocol <NPC>
#property (nonatomic) NSString *someNPCString;
- (void)foo;
- (void)bar;
#end
#interface Player : NSObject
#end
#implementation Player
- (void)message
{
NSLog(#"message");
}
#end
#interface AI : Player <NPC>
#end
#implementation AI
#synthesize someNPCString;
- (void)foo
{
NSLog(#"foo");
}
- (void)bar
{
NSLog(#"bar");
}
#end
#interface viewController : UIViewController
#property (nonatomic) NSArray *humans;
#property (nonatomic) NSArray *npcs;
#end
#implmentation ViewController
-(void)viewDidLoad
{
id<Player> currentPlayer = nil;
humans = [NSArray arrayWithObject:[Player new]];
npcs = [NSArray arrayWithObjects:[AI new], [AI new], nil];
// message all player types, regardless of player or npc
for (Player *player in [humans arrayByAddingObjectsFromArray:npcs])
{
currentPlayer = player;
[player message];
if([player conformsToProtocl:#protocol(NPC)])
{
[(id<NPC>)player foo];
}
}
for (id<NPC>npc in npcs)
{
[npc bar];
npc.someNPCstring = #"str";
}
}
As you can see, this lets you treat npcs like human players, if you need to, let's you ask if the player conforms to the NPC protocol, so you may call the required protocol methods, and let's you reference objects specifically by their protocol.
Protocols begin to make the most sense, in my humble opinion, when you begin to need to "mix in" behavior to various objects.
I have an AMContact object where one of its strong properties is an array of AMEmailAddress objects. One contact can have many email addresses. Can I create a strong property on my email address object that points to the contact object?
I feel like if its a strong reference there could be a retain cycle. If I make it weak, when I do my query to get all of the email address objects, at some point the contact object for each one is becoming nil.
- (NSArray*)allEmailAddresses
{
NSArray *allContacts = [self allContacts];
NSMutableArray *emailAddresses = [NSMutableArray array];
for (AMContact *contact in allContacts) {
if (contact.emailAddresses) {
for (AMEmailAddress *address in contact.emailAddresses) {
[emailAddresses addObject:address];
}
}
}
if (emailAddresses.count > 0) {
return emailAddresses;
}
return nil;
}
#interface AMContact : NSObject
#property (nonatomic, strong) NSString *firstName;
#property (nonatomic, strong) NSString *lastName;
// arrays of AMEmailAddress, AMPhoneNumber objects
#property (nonatomic, strong) NSArray *emailAddresses;
#property (nonatomic, strong) NSArray *phoneNumbers;
#end
#interface AMEmailAddress : NSObject
#property (nonatomic, strong) NSString *label;
#property (nonatomic, strong) NSString *email;
#property (nonatomic, strong) AMContact *contact; // IS THIS OK OR A RETAIN CYCLE?
#end
A short and simple answer to your question: Can I create a strong property on my email address object that points to the contact object?
Can you? Yes. Should you? Absolutely not. Your model design already hints at what the relationship should be - the AMContact objects owns the email addresses, not the other way around. Having email addresses have a strong reference to the parent object is not a good way to go about this. The reference from child back to owner should be weak. The fact that your AMContact instance is going to nil is an issue with scoping and design and you shouldn't use a strong reference to get around this.
As for why your AMContact instance is going nil - It's a bit odd because if the AMContact object goes to nil, its child objects should as well. Is it going nil in the code you posted, or at some other point in some other method? Seeing the code where you're trying to refer to it, and it's nil, would be good.
UPDATE:
If you want a list of contacts that have email addresses, you should change the method to return that. However I'm guessing what you mean is that you want a list of their email addresses with their associated contacts. In this case you would have to flip the relationship around and consider the email to be the parent, and the contact to be the child. Note that if a contact has multiple email addresses then you'll have multiple references to the same contact. Assuming you have a contact property of type AMContact in your AMEmailAddress object, I would add a line as follows:
for (AMEmailAddress *address in contact.emailAddresses) {
//Assign the contact as a property of the email address
//Make sure the contact property is strong
address.contact = contact;
[emailAddresses addObject:address];
}
//Nil out the emailAddresses array
contact.emailAddresses = nil;
UPDATE:
Ok so now you should have a flipped object - emailAddress as the parent and contact as the child, with no strong reference from contact to emailAddress anymore. This means you won't be able to re-use the contact object to get email addresses again though. If you need to maintain the original contact object as-is then you're right, you'll have to store it as a property in the View Controller or in another class - for approaches like this where I have to deal with people objects (for allowing users to invite friends, etc) I use a 'People Manager' singleton and keep all the original objects there.
Well in your case, I think it's very clear that Contact is the owner (parent) of his email addresses, so you will avoid any cycles by just designing this relation in that way, i.e. using weak reference back to contact. If you use a strong ref, then you will have a retain cycle because NSArray retains it's children in emailAdresses.
Now, I would check your program structure to see how and why you lose contacts in that weak reference, something must be releasing them, perhaps, your contact leaves scope prematurely?
You can get more info and advice in this great article on retain cycles, there are some workarounds as well, but I would encourage you to stick to a design that makes more sense.
Is it possible to make an instance of a class and then send/recive data from every scene in a game?
Ex: Let say you make a RPG game, and you want to create a "Party" with information like Party Leader, members etc... and then you want different battle scenes to use the data from the very same instance?
If possible, then how?
/Daniel
First option: use a singleton.
Second option: pass the instance as a parameter to custom init method of a scene:
#interface GameScene1()
#property Party *party;
#end
#implementation GameScene1
-(id)initWithSize:(CGSize)size party:(Party*)party {
if (self = [super initWithSize:size]) {
self.party = party;
.....
}
}
#end
My situation is that I have a few different mini-games in my app. The games are listed in a table view, and when one of them is selected I create the corresponding game object. I need the game objects to have a common parent class, so that I can do common things such as pausing and resuming.
I have a generic GameScene class which has a generic GameLayer property:
#interface GameScene : CCScene {
}
#property (nonatomic, strong) GameLayer* gameLayer;
However each child class of GameScene has it's own type of GameLayer. So for example the SuperMarioBros_GameScene has a SuperMarioBros_GameLayer. The problems arise when I initialize the SuperMarioBros_GameScene:
-(id) init
{
if( (self = [super init])) {
self.gameLayer = (SuperMarioBros_GameLayer*)[SuperMarioBros_GameLayer node];
[self addChild: self.gameLayer];
SuperMarioBros_InputLayer *inputLayer = [SuperMarioBros_InputLayer node];
inputLayer.delegate = self.gameLayer; //ERROR (see below)
[self addChild:inputLayer z:1 tag:2];
}
return self;
}
In general each game will also have an input layer, which will send UI messages to the gameLayer. I get this error:
Assigning to 'id <SuperMarioBros_FireDelegate> from incompatible type GameLayer*
I understand this is happening because SuperMarioBros_GameLayer implements <SuperMarioBros_FireDelegate>, but GameLayer doesn't.
So my question is how do I make the GameScene class hold a polymorphic property that can be any subclass of GameLayer? Keeping in mind that each type of GameLayer may implement different protocols based on their corresponding input layers? Or maybe there's a better way to go about this?
Again, the end goal is to be able to make a call from the main game controller such as
[currentGameScene pause];
which will in turn do something like:
[self.gameLayer pauseGameLoop];
In the implementation file of the SuperMarioBros_GameScene class, you can override the property declaration of the gameLayer property in a class extension:
#interface SuperMarioBros_GameScene ()
#property (nonatomic, strong) SuperMarioBros_GameLayer *gameLayer;
#end
Then you should not get a compiler error anymore.
This will not create new getter or setter functions (these are still called in the superclass), and does not introduce a new instance variable as backing store. It only tells the compiler that self.gameLayer is an instance of the subclass in this implementation file.