Scope of an instance Variable in Objective C - objective-c

The question might sound pretty naive, ut this is really troubling me.
I am trying to set an instance variable by calling an instance method method of a ViewController from another view controller. Basically here are the steps
I am in ViewController1
Initialized an object of ViewController2
Called an instance variable to set some values to the instance variable of ViewController2
Then finally called the presentModalViewController to load the view controller
Using the variables in viewWillAppear method, But the app crashes and on debugging it shows BAD_EXEC
I have tried printing the same in instance method and it prints there but crashing when trying to use somewhere outside the method.
I have also defined the property and also ynthesized the variable.
The only problem I can figure out is I am initializing the variable in methos ...Does that limit the scope of the variable.
Any kind of help would be highly appreciated.
Thanks in advance!!

Most likely you're running into a memory management error, and without code all I can advise is to make sure you are familiar with Cocoa's memory management system:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

If you are creating the properties for the instance variable and synthesizing the getters and setters, you should be able to set the instance variable using dot notation:
viewController2.variable = foo;
or by using the setter method:
[viewController2 setVariable:foo];
You should not be trying to access the instance variables directly. By default, the scope is set to Protected, meaning that you can only access it by methods in the class, it's subclasses, and in category extensions.

Related

In Objective-C, do we have to use self.var or just var to reference a property of self?

If I add a property to the ViewController
#property (strong, atomic) UIView *smallBox;
and synthesize it in the .m file, the variable can actually be referenced just by smallBox inside of any instance methods.
But then, self.view cannot be replaced by view, even though view is defined as a property of UIViewController too. Why the difference and what is the rule?
self.view and view/_view are not the same thing. Depending on how you create your instance variables, view or _view refer to the actual object instance variable. It is dangerous to access this directly, and you should only do so in init, dealloc or in accessors. Everywhere else, you should use self.view.
self.view is exactly the same as [self view], which passes the message "view" to the object "self" an returns the result. By default, when an object receives a message, it executes the method with that name, and the default implementation of view will return the value of the related instance variable (either view or _view).
In older versions of Xcode, #synthesize view would create an instance variable called view. In the latest versions of Xcode, declaring a property view will will automatically create an instance variable called _view in many cases, even without #synthesize. This change makes it easier to notice when you are accessing the ivar directly.
In short:
except in init, dealloc and the view accessors (if you custom write them), always use self.view.
In those methods, you should refer to it as _view.
If you are writing for the latest Xcode, do not include #synthesize at all. If you are writing for a slightly older Xcode, use #synthesize view=_view;
self.view does not mean "the value of the instance variable." It means "the result of passing the message 'view'" which is generally implemented as returning the instance variable.
You can't access the view member directly because it's declared as #package visibility in UIViewController. This prevents your code from accessing it. (Normally, you wouldn't want to access instance variables of your superclasses directly anyway.)
For your class's own properties, you can access the instance variable directly, but you need to be aware of the memory management implications of this. (As well, as Rob points out, as any other behaviours you're side-stepping by avoiding the accessor.)
Apple defined properties usually contain an underscore before their name, so when you use self.view, it is actually getting the instance variable _view from the object. You cannot use _view in code, as it will cause a linker error on compiling, but Xcode will still highlight it for you. Another way of accessing the instance variable for self.view is by self->_view, but again, this causes a linker error. The reason for these linker errors is because the compiled libraries do not contain the symbols for _view; even if its declaration can be found in UIViewController.h.

Where should I initialize variables in objective c?

In objective c, should I overwrite the init method to initialize my variables? If the variables are properties can I still access them the usual way to set their initial value?
In objective c, should I overwrite the init method to initialize my variables?
Yes. Specifically, the designated initializer(s).
Your subclass may also specify another construction stage (e.g. viewDidLoad). Also, the object's memory is zeroed when it is allocated, so you do not need to set them explicitly to 0/nil (unless you find it more readable).
If the variables are properties can I still access them the usual way to set their initial value?
You should avoid using the object's instance methods/accessors, and access ivars directly in partially constructed states (notably the initializer and dealloc). There are a number of side effects you will want to avoid - Example Here;
you can initialize you variables in viewDidLoad method of a view controller.
Variables declared in the classes interface will automatically be initialized to there default value, 0 for integral values and nil/NULL for classes and pointers. If you need to initialize the variables to other values then you need to override a guaranteed entry point for you class. A custom class inheriting from NSObject for example you will simply override init. If you are working with a view controller loaded from a NIB file then you could override initWithCoder: or – awakeFromNib. You should always check the documentation for whichever class you are inheriting from and find the designated initializer for that class. Sometimes you will need to set a common initializing method and call it from various initializers. Also if you have a variable that is also a property it is recommended that you should set the property and not the variable directly.
should I overwrite the init method to initialize my variables?
Instance variables: yes, although they are by default initialised to 0/nil/false already.
If the variables are properties can I still access them the usual way to set their initial value?
Yes you can. Apple advises against it because of the danger that a subclass has overridden the set accessor to do something unexpected. In practice, this is rarely a problem.

Local declaration of tableView hides instance variable?

I understand why I get the warning in the title when I define my own tableView property in my own class and then use a local variable name tableView.
What I want to know is why DON'T I get this warning when I derive my class from UITableViewController, which has it's own tableView property? Does the compiler/editor only look at my class and not the parent class?
When you’re implementing a method, parameters/local variables share the same namespace as instance variables. However, they don’t share the same namespace as declared properties, which means that a class can declare a property named someData (or inherit it from one of its superclasses), have the backing instance variable with some other name, and the implementation of a method of that class can also have a parameter/local variable named someData — the compiler won’t give a warning in that case.
I assume you have a declared property named tableView and also an instance variable named tableView, the latter being either explicitly declared in the interface or automatically created when synthesizing the property. In that case, if you define a method that takes a parameter named tableView or declares a local variable named tableView, this local declaration will hide the instance variable named tableView (but not the property).
In the case of UITableViewController, there is no instance variable named tableView. There is a declared property named tableView which, because it’s in a different namespace, won’t be hidden by a local (variable) declaration.
One easy fix to avoid the compiler warnings is to give a different name to the instance variable. For instance, the instance variable can be named _tableView, and the property would still be named tableView but synthesized as #synthesize tableView = _tableView.
Post the exact code that is generating the warning.
"Local declaration" typically implies that you have something like:
- (void) foo {
int thisIsTheNameOfAnInstanceVariable;
}
There are likely other permutations via which you could cause this to happen, though.
I'm not exactly sure if I'm answering this correctly, but if you want to access variables in the super classes (e.g. UITableView, since your class is deriving form it) you have to use "self." then the variable name form the super class. Whenever you directly call a variables, e.g. 'myVariable', it will only look for local instances.

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!