What's a 'null defined macro'? - objective-c

I'm learning objective-C and Cocoa. In the Apple tutorial I'm working through there's a side note that says:
IBOutlet is a null-defined macro, which the C preprocessor removes at compile time.
I'm curious - what's a null-defined macro?

#define IBOutlet
Whenever IBOutlet is used in program text, it will be replaced with nothing at all.

FYI, in this particular case, the reason the IBOutlet even exists is simply so that Interface Builder can parse the source file and glean bits of understanding from it. It's a clue (well, a bit stronger than a clue) that the variable preceded by IBOutlet should show up as an Outlet in Interface Builder when designing your UIs.

A null-defined macro is a macro which will be replaced by nothing (will be removed) by the preprocessor. It's role is to give a hint about something in code, such as:
#define IN
#define OUT
#define INOUT
int myFunction(IN char *name, INOUT char *address, OUT char *phone);
This declaration suggests that name is a input variable for the function, address is both input and output, phone is an output variable.

Also - if you're unsure how anything is defined - command double-click it and Xcode will open the definition in the original source file.

Oh and while I'm at it. Option double click will (attempt to) open up the documentation for the double clicked symbol.

Related

Weird syntax errors in header file

I have a header file containing an interface with properties and methods (let's call it E.h), and Xcode notifies me about syntax errors inside this header field, which make no sense because E.h doesn't contain any error.
These errors appear only under certain conditions:
E.h is already included in A.h, and there is no error.
When E.h is not included in B.m, there is no errors and it compiles fine, but if I include it in B.m, errors show up. (B.m doen't use any code from E.h)
Additional information: B.m includes B.h and then E.h .
I didn't find relevant to include source code because it represents thousands of lines and I won't ask you to analyze this.
I jus need some hints for what could be the cause and where to start searching.
Thanks in advance.
By using the "Show Preprocess" option in Xcode, I found that the property in E.h named #property (retain) NSString *MY_STRING; was replaced with #property (retain) NSString *#"My String". It appeared that there was a define MY_STRING #"My String" included in a different header file itself included in B.h, itself included in B.m before E.h .Hard to spot ! Lesson of the day : never write your variables in upper case.
In C++ this works, maybe will help you:
in file E.h
#ifndef __ECLASS__
#define __ECLASS__
<here original declarations from E.h>
#endif

Add constants issues Xcode 4.5

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.

Any way to replace part of word with the preprocessor?

I have something like this in my objective-C class
#interface PREFIX_MyClass {
...
#end
and I'd like to use the preprocessor to convert it to:
#interface AwesomeMyClass {
...
#end
so something like
#define PREFIX_ Awesome
doesn't work because it's a part of a word. Any other way? I know I can use something like this:
#define PrefixClass(NAME) Awesome##NAME
#interface PrefixClass(MyClass)
but I don't like this because it breaks code complete and reference following in dev tools (i.e.: Xcode in this case)
This isn't very elegant, but you could use the preprocessor to replace the entire class name instead of just part.
#define PREFIX_MyClass AwesomeMyClass
#interface PREFIX_MyClass
Of course, this becomes an issue if you use the prefix more than once and it changes. You could fix this using by using another calling another macro to add the prefix, so that only one macro contains the actual prefix.
#define ADD_PREFIX(name) Awesome##name
#define PREFIX_MyClass ADD_PREFIX(MyClass)
#interface PREFIX_MyClass
This still requires a macro for everything you want to prefix, but code completion will recognize the PREFIX_MyClass name.
This is not exactly what you're asking for, but it may be another route to accomplish your goal. Xcode allows you to define a class prefix for your project. Select your project in the file navigator, and in the file inspector (first "tab" of the right sidebar) you will have this:
Whatever text you put into the "Class Prefix" field will be prepended to the names of any classes you create in that project.

Difference between strings and char arrays in objective c in #import statements

I recently noticed this while working on an app- why is it that when you import a file you use
#import "SomeFile.h"
but when you are manipulating a string you use the # symbol before the string, such as
NSLog(#"Hello World");
I know these two are not interchangeable, so is there a specific reason the #import directive doesn't take a type of string? There must be some history/a good reason behind this. Maybe. Thanks for your time!
Its because #import is a preprocessor macro, that is compiled before the objc runtime is even a part of the picture. All import is is a wrapper around #include that makes sure you don't include the same file twice.
The #import statement is a preprocessor macro that is used when the compiler compiles your code. It makes sure that the file you are going to import is actually added to the source file you're compiling.
The compiler takes its own type of string to find the file. When not using the " you are actually talking about a C type string, or char[].
When using the #"" directive, you are actually talking about an object of type NSString, which is in the end also, a 0-terminated array of chars.
So basically, they're both strings. But the #"" directive is used in Objective C to denote a string object, and the standard " " notation is used for lower level languages' string types.

Global Variables in Cocoa/Objective-C?

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.