Objective-C private instance variables definition - iphone

Is there any difference in where we define private instance variables? As I understand there are two possibilties:
1) In header file
#interface MyViewController : UIViewController {
#private
NSString *fooString;
}
2) Second way is to define it in the implementation:
#implementation MyViewController
NSString *fooString;
What is the difference? Cheers!

In 2nd case fooString is not instance variable - it is global variable, so your two cases are completely different

The first way defines a private instance variable. Each object of class MyViewController will have its own private fooString.
The second way defines a global variable. There will be only one instance of fooString and it will be visible to any source file with the following declaration:
extern NSString *fooString;

The first one is a unique fooString per MyViewController that you create.
The second is a fooString that every MyViewController shares.

Related

How to pass value to a variable in an inherited class

I have a class called TimeLineViewController which is inherited from MyViewController. I need to pass a value to a variable from MyViewController to TimeLineViewController. How can i do it ?
MyViewController.h
#interface MyViewController : TimeLineViewController {
.....
}
In TimeLineViewController.h i have a String *str assigned. From MyViewController.m i need to pass a value to the String *str variable in the TimeLineViewController class. How can i do this.
I tried the following from MyViewController.m but none worked.
[super str]=#"hi";
The point of inheritance is using existing functionality and extending it for specific needs by the sub class(es)
So... If your TimeLineViewController inherits from MyViewController there is no need to declare the member again in TimeLineViewController and you can just use it with since it was already declared for MyViewController:
self.str = #"hi";
If str is a property inside the class TimeLineViewController you can access it via inheritance in MyViewController. So if you change it in MyViewController it changes also for the father.
Remember:
A
|
B
if in A you have a property c then you can do B.c.
Read this.
From the apple's doc,
The instance variable is accessible within the class that declares it
and within classes that inherit it. All instance variables without an
explicit scope directive have #protected scope.
So you can just use as
super.str = #"hi";
You should have setter or property in TimeLineViewController.
Then you can use
[self setStr:#""];
or
self.str = #"";

Can we have retain property with no getter and setters on Obj C elements?

Ok, so I was reading some articles regarding Good Programming Practices and I came across a statement which said that making all your Elements public for your classes isn't a good idea.. aka The concept of Encapsulation.
Now in Objective C, When I create a element for my class, I do the following, consider an NSMutableArray
#property (nonatomic, retain) NSMutableArray* myArray;
WHY I DO THIS?
So as to give the Retain property to myArray and therefore, giving it a simpler Memory Management cycle. Later on, I initialize the myArray in viewDidLoad as
self.myArray = [NSMutableArray arrayWithCapacity:0];
Later in Dealloc...
self.myArray = nil;
WHAT ELSE HAPPENS
By giving this property and synthesizing myArray in .m file, what I am unknowingly doing is making Public Getters and Setters for all the elements of my class.
Also, the auto-generated UI Elements from Xib files, do have the same declarations applied.
That isn't a nice idea to keep creating public Getters and setters for each and every element of your class, right?
So, there's absolutely no kind of encapsulation applied! Please correct me if I am wrong here and help me with any solutions!
Thanks!
Simply use the principle of Class Extensions that allows you to put part of your declarations in your .m file, thus making it invisible in your header and invisible from other classes.
(This is Apple's recommended way to declare private methods and properties, by the way)
YourClass.h
#interface MyClass : MySuperclass
// public properties
// public methods
#end
YourClass.m
#interface MyClass()
// This is a class extension
// put here private properties
// and private methods too
#end
#implementation MyClass
// And your implementation of course here
#end
You can even declare a property as readonly in your public interface (in the header file) and redeclare it as readwrite in your private interface (in the class extension in the .m file) for example.
See the Apple documentation for more details.
Note that:
There is NO NEED to declare the instance variable if you declare the property: the compiler will generate it automatically for you so you don't have to bother and to declare it in the .h. In the latest version of the compiler (Modern Objective-C) there is even no need for the #synthesize directive as it now generate it automatically if not present (see doc)
If you prefer to declare instance variables anyway, you can also do this in the class extension in your .m the same way you would do in your .h. That's a way to hide instance variables from the public header too. In general I really rarely use instance variables (as declaring only the properties is sufficient) and if I really need an ivar I declare it in the class extension to make it not visibile in the public header.
You can declare the property in your class.m file, so the getter and setter methods are accessible only in that class. An example:
MyClass.h
#interface MyClass : NSObject {
NSMutableArray *_myArray;
}
#end
MyClass.m
#interface MyClass ()
#property(nonatomic, retain) NSMutableArray *myArray;
#end
#implementation MyClass
[... MyClass implementation ..]
#synthesize myArray = _myArray;
#end
So you can use "self.myArray" only in "MyClass.h" file.

Unable to access object of other class

I am accessing object of one class in the another class. But instance variable is Showing null.
This is my code.
fvcObj = [[FirstViewController alloc]init];
NSLog(#"%#",fvcObj.user);
Which things to take care in declaring object of another class?
Thanks.
As PengOne has said it is a new instance of the class FirstViewController and it cannot hold the data which you have assinged to the "user" variable in FirstViewController class. I think you want to pass data from one view controller class to other. If so then declare a method in the class to which you want to send the data and call this method from the other class and pass the data as a parameter of the method.
Hope this might help u.
Happy coding
fvcObj
is a new instance of FirstViewController, so my guess is that the user property has yet to be defined.
In header file (*.h) for example:
#interface MyClass : NSObject
{
NSString *someString;
}
#end
#property (nonatomic,retain) someString;
In implementation file (*.m)
#synthesize someString
This create setter and getter for someString

How do I work between classes in Objective-C?

At the moment, the majority of my code is in the same viewcontroller, and i'd like to move some of it over to other areas. Such as moving the animations all over to somewhere else. But then how do i reference things which are in another class? And how do i reference back from that class to items in my viewcontroller class? Not going this has always disuaded me from doing it.
there is a couple of ways you can achieve that.
one way is the cocoa delegate #protocol way, the second way could be creating references to each object in the other class.
for the first way you can do something like this:
#class Class2;
#interface Class1 : NSObject {
Class2 *cls2Pointer;
}
#property Class2 *cls2Pointer;
#end
#class Class1;
#interface Class2 : NSObject {
Class1 *cls1Pointer;
}
#property Class1 *cls1Pointer;
#end
int main(){
Class1 cls1Obj = [[Class1 alloc] init];
Class2 cls2Obj = [[Class2 alloc] init];
[cls1Obj setCls2Pointer:cls2Obj];
[cls2Obj setCls1Pointer:cls1Obj];
}
the second way, is to declare a protocol in one/both of the classes to be able to pass arguments and call different methods on other objects:
#protocol Class1Delegate
- (void)class1:(Class1)obj MethodWithArg:(id)arg;
#end
#interface Class1 : NSObject {
id <Class1Delegate> delegate;
}
#end
#interface Class2 : NSObject <Class1Delegate>{
}
#end
#implementation Class2
- (void)class1:(Class1)obj MethodWithArg:(id)arg {
//do stuff when called from the 1st class
}
#end
You might like to look into this here - to create static classes in objective c and then reference them in a separate file by classname - as in the view controller quoted in the linked example.
Otherwise you can just create a new class within a separate .m file and then code it such that the calling method in another class will first create an instance of this new class and then invoke the necessary method on this instance.
Hope this helps.
Basically what you do is that you create one or more classes, move the code over to these classes and then create instances of these classes in your viewcontroller.
so if you had a method in your view controller
-(void)foo;
you would create a new class say C and move the method there.
then in your view controller you would create an instance variable of that class e.g.
C* myC;
then alloc/init and then call the foo method. This is not object oriented in the sense that foo is not really related to C in any way so method foo could have just been a static method not relating to the instance and as such called just like any other method but as [C foo] instead of [self foo] from the view controller.
the other more OOP method would be to move functionality that belongs to together into a separate class like animation in your example.

How to update a variable in one class from another?

I need to set a variable in Class A from Class B. To test this, I have a while loop running in Class A that continuously prints the variable via NSLog. However, no matter what I try, I cannot get Class B to update the variable in Class A in such a way that Class A can read the changes made by Class B. I am pretty sure I have everything hooked up properly in IB. Here's how I have things set up:
//Class A
#interface AppDelegate : NSObject {
NSString *teststring;
}
#property(readwrite,nonatomic,retain) NSString *teststring;
#end
#implementation AppDelegate
#synthesize teststring;
-(id)init{
self = [super init];
if(self) {
teststring = [[NSString alloc] init];
}
return self;
}
-(void)awakeFromNib
{
while(1){
NSLog(#"teststring is %#",teststring);
usleep(500000);
}
}
#end
//Class B
#class AppDelegate;
#interface otherClass : NSObject {
AppDelegate *appdel;
}
-(IBAction)doTest:(id)sender;
#end
#implementation otherClass
-(void)awakeFromNib
{
appdel = [[AppDelegate alloc] init];
}
-(void)doTest:(id)sender
{
appdel.teststring = #"Test";
NSLog(#"Set teststring to %#",appdel.teststring); //this works
}
#end
You are thinking too much about classes (as seemingly some sort of “department” of code) and not enough about objects, and both your wording and your problem demonstrate this.
You have your instance of otherClass creating a second instance of the AppDelegate class. You already had one AppDelegate instance, which is the actual application delegate (because, I assume, you have it in your nib and you have it hooked up to the application's delegate outlet there); now, in -[otherClass awakeFromNib], you are creating another.
You then tell this second AppDelegate instance to set its teststring property to #"Test", and then you ask your second AppDelegate instance for the value of that property, and your second AppDelegate instance dutifully shows you the value you gave it.
The first instance doesn't have the same value for its teststring property because the otherClass object never gave that instance a value for its teststring property. Note that the variables you define in the #interface section are instance variables, which is why different instances of a class can and usually will have different values in those variables. Properties are likewise per-instance, being usually backed by these instance variables.
AppDelegate A (the real application delegate, created in the nib) and AppDelegate B (created by the otherClass object, not anything's delegate) are two separate instances of AppDelegate, with separate teststring variables.
Thus, the solution: Have the otherClass instance talk to the real application delegate, not an AppDelegate instance that it created itself. You could ask the application for its delegate, or (if the otherClass object is in the MainMenu nib) give it an outlet to the application delegate, just like the application has.
However, piling too much stuff into your application delegate class is bad design; each class should have one specific purpose, and generally should fit neatly within one of the Model, View, and Controller classifications. So, assuming your otherClass object should be a controller, move the property into otherClass and make that object the controller of whatever needs the property.