Objective-C : How to access properties of an object within another class? - objective-c

I'm creating a game in objective-c and need to detect when two objects intersect frames.
I typically would detect this by using
if (CGRectIntersectsRect(object1.frame, object2.frame)) {/*do something*/}
My only issue is that I've created individual class files for each object. I have object1 in class1 and object2 in class2, so I can't access object1 in class2.
I tried passing the object as a parameter but received a strong id error, so I assume objects aren't allowed to be passed. How I can access the object1.frame in class2? I'm still new to objective-c, so I would appreciate any advice! Thanks in advance, let me know if you need any more information.
EDIT: Sorry for the ambiguity, I wasn't very clear. I declared a UIImageView or "object1" in class1.h and is used throughout the class1.m file.
I have another class where I declared another UIImageView "object2" in class2.h and class2.m. At one point during the class2.m file, I need to see if object1 and object2 are intersecting.

Actually as they are both image views neither of them should really be dealing with intersecting with each other. The better route is to have a third class that has a connection to each of the first two classes that takes care of detecting the collisions or to create a C function that just takes any two instances of UIImageView that conforms to an appropriately designed protocol and if there is a collision tells the objects to handle it.
void checkForCollision(object1, object2) {
if (CGRectIntersectsRect(object1.frame, object2.frame)) {
[object1 handleCollisionWith:object2];
[object2 handleCollisionWith:object1];
}
}
With something like this it makes life easier when later on you need to detect collisions involving a third or fourth object. Both objects do need to have the same superview though or this will not work.
Also, you can pass objects but you normally pass by reference. In order for object1 to tell, or ask, object2 anything it has to have a pointer to it the same applies in reverse.

Related

Changing the class of an ivar (to a derived class), in a subclass

Assume I have two base classes, Container and Gizmo. Class Container has an instance variable of class Gizmo.
Now I subclass Container (call that SubContainer) and I also subclass Gizmo (SubGizmo). In some of the methods of SubContainer I need to send a message to some properties that Gizmo doesn't have but SubGizmo does. Is there any way to override the ivar to be of class SubGizmo in SubContainer, so I can send those messages?
Right now I can make it work by casting my inherited ivar to SubGizmo every time I need to use such a property or method.
Here is why I want such a behavior: I already have a game that works, but the more modes I add, the harder it gets to maintain. If I want to change/add a method that will run on each mode; I would need to go to three different game - controller objects and make the change.
By subclassing, I wanted to keep the main game mechanics in the base classes and create a subclass for each mode. this way a change I make in a base class would reflect on each mode. However each controller and game object have new methods for different modes, and they send messages to each other. This is where my problem is arising from.
just introduce type safety and conversion logic using an approach like this:
#interface SubContainer ()
- (SubGizmo *)subGizmo;
// setter is often unnecessary
- (void)setSubGizmo:(SubGizmo *)pSubGizmo;
#end
#implementation SubContainer
...
- (SubGizmo *)subGizmo
{
Gizmo * ret = self.gizmo;
// sanity check the type to ensure this is properly initialized,
// or return nil if holding a Gizmo is valid in this context:
assert([ret isKindOfClass:[SubGizmo class]]);
return (SubGizmo *)ret;
}
- (void)setSubGizmo:(SubGizmo *)pSubGizmo
{
self.gizmo = pSubGizmo;
}
- (void)addWater
{
[self.subGizmo addWater];
}
#end
however, the creeping complexity suggests more variations in types is worth consideration.
just use type id for your ivar, you only have to include the proper header file to avoid warnings.
The easiest way would be to use SubGizmo in Container, not Gizmo. :-)
However, if you can't do that directly for some reason, you can modify SubContainer at runtime (seek for class_addIvar or class_addMethod, I can give you an example when you need it), but that does not help to avoid Xcode's warning.
You canu use NSNotifications for sending updates to all your game controllers.

sharing an object between two viewcontrollers in objective c

I am guessing that this maybe a silly beginner question, but I cant figure out the answer to it. I basically have two view controllers in my iphone app that I would like them to share a third class (.m and .h) that suppose to hold data that both suppose to use. Lets say for example that both views are displaying locations and presenting a table with some of this information manipulated - what i'd like to do is to have a third class, like an engine, that will do all that, and those views will just instantiate this engine and read the table/location data when needed.
My question is - how can I instantiate this engine in both my views but have in fact only one copy of the engine that both views read from. I know that when instantiating twice, two copies are being created, and i dont want that. i am hoping to make this engine "global".
is this possible at all in objective c? what would be the best way to go about that?
Thank you much all.
You might consider adding a #property to both view controller's that points to your model ("engine") object. When the view controller's are created, you can set that #property to point to the model. If the #property is retain, then it won't copy the model.
You have a lot of options when it comes to this. Following an MVC approach, you are on the right track in that you should have a single copy of this data (the model). How you get that to your view controllers is up to you. I'll give two ways and you can see which works better in your situation, but there more than ways to do this. Option 1) Create a singleton to house your model/data. You've probably seen this in the SDK when using stuff like ... = [SomeController sharedInstance]. The two view controllers can just use that shared instace. Option 2) You can instantiate the model somewhere at startup and pass it directly to the view controllers. Whether it's a singleton or not is not their concern. They just know they have access to some data. You can create a property like #property (nonatomic, retain) TheData *theData for each of the view controllers and pass it that way.
Since you only have one of these "Engines", I'd suggest going the singleton route.
Create a static method that returns an instance to the object you want shared, then you can use that method in each class.
forgive my syntax... I don't have my objective C stuff in front of me atm, but essentially you'll want to do something like the following.
EngineClass.h file:
STATIC EngineClass * getSingleton();
STATIC EngineClass * INSTANCE;
EngineClass.m file:
STATIC EngineClass * getSingleton()
{
if(INSTANCE == null)
{
INSTANCE = new EngineClass();
}
return INSTANCE;
}

Return the object of which something is a property?

Lets say I have an object with a number of properties, one of them being a CALayer.
Throughout my view, I have to hitTest layers. After I've got the layer, I then need to get at the object of which the layer is a property, or 'to which it belongs'. Is there anyway to return the owner of a property?
Thanks!
We have three different things here:
The property
The instance variable behind the property
The CALayer
These are three distinct things. The property belongs to the object's class, and tells the compiler how to go about accessing the instance variable (if I can be a little bit hand-wavy). The instance variable belongs to the object, and points to the CALayer. And the CALayer just does its own little CALayer thing.
Several different instance variables used by any number of properties either from the same object or many different objects can all point to that same CALayer object.
So the question becomes: Does an object keep a list of all the variables that are pointing to it?
And the answer is: Unfortunately, no.
One approach is to iterate through your objects, comparing the layer property to the CALayer retrieved by hit-testing:
MyObject *theObject = nil;
for ( MyObject *obj in self.objects ) {
if ( obj.layer == theLayer ) {
theObject = obj;
break;
}
}
Another approach is to subclass CALayer and add ivar/property pointing to the object it represents. To avoid retain cycles it should be #property(assign) MyObject* representedObject. It makes getting the object trivial, but requires subclassing CALayer.
I wold suggest you pass around the parents of the CALayers instead of the actual layers when you do the hit-testing, so that you never need to back up to the parent.
You ca not find the parent of a property object, unless you implemented a both-ways relation. Both-ways relations are generally bad, since it can easily introduce retain cycles.
The general solution to this in Cocoa is to use delegates, turns out that the delegate for a CALayer is the UIView it is backing. So in the case of most CALayer instances you can back up to it's parent through the delegate. Do notice I say most, not all, so it is not a silver bullet.

Accessing an object outside scope in a controller class

In my controller class, I initialize two instances of a model class (whose header is properly imported into controller class) with an NSButton. The model is really simple, just 4 members and one method - attack(). Making a silly text game!
- (IBAction)startGame:(id)sender {
Combatant *hero = [[Combatant alloc] init];
Combatant *enemy = [[Combatant alloc] init];
[console insertText:#"You have created a hero! An enemy approaches...\n"];
}
So now I have these two objects sitting there. Or do I? Because this other button, the one that's supposed to make them fight, has no idea what hero and enemy are, or that they have a class method that makes em' fight!
- (IBAction)attack:(id)sender{
[hero attack:enemy]; //Use of undeclared identifier, blah blah.
[console insertText:#"You attack the enemy! Woah!\n"];}
I get that if I initialized those objects in the attack method, then I could use them, so I gather this is something to do with scope. But I don't like the idea of sending model objects to controller methods, that seems silly.
Let me apologize: yes, this is a stupid, high-level question about the structure of Cocoa. Sorry. But I figure one of you will know exactly what I am not doing and tell me to do it!
In short, what is the Cocoa way of doing things in this situation? Thanks in advance.
-Alec
When you declare a variable in a method, it is a local variable, which means it only exists in that method. The same goes for variables you declare in functions.
If you want the variable to exist in all instance methods in the class, you need to make it an instance variable, which you do by declaring it in that { … } section in the class's #interface.
Note that any objects you store in instance variables, the instance should own. This means three things:
You'll need to either retain the object (and thereby own it) or make a copy (which you will then own) before assigning it to the instance variable.
Since you own it, you'll need to release it in the instance's dealloc method.
If you decide to replace it with a different object, you'll need to release the former object (since you still own it) and retain or copy the new object (in order to own it).
See the Objective-C Programming Language and the Memory Management Programming Guide for more information.

Passing a value from one object into another with Objective-C

I have a class called GameScene, with is a subclass of a cocos2d Scene.
In there I have two layers. GameLayer and ControlsLayer. You can probably tell already that I want the ControlsLayer to move stuff around in the GameLayer. To be precise, I'm trying to control a cPBody in the GameLayer from the ControlsLayer.
At the moment, I'm trying to route the instructions from the ControlsLayer, back up into the GameScene and then back down into the GameLayer. If that makes sense. Anyway, I can't get it to work. I have a PHP background so I think I'm incorrectly applying my PHP experience to Obj-C.
My thinking is, I should be able to access a property inside a class/object using something like
aThing *someThing = someInstance->aThing;
From the sample code I've been looking at, it looks like this should work. But it doesn't. Here's the code, stripped down to as much as possible http://pastebin.com/d49c9d0be
Rather than knowing how to fix this particular issue, The question is, what don't I understand?
In Objective-C you need to define accessor methods to get at the instance variable, you can't directly access it like that unless you're calling it from the same class type (for instance when you're implementing the NSCopying protocol and need to set private variables, but don't worry about that now).
The easiest way to do that is to define a property in your header using #property(retain) SomeClass *name;, and have Objective-C generate it by putting #synthesize name = instanceVariable; in your implementation. You can then access the variable outside of that class using object.name; or [object name];. For more information take a look in the documentation for properties and Object Oriented programming.
You're not exposing the gameLayer.myBody property in any shape. You'd have to use the #property declaration (assuming objective-c 2.0) (here's an example).
I don't have any PHP background, so I don't know how it may be different in PHP.
The correct way to access a property in an object is as follows:
aThing * someThing = someInstance.aThing; // new style
or
aThing * someThing = [someInstance aThing]; // old style
If you were coding in c, the -> operator would make sense. In objective-c, however, objects are always passed around through pointers. No objective-c variable ever actually holds an object, they just hold pointers to objects. The language designers simply decided to use the [] or . syntax to access members, so that's what we have to do!