Cannot declare variable inside #interface or #protocol - iphone

I have an iOS app built since the beginning with an error in it. Since the source was began constructed from the template, its appdelegate.h looks like:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
myViewController *viewController;
}
BOOL myBool; // intended to be globally accessible
NSString *myString; // intended to be globally accessible
#end
I refer to myBool and *myString from many other .m source files, as to global variables.
Below XCode 3.2.6, I can not remember getting any issues at compile time.
At 3.2.6, warning appeared at compile pointing to these “global” variables in appdelegate.h, saying: “Cannot declare variable inside #interface or #protocol”. As there were no further problems with compilation or during app runtime, unfortunately I did not consider these warnings.
Now, using XCode 4.2, I am unable to compile this source, because the former warnings turned into build errors. They refer and point to each of those lines in the different .m files where there is a reference to the “global variables”.
Is there an easy way to correct this problem, considering that I still want to access these variables/references as global ones?
Additional question: while I am evaluating so far received answers (thanks for all of you), another question: any idea why no warning were given below XCode v3.2.6, and only warnings in 3.2.6 if this is a real error from my side? And why the code was still compiled and could be run without any problem?

They can't go there. You can put them inside the curly braces {} like this:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
myViewController *viewController;
BOOL myBool; // intended to be globally accessible
NSString *myString; // intended to be globally accessible
}
#end
And that makes them global to the implementation class. But if you want them global to every class in your app then you should drop them in your App-Prefix.pch file:
//
// Prefix header for all source files of the ... project
//
#import <Availability.h>
BOOL myBool; // intended to be globally accessible
NSString *myString; // intended to be globally accessible
#ifndef __IPHONE_3_0

Are you trying to define them as public members on a class? Classes in Objective-C are rather different than in other languages you might be familiar with. Outside of the curly braces you can only define methods. If you want to make a publicly-accessible member, define them as properties:
#interface myAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
myViewController *viewController;
BOOL _myBool;
NSString *_myString;
}
#property BOOL myBool; // intended to be globally accessible
#property NSString *myString; // intended to be globally accessible
#end
Then in your #implementation do something like:
#implementation myAppDelegate
#synthesize myBool = _myBool;
#synthesize myString = _myString;
Then you can access them as myObject.myBool and so on.
If you are just trying to make them into static ("global") data for all instances of the class, then as other posters have said, you want to move the definition into your .m file (and ideally declare them static so they won't cause link issues).

The compiler is complaining about the variables being in the #interface block, so move them out of it, either above the #interface or below #end. You'll actually probably want to change them to externs in the header and actually declare them in the .m file.

C Global variables should be declared in .m implementation files, not in .h header files. An extern declaration can go in the .h header files, usually after the includes and outside the interface declarations.
It's also good practice to initialize global object pointers to nil, or else they might contain a garbage object reference.

Related

Basis to declare variables in Objective C

If we are having:
First way is
MyClass.h
#interface MyClass : UIViewController{
IBOutlet UILabel* _label;
NSString *myString;
}
Second way is
MyClass.m
#interface MyClass() {
IBOutlet UILabel* _label;
NSString *myString;
}
#end
My question is what are the differences between the first way and the second way.
I do know that the second way is create private variables for MyClass. How is about the first way. Does it do the same or else.
Please advice me on this issue
The first way is the way you would declare it in the header file, MyClass.h. Whoever will use this class will always have your header file, so they'll see those instance variables.
The second way you would use it on your implementation file, MyClass.m. So if you would give me a framework with your class inside, with only the .h file, I would be able to use your MyClass class but I wouldn't know about your instance variables.
You can use #private keyword to make your variables from the first example private. That is not the main point of adding variables in a class extension. Rather, adding ivars in an extension lets you remove unwanted dependencies from the header without using forward declarations.
For example, if MySpecialClass is defined in MySpecialClass.h and you want to add MySpecialClass *special as a private variable, doing it in the header would require either a forward declaration #class MySpecialClass, or an inclusion of MySpecialClass.h header inside your own header. On the other hand, adding a variable to an extension (your second way) lets you include MySpecialClass.h in your implementation .m file, avoiding the clutter of forward declarations and unnecessary header dependencies.
Of the two, the second way is better. The first way requires you to put internal implementation details in the public interface of your class i.e. it breaks encapsulation by leaking those details to users of the class.
However, now there is a third even better way. You can put your instance variables in the implementation:
#implementation MyClass
{
#private
IBOutlet UILabel* _label;
NSString *myString;
}
// method implementations
#end

Do I still need to declare the instance variable if I am using #property?

In Objective C you can now use #property and #synthesize to auto generate get and set methods. My question is: Do I still need to declare the property in the interface? My program compiles and runs fine without it. But most books and other examples still have it. Why?
#interface Person : NSObject {
// do i need the declaration "NSString name;"? why?
// i have notice that my program works fine without it.
// but many programming examples still incude it.
// NSString name;
}
#property NSString *name;
#end
#implementation Person
#synthesize name;
#end
This depends on runtime. Modern runtime is used in iOS and you don't have to declade ivars. This is not always the case in OS X though. See here - http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html
What you're talking about is the ivar. You do not need to declare it as the #synthesize adds it for you. This did not use to be the case on older compilers (and obviously before #propertiy was added to the language), thus a lot of people and books still do.
PS: You also do not need the {...} if you don't have any ivars, e.g.:
#interface Person : NSObject
#property NSString *name;
//...
You do not need to; the ivar will be generated for you. But the debugger won't show you auto-generated ivars, so I like to declare them anyways.
You don't need to declare the ivar. The #synthesize directive does it for you if you omit the ivar.

Private properties and methods in Objective-C

In looking at one of Apple's examples, in the TableViewController.m, they have this:
// Private TableViewController properties and methods.
#interface TableViewController ()
#property (nonatomic, retain) NSMutableArray* sectionInfoArray;
#property (nonatomic, retain) NSIndexPath* pinchedIndexPath;
#property (nonatomic, assign) NSInteger openSectionIndex;
#property (nonatomic, assign) CGFloat initialPinchHeight;
... more properties and methods
#end
#implementation TableViewController
... usual stuff
I'm wondering why they put these properties in the .m file and how this is private. It seems like anyone who imports the TableViewController.m file can use these properties and methods right? Why not use the #private in the .h file?
What they're doing is declaring a category on the class, but since this is done in the .m file, the effect is that those methods are "invisible".
This doesn't mean however that those methods cannot be called from the outside. This is due to the fact that there is no real privacy in objective c, because we're dealing with messages, not method calls. This means you can send an object a message even if you do not know if that object actually implements the method you're trying to call. The receiving object will determine at runtime if it can handle this call, maybe it will even forward it, and it will make no difference whether the method was known to the calling object or not.
This is one of the reasons why it is possible to call private APIs and get rejected for it.
They're not private. They're anonymous properties, since they're part of an anonymous category.
One of the things properties are good for is putting the memory management semantics for an owned object in a single place. Consider this:
#property (nonatomic, assigned) NSString *assigned;
#property (nonatomic, copy) NSString *copied;
#property (nonatomic, retain) NSString *retained;
In all three cases, you can assign to them like this without knowing what their memory semantic is:
self.assigned = stringParameter; // assigns to instance variable
self.copied = stringParameter; // copies, assigns copy to instance variable
self.retained = stringParameter; // retains, assigns to instance variable
And in all three cases, you can free clean up using the same code:
self.assigned = nil; // this just nils the instance variable
self.copied = nil; // releases copy in ivar, nils instance variable
self.retained = nil; // releases ivar (same as original object),
// nils instance variable
This is why you'll often see local properties: It lets the coder skip writing all the memory management logic each time they want to assign to the instance variable. This is a major advantage in that you can change the memory management logic throughout the entire class just by changing the #property.
Another use of anonymous properties is to extend a property declared as readonly to outside code as read/write to the class itself.
In .h:
#property (nonatomic, readonly, retain) NSError *lastError;
In .m, in an anonymous category:
#property (nonatomic, readwrite, retain) NSError *lastError;
Elsewhere in .m code:
self.lastError = error;
Again, this is mostly done for memory management reasons.
An example, that pertains to either use of anonymous properties.
Here's what each assignment to a _lastError instance variable looks like without properties.
Assume we have a NSError called _lastError defined in the .h file.
With retain:
[_lastError release];
_lastError = [error retain];
With copy:
[_lastError release];
_lastError = [error copy];
With assign:
_lastError = error;
In the first two cases, you need this in your dealloc:
[_lastError release];
But in the last case, you must put nothing in the dealloc or you'll get a crash.
So let's add what we need to use a property instead:
Add this in an anonymous category:
#property (nonatomic, readwrite, retain) NSError *lastError;
Add this in the #implementation:
#synthesize lastError = _lastError;
Note, also, that at this point on the "modern" Cocoa runtime (64 bit Mac or iOS), you can remove the NSError *_lastError from your header. The compiler can figure out you want that based on the #synthesize.
Here's how that changes our code:
Each assignment:
self.lastError = error; // works regardless of storage specifier
In daelloc:
self.lastError = nil; // works regardless of storage specifier
AFAIK
a) You can not mark properties as #private in .h - this works only for ivars.
b) You will not be able to reference your class if you just import .m file (without interface definition in .h file). and if you do - you will get duplicate symbols during linking.
c) So yes these properties are private in the sense they are not accessible as regular properties from outside - these properties are accessible only using explicit messages - however you'll get warnings from compiler in this case or you could use KVC
First, you typically cannot import an .m file - not without numerous compiler/linker errors. Second, the properties are private so that Apple is free to change them in subsequent releases.
Yes, you can get to them via reflection. But that's a slippery slope, blah blah proceed at your own risk, will break in later versions blah blah reflection bad unless you know exactly what you're doing.
There are no private methods or variables in objective c, the #private flag is mainly there just so when other developers look at it, they know it's supposed to be private. What your seeing in the apple code is an example of a category, a way to fake private methods and variables in objective c. Because outside classes will import the .h file only, they will never see the added methods and variables in the .m file.
Using an anonymous category black boxes internal properties and methods that other classes should not know about. Although the compiler doesn't know about them when this class is referenced from other classes, you could technically access any of these properties from that other class using key value coding.
you can't import the implementation file TableViewController.m, Only the .h file of TableViewController could be imported,
Although, you could have the reference of these property outside your TableViewController class with a warning that shows the "not respond" note.

Instance Variable Syntax Question

When declaring an instance variable, does it make a difference if I declare it under #interface and as a #property? Example:
#interface MyViewController : UIViewController {
NSString *myString;
}
#property (nonatomic, retain) NSString *myString;
Would it matter if I took out the one under #interface? I have been doing that and would like to know if it does anything.
With a modern compiler (recent versions of LLVM), there is no need to declare the instance variables in conjunction with an #property (as tc says; it is the #synthesize that actually tells the compiler to reserve a slot, otherwise, you are on your own for storage) and doing so doesn't change anything.
One suggestion; when you #synthesize, do something like #synthesize myString = myString_; to cause the iVar to have a different name and, thus, make it impossible to accidentally directly access when you meant to go through the property.

How to declare and change global variable in Objective c

can anyone tell how to declare and change global variables in objective c
Just the same way that you would in C. Are you having any particular problem?
On a related note; global variables are (very) generally speaking considered a Bad Thing™. In Obj-C the more common approach is making them a property on a singleton object, ensuring at least some encapsulation is taking place.
In an AppKit/UIKit application; a global variable might more properly be a property on your application delegate; another, somewhat more involved, option is making a singleton class for encapsulating the variable and related methods.
Global Variable for Complete iPhone Project
For Declare/Define/Use a global variable follow these easy steps:-
Create a NSObject File with named "GlobalVars.h and .m" or as u wish
Declare your global variable in GlobalVars.h file after #import and before #implementation like-
extern NSString *Var_name;
initialize it in GlobalVars.m file after #import and before #implementation like-
NSString *Var_name = #"";
Define its property in AppDelegate.h File
#property (nonatomic, retain) NSString *Var_name;
synthesize it in AppDelegate.m File like-
#synthesize Var_name;
Now where you want to use this variable (in .m file) just import/inclue GlobalVars.h file in that all .h files, and you can access or can changes easily this variable.
Carefully follow these Steps and it'll work Surely.
Single source file:
int myGlobal;
Header file:
extern int myGlobal;
Any file including the header:
myGlobal = 10;