I am used to Objective C header files and am not sure how C header files are used in terms of good practice.
Where would one #include other source files, in the header file or the .c file?
Does the same idea apply to C where .c files include their own header files. and other files include the .h files of the source they want to include?
Is there anything equivalent to the #class usage in Objective-C?
Is it good practice to declare pointers in the .h file and initialize them/alloc them in the .c file?
You normally distinguish between source and header files in the same way that Objective-C differentiates between implementation (.m) and interface (.h) files. Source files contain everything that may execute, header files contain enough information about symbols that other source files know how to communicate with that source file.
Header files often include other header files, so you'll see #include in both source and implementation files. #include operates exactly like #import except that it doesn't automatically check whether you've #included the same file twice. So C header files often look something like:
#ifndef __SOME_SYMBOL
#define __SOME_SYMBOL
... rest of header file here ...
#endif
Which has the same effect of ensuring the main body of the header file is included only once.
EDIT: more on this, as per request. Obviously you'd never do something like:
#include "File.h"
#include "File.h"
But you can easily end up with something like:
#include "FirstComplexThing.h"
#include "SecondComplexThing.h"
Where both FirstComplexThing.h and SecondComplexThing.h rely on something inside and hence #include SimpleThing.h. So you end up with SimpleThing.h #included twice, without making any sort of error or following any bad design pattern.
C compilers work just like Objective-C compilers — each source file is compiled on its own, in isolation, with no overview until the linker comes along. #include is a preprocessor directive that has the same logical effect as copying the contents of the named file and pasting them into your source file at that location, so if you end up the same file #included twice you'll probably end up with something like:
char *somePointer; // I'm from SimpleThing.h
... lots of other things ...
char *somePointer; // I'm from SimpleThing.h
And the compiler will stop with an error that the same thing is declared twice. #import in Objective-C avoids that by being shorthand for '#include, but only if you haven't already #included that file'. The C #ifndef/#define/#endif convention achieves the same thing as #import because the #ifndef/#endif pair say that the stuff in between should be passed on to the compiler if the nominated preprocessor symbol (__SOME_SYMBOL in my example; it tends to be a name derived from the name of that header file but exact conventions vary) hasn't been defined. It won't have been the first time the construct is encountered. Because it is defined inside the construct, it will have been when the same #ifndef is encountered the second time, so the stuff up to the matching #endif won't be passed on.
Although it's a question of style, it is very often the case that each C file has one H file that is directly connected to it.
There are no classes in C, obviously, but if you mean a construct like:
#class SomeClass;
#interface SomeOtherClass: NSObject
{
SomeClass *otherClass; // I can reference SomeClass without importing
// the interface file because I've declared the
// type above
}
- (void)whatever;
#end
That's actually the normal C distinction between declarations and definitions. You'll have a problem if you do something like:
struct SomeStruct;
struct SomeOtherStruct
{
struct SomeStruct otherStruct;
};
Because the compiler doesn't have enough information. It doesn't know how large SomeStruct should be, so it can't work out how SomeOtherStruct should be laid out. However, this is completely valid:
struct SomeStruct;
struct SomeOtherStruct
{
struct SomeStruct *otherStruct;
};
Because the size of a pointer is always known, irrespective of what it is pointing to. You'll often see that C libraries with opaque types describe those types by pointer only (sometimes to void *, but not always — e.g. stdio.h uses FILE *) or just give you an integer (including OpenGL, notably). So they ensure you've something that the compiler will know the size of without having to tell you what data they're associating with it or giving you any way to try to manipulate it yourself.
It's perfectly good practice to put pointers in the header file (assuming it's good practice to expose the thing globally, obviously). The same thing is often done in Objective-C, albeit for slightly different reasons, e.g.
// interface/header file
extern NSString *someGlobalIdentifier;
And:
// implementation/source file
NSString *someGlobalIdentifier = #"somethingOrOther";
In Objective-C that's because you can then test identity rather than always having to test equality, but basically the same rules apply to C with respect to it being normal to put the reference (be it a pointer or whatever) that represents a thing into the header and create or declare the thing in a source file. In fact, if you start putting declarations in the header file you'll end up with errors when the program comes to link because multiple source files will think they declare the thing.
->#include is working in c and objective c.
->But generally in objective c, always used #import.
->#include and #import are different, when you used #include compiler generate one separate copy of .h file, and if you used #import then compiler generate only one copy at a time
Is there anything equivalent to the #class usage in Objective-C?
-> No there is no any other equivalent
Is it good practice to declare pointers in the .h file and initialize them/alloc them in the .c file?
-> Yes if your object is public, then you must declare in .h file, but always is good practice that initialize them it in constructor.
This is how I finally figured out how to do this properly. After long time of trying and failing at what used to be a simple thing.
//this is the mechanics.h file
#ifndef ProjectA_mechanics_h
#define ProjectA_mechanics_h
#ifdef __cplusplus
extern "C" {
#endif
int funcAdd (int A, int B);
#ifdef __cplusplus
}
#endif
#endif
// this is the mechanics.c file
#include "mechanics.h"
#include <math.h>
int funcAdd (int A, int B)
{
return A + B;
}
math.h is there "just because"
have fun, dang this sucked for while
Related
This question already has answers here:
What does the extern keyword mean?
(3 answers)
Closed 8 years ago.
what does this code mean?
// myheader.h
extern const NSUInteger Something;
#interface MyObject : NSObject
...
#end
What does extern mean here, and how can/will it be used? is it part of the object? is it global in the project? Does it matter where (in which header) is it defined? Is that a good practice?
This is plain C.
What does extern mean here, and how can/will it be used?
extern const NSUInteger Something;
It means:
There is a var with the name Something.
It has the type NSUInteger.
It cannot be changed (const)
Do not create that var, but link to a creation somewhere else in a file contained in the executable (extern).
Let's have an example:
Exporter.h
extern const NSUInteger Something;
Exporter.m (Or Exporter.c, since it is plain C.)
#import "Exporter.h"
const NSUInteger Something = 5; // This is the definition for the declaration above.
After defining that var in Exporter.m and extern declaring it in Exporter.h everyone that imports the Header can use it:
Importer.h or Importer.m (Or Importer.c, since it is plain C.)
#import "Exporter.h" (Or #include, since it is plain C.)
// Now the compiler knows that
// there is a global readonly var called Something,
// its type is int, and
// it is readonly.
Every importer will share one var. Without the extern keyword, there would be different vars.
Is it part of the object?
No. To be precise: An ivar is declared, if it is inside { … }that belongs to an #interface … or to an #implementation …. Whether this is done in a header or in an .m file is without any meaning.
Is it global in the project
It is global in your executable. (You call that "project" what is not precise, but okay.)
Does it matter where (in which header) is it defined?
No. That never matters in C. (The compiler sees the text after resolving imports and includes. It has no idea from where it came.) But in one translation unit (".m") you have to have a definition as shown above in Exporter.m.
Is that a good practice?
The problem with extern var declaration is that everyone importing Exporter.h can read and – that's important – change that var without any notification to other parts of your software dealing with Exporter.h (and Something). So it is nearly impossible to control the data flow.
In nowadays extern global vars are only used for const vars, as in your Q. That vars cannot be changed. So there is no problem and it is commonly accepted practice.
As the title says - in Java I would just make a class define the constants then import them into the classes that will be using them. Is it done the same way in Objective-C?
To make it clear, I want to
#define variable 1
#define variable 2.0
And use the same constants in different classes.
Put the macros in a header file, and #include or #import that header file whenever you need to access them.
There is another alternative to using macros. You can define them as global variables.
In Constants.h:
extern int variableX;
extern float variableY;
In Constants.m (typically after the imports, before any other code):
int variableX = 1;
float variableY = 2.0f;
There are a few advantages to this approach over macros:
Clients don't need to see the value.
If the value(s) change, there is no need to recompile every file that imports Constants.h.
The values can be initialized many different ways, not just with literals.
Type safety and compiler checking when you use the variables.
Your example is using C preprocessor macros. This works the same with Objective-C as in any other environment supporting C-style preprocessor macros: Stick them into a shared header and #import or #include it.
While that's perfectly ok, you were asking about class-related constants and Objective-C in particular. In Objective-C you'll often see constant NSStrings (e.g. for notification names or dictionary keys) and similar constants belonging to a specific class defined like this:
In the header (.h):
extern NSString * const LibraryEntryDidUpdateNotification;
extern const NSUInteger LibraryEntryDefaultStarRating;
#interface LibraryEntry : NSObject
...
In the implementation (.m):
NSString * const LibraryEntryDidUpdateNotification = #"LibraryEntryDidUpdateNotification";
const NSUInteger LibraryEntryDefaultStarRating = 3;
#implementation LibraryEntry
...
This is how Apple does it in their modern frameworks, and how it is done by many 3rd party developers. In my opinion it's easier to refactor than preprocessor macros (e.g. when renaming a class using the "refactor" button in Xcode, the same easily works with these constants), but preprocessor macros for constants do have their benefits as well.
See here and here for a more in-depth discussion of the topic in case you're interested.
I've got a class for storing constants.
So, there are two files that call Constant.h and Constant.m
This is what I have in .h file:
#import <Foundation/Foundation.h>
enum kParams {
kFirstName = 0,
kLastName = 1
};
extern NSString * const kNotificationUpdateMainMenu;
This is what I have in .m file:
#import "Constants.h"
NSString * const kNotificationUpdateMainMenu = #"kNotificationUpdateMainMenu";
For first time it works good, but when I try to add some other const (kNotificationFbLoginSuccsess for example) other classes don't see it.
This is a message that shows me which problem I have. But I don't understand how my other constants work without this issue (just new constant that I add get this error).
/Users/developer/Documents/Projects/Test/Test/Test/AppDelegate.m:121:64: Use of undeclared identifier 'kNotificationFbLoginSuccsess'
I found some way how to fix it:
Open organizer
Clear derived data
Delete project.xcworkspace file and xcuserdata
Close Project
Relaunch Xcode
but as I think is too much operations that I can add one constant. How come?
Your "global" constant is not actually external (separately compiled and later linked together). Take the easy way out and place NSString * const kNotificationUpdateMainMenu = #"kNotificationUpdateMainMenu"; into the header file. The method file needs nothing.
I would use #define kNotificationUpdateMainMenu #"kNotificationUpdateMainMenu" to perform the spell checking. The compiler will create one shared instance of the constant string for the entire compilation.
I don't know why, but after a while working without problems I added some buttons, then I launched my app and this error appeared:
ld: duplicate symbol _x in
/Users/alexbarco/Library/Developer/Xcode/DerivedData/RecolectaDatos-ayjpqqcajbhuzvbkvernzsyunpbe/Build/Intermediates/RecolectaDatos.build/Debug-iphonesimulator/RecolectaDatos.build/Objects-normal/i386/SeconViewController.o
and
/Users/alexbarco/Library/Developer/Xcode/DerivedData/RecolectaDatos-ayjpqqcajbhuzvbkvernzsyunpbe/Build/Intermediates/RecolectaDatos.build/Debug-iphonesimulator/RecolectaDatos.build/Objects-normal/i386/ViewController.o
for architecture i386 clang: error: linker command failed with exit
code 1 (use -v to see invocation)
Whenever I have duplicate symbol errors, it is almost always because I have a circular #import in my headers. The solution is quite simple, use forward declarations where possible, and #import .h files from .m files instead.
There are just two cases where you need to #import one .h from another:
if you are extending the class in the #import
you are implementing a protocol in the #import
Specifically, you do not need to import files just to use a class name or protocol in your signatures; instead use forward declarations.
For example, this (in Bar.h):
#import "Foo.h"
might become this (Bar.h):
#class Foo;
#protocol FooDelegate;
and bar.m:
#import "Foo.h"
Here is a link to the documentation on forward declarations.
The "duplicate symbol" message means that you're declaring some name (in this case, _x) twice in the same scope. Say you had code like this:
int _x = 1;
int _x = 2;
You'd expect to get an error then, right? You can use the same name for two things at the same time.
The error you're getting is essentially the same. You're declaring _x somewhere, and from the compiler's point of view you're doing it twice. There are a few ways to deal with this, depending on what _x represents.
chrahey's answer explains about forward class declarations. I won't cover that again here except to say that a forward declaration helps you resolve circular references, where the definition of class A depends on class B and vice versa.
If _x is a variable, it's likely that you're trying to declare it in a header file. The compiler basically copies the contents of each header file that you import into the source file, so if you declare a variable in a header file and then import that header into two or more implementation files, you'll end up with multiple declarations of that variable. To get around that, use the extern keyword to tell the compiler "this name will be declared somewhere else" and then put the real declaration in an implementation file:
Foo.h:
extern int _x;
Foo.m
int _x;
Pretty much the same thing goes for functions. It doesn't appear that _x is a function, but if it were, and if you were silly enough to put the function definition in a header file, then you'd again get an error if that file were imported into more than one implementation file. This is why header files contain prototypes, not definitions:
Foo.h:
int foo(int a);
Foo.m
int foo(int a)
{
return a + 10;
}
According to Cocoa Programming for Mac OS X, 3rd Edition, on page 202 (chapter 13):
You will be registering, reading, and
setting defaults in several classes in
your application. To make sure that
you always use the same name, you
should declare those strings in a
single file and then simply #import
that file into any file in which you
use the names. There are several ways
to do this. For example, you could use
the C preprocessor’s #define command,
but most Cocoa programmers use global
variables for this purpose.
Is this really the correct best practice? Global variables? That seems insane to me – counter to everything I’ve ever been taught.
Would a better design be a simple Singleton class with these defined? Or is it really the correct best practice to go global? Is there a better pattern than either, given that many people consider Singletons to be globals in a pretty dress?
Just to be clear, the recommendation is to create immutable global variables instead of in-line string constants (hard to refactor and no compile-time checking) or #defines (no compile-time checking). Here's how you might do so...
in MyConstants.h:
extern NSString * const MyStringConstant;
in MyConstants.m:
NSString * const MyStringConstant = #"MyString";
then in any other .m file:
#import "MyConstants.h"
...
[someObject someMethodTakingAString:MyStringConstant];
...
This way, you gain compile-time checking that you haven't mis-spelled a string constant, you can check for pointer equality rather than string equality[1] in comparing your constants, and debugging is easier, since the constants have a run-time string value.
[1] In this use, you are essentially using the pointer values as the constants. It just so happens that those particular integers also point to strings that can be used in the debugger
Global variables or a singleton will accomplish the same thing here. Both can be used to turn 'key' names in Cocoa that won't throw a compiler error if it's misspelled into a compiler error. That's the main purpose. Global variables are a bit easier though seeing as it requires less typing.
Instead of doing this:
[myArray setObject:theObject forKey:MyGlobalVariableKeyName];
You'd have to do something along the lines of:
[myArray setObject:theObject
forKey:[[MySingletonVariableClass getInstance] myVariableKeyName];
Global variables are essentially less typing for the same effect.
Calling it a global variable is technically correct but misleading.
It is a global constant -- global in scope but constant and therefore not bad in the sense that global variables are bad.
To show how global constants are common, safe and numerous, consider these examples of global constants:
Every class in your program
Every #define
Every enum
Almost every name declared by Cocoa (excluding rare global variables like NSApp).
The only time you should worry about global constants is when their names are too generic (they may pollute the global namespace). So don't use names that are likely to conflict with anything (always use a prefix and always make the name task-specific like NSKeyValueObservingOptionNew).
Constant globals that are set at compile time and never change are acceptable to me. If you hard code a string, it's the same thing, just hidden by the compiler. I'll avoid mutable globals like the plague.
Remember, Apple itself uses the same technique. Many of the constants I expected to be defines are actually constants. You'll get link errors if the headers are reachable but the framework is not.
building on #Barry Wark's and #Matt Gallagher's excellent answers, and my initial response (see end of this answer) there is a third approach, and that is to use a macro/include combination that ensures you only type the variable name once, and therefore it is included in both the .h and .m files simultaneously.
< EDIT >
"there is always another way..."
After thinking about how to make it even simpler, without involving an additional header file, here is a more concise approach using nested macros.
in .h file
#define defineKeysIn_h_File(key) extern NSString * const key;
#define defineKeysIn_m_File(key) NSString * const key = ##key;
#define myKeyDefineKeys(defineKey) \
/**start of key list*/\
defineKey(myKeyABC);\
defineKey(myKeyXYZ);\
defineKey(myKey123);\
/*end of key list*/
myKeyDefineKeys(defineKeysIn_h_File);
in .m file
myKeyDefineKeys(defineKeysIn_m_File);
implementation note
You can use this more than once in multiple headers, however you need to change the
name of "myKeyDefineKeys" to be unique, I suggest giving it the same prefix as the keys you are defining - for the sake of an example I have used "myKey" throughout.
In another file I might use "myOtherKeyDefineKeys".
Also don't mess with the defineKeysIn_h_File and defineKeysIn_m_File macros or you will get a warning the definition has changed.
< END EDIT >
ORIGINAL ANSWER, STILL VALID, BUT WITHOUT REFINEMENTS
First, make a vanilla.h file and remove the default #ifdef etc,and enter your keys as below:
(This is a cut and paste from a category I wrote to extend AVAudioPlayer)
// playFromConsts.h
define_key(AVAudioPlayer_key_player);
define_key(AVAudioPlayer_key_duration);
define_key(AVAudioPlayer_key_filename);
define_key(AVAudioPlayer_key_filepath);
define_key(AVAudioPlayer_key_fileurl);
define_key(AVAudioPlayer_key_urlString);
define_key(AVAudioPlayer_key_envelope);
define_key(AVAudioPlayer_key_startDate);
define_key(AVAudioPlayer_key_linkToPlayer);
define_key(AVAudioPlayer_key_linkFromPlayer);
define_key(AVAudioPlayer_key_linkToPlayerEnvelope);
define_key(AVAudioPlayer_key_linkFromPlayerEnvelope);
define_key(AVAudioPlayer_key_deviceStartTime);
define_key(AVAudioPlayer_key_currentVolume);
define_key(AVAudioPlayer_key_fadeFromVolume);
define_key(AVAudioPlayer_key_fadeToVolume);
define_key(AVAudioPlayer_key_fadeTime);
define_key(AVAudioPlayer_key_segueTime);
Then in your normal.h file (where your #interface, #protocol etc is declared) place these 3 lines (substituting your header file of course)
#define define_key(x) extern NSString * const x;
#include "playFromConsts.h"
#undef define_key
finally in your .m file, that is paired with your "#interface .h" file, place these 3 lines:
#define define_key(x) NSString * const x = ##x;
#include "playFromConsts.h"
#undef define_key
note the "#include" and not "#import" - we actually do want to include this file more than once.
this will do all the dirty work, and ensure the keys are NSString * const.
the trailing ; is optional, as it's included in the macro, however i personally prefer it.
So after all. I came up with 3 files.
Constants.h
#define def_key(name) extern NSString *const name
#define def_int(name, value) extern int const name
#define def_type(type, name, value) extern type const name
#include "ConstantsDefs.h"
Constants.m
#import "Constants.h"
#undef def_key
#define def_key(name) NSString *const name = ##name
#undef def_int
#define def_int(name, value) int const name = value
#undef def_type
#define def_type(type, name, value) type const name = value
#include "ConstantsDefs.h"
ConstantsDefs.h
def_key(kStringConstant);
def_int(kIntConstant, 313373);
def_type(float, kFloatConstant, 313373.0f);
It depends on the design of your software. Suppose you have a job management software and one of your "defaults" is a list of directories in which various items can be saved.
For each Job you can have a storagefile member that is a singleton that load up the user preferred locations at startup.
Or you could have a Storagefile member of a global variable called User Preferences. Still could be a singleton but doesn't really matter in this case.
For me complex defaults (dozens of different types of classes) should reside in their own "space" accessible to model.
However there may be preferences that are important to how a Job is setup so those preference need to be stored in the Job Object so when you open it in another user's application it works as intended.
Again it depends on your design.