How to manage lots of flag variables in interfaces - objective-c

Sometimes my interfaces end up having a lot of flag variables, such as isThatFeatureEnabled. Or, even worse, I will have an interface containing only flags and instance information.
While reading some UIKit header files, I found out that some classes declare a structcontaining all the internal flags they need. For example UIView has this:
struct {
unsigned int userInteractionDisabled:1;
unsigned int implementsDrawRect:1;
unsigned int implementsDidScroll:1;
unsigned int implementsMouseTracking:1;
unsigned int hasBackgroundColor:1;
unsigned int isOpaque:1;
// ...
} _viewFlags;
How does this work and how is it used?
Also, (sorry if this may seem unrelated), take StoreKit's SKProduct, for example. It doesn't have any methods, just readonly properties for getting instance specific information, such as localizedDescription, localizedTitle and price. But how is it initialized? How does the code that initializes instances of this class set those properties in the first place if they're readonly? I see this class also has an id _internal ivar; what's that for?
Often I end up with interfaces similar to SKProduct, except that my properties can't be readonly, because I have no idea how to set them when I need to initialize an instance, for example in an XML parsing code.

The structure that you have presented is the way that C, C++ and Objective C have for declaring bitfields. It has an advantage over something like #define MYFLAG 0x0001 in that you get compiler checking, so that you don't do any of the following:
Accidentally assign the same bit to more than one flags
Accidentally overwrite a flag with a number (e.g. flag=34)
Accidentally use one #define with the wrong variable (e.g. myColor=FLAG_TEMPERATURE_HIGH).
You can set all of the variables at the same time doing a structure assignment in C++. You couldn't do that in C or Objective-C the last time I looked, but you may be able to do so now.
You set and get these flags like any other instance variable.

Related

Is there a way to declare an objective-C block typedef whose arguments contain that typedef?

Here's an interesting one for the objective-C gurus out there...
Is there a way to declare an objective-C block typedef that contains an argument of that typedef?
typedef BOOL (^SSCellAction) ( UITableViewController* inTVC, SSCellAction inChainedAction );
The idea is that I wanted to used chained menu action system that allows a chain of work/response to occur (usually 1-3 items). When the last action invokes, it passes nil for inChainedAction. Since this seems relatively trivial to imagine, I'll be dammed if I can't figure out how to declare it without llvm saying no. :)
rmaddy's comment is correct. Just as in C, a typedef cannot use itself. Basically, a typedef does not make a real type, but just makes an alias that the compiler expands out at compile-time. It is always possible to manually expand all typedefs in your program yourself (which is sometimes an instructive exercise), so that your program is written without typedefs. However, a recursive typedef cannot be expanded.
Some possible workarounds:
Use id as the parameter type, and cast back into the right type inside the block. This loses type safety.
Or, use a struct type of one member, the block. A struct is a real type, so it can be used within its definition. The downside of this is that you explicitly "wrap" the block into the struct type to pass it, and explicitly "unwrap" the struct into the block by accessing the field when you need to call it. This way is type-safe.

ObjC protocols potentially useless

In ObjC we can use protocols to restrict an id behavior, so we can declare something like
-(void)aMethod:(id<aProtocol>)aVar which works very well until we provide a value or a non-id variable as aVar, but this gets completely broken since we can pass a generic id variable delcared without protocols specifiers... Is this normal? Is there any workaround? Am I missing something?
Just use id less, and declare variables and parameters using the correct types, where possible. That is to say: don't pass ids around. If you are implementing a collections class (for example), then id's often useful.
My approach is to specify types, and introduce that type as local as possible in the source. So I omit id and add the type, and when (for instance) I take a reference from a collection, I create a variable:
MONType<MONProtocol>* thing = [array objectAtIndex:idx];
// now thing is correctly typed. use thing.
Similarly, if I have an id parameter, I declare a new variable:
- (IBAction)someAction:(id)sender
{
NSButton * button = sender;
// now use button, not sender
Protocols are extremely useful. Very often, better/cleaner than subclassing.
You're missing the understanding that types in Objective-C are determined at runtime, not compile time. Just because you say that an object will be of type id<aProtocol> does not mean that at runtime it is guaranteed to be so.
The idea of specifying something as id<aProtocol> is to aid you as a developer and people using your code. It aids you as a developer because the compiler will warn (or error under ARC) if you attempt to call a method on something that the compiler can determine it doesn't think exists on instances of its supposed type (excluding forwarding which could mean an instance responds to something the compiler cannot determine). It aids people using your code as it tells them the contract that they should adhere to when interfacing with your code.
So, in your question you say that:
but this gets completely broken if we pass a generic id variable delcared without protocols specifiers
Well, the compiler would warn and tell you that you're trying to pass something that does not conform to that protocol, except for the case of passing id. That's why you generally should try to type things more precisely than just id.
If you have a method defined like so:
- (void)aMethod:(id<aProtocol>)aVar
Then aVar could be of type SomeSubclass where that is defined like so:
#interface SomeSubclass : NSObject <aProtocol>
And you could then use aMethod like this:
SomeSubclass *obj = [SomeSubclass new];
[other aMethod:obj];
I (FINALLY) found out that using Objective-C++ is the way to go. Let's suppose I want to be able to pass NSString or NSNumber (instead of a too much generic id and instead of using protocols which become useless passing id values): well, I can create a C++ class having two distinct constructors, one for each ObjC class, so passing id values cannot be done anymore (almost directly). For example, let's take a look at
class NSStringOrNSNumber{
public:
NSStringOrNSNumber(NSString *);
NSStringOrNSNumber(NSNumber *);
};
The great advantage is that methods/functions taking a NSStringOrNSNumber parameter can get NSString/NSNumber values DIRECTLY, since the constructor acts as an implicit cast. In other words, if we have
void aFunction(NSStringOrNSNumber param);
the following calls are perfectly valid:
aFunction(#"Hello!");
aFunction(#25);
The only (little) downside is that we need the class to implement a function if we want to get back the value passed to the constructor.
Using a C++ class constructor to get something like id<NSCoding> is still better the using id<NSCoding> directly: in fact, if we do the following
#class classOne, classTwo;
class NSCodingClass{
private:
NSCodingClass(classOne *);
NSCodingClass(classTwo *);
public:
NSCodingClass(id<NSCoding>);
}
we won't be able to pass a generic id as a parameter (since it would be ambiguous: the compiler cannot know which constructor to call among the two private ones)

objective-c - global variables

How do I declare a variable in the main.m file so that it is available in all the classes?
If I simply declare it in the main function, the compiler says it's undeclared in the class method.
Must I declare it in an object like this?
#public
type variable;
All you need is to use plain old C global variables.
First, define a variable in your main.m, before your main function:
#import <...>
// Your global variable definition.
type variable;
int main() {
...
Second, you need to let other source files know about it. You need to declare it in some .h file and import that file in all .m files you need your variable in:
// .h file
// Declaration of your variable.
extern type variable;
Note that you cannot assign a value to variable in declaration block, otherwise it becomes a definition of that variable, and you end with linker error complaining on multiple definitions of the same name.
To make things clear: each variable can be declared multiple times (Declaration says that this variable exists somewhere), but defined only once (definition actually creates memory for that variable).
But beware, global variables are a bad coding practice, because their value may be unexpectedly changed in any of files, so you may encounter hard to debug errors. You can avoid global variables using Singleton pattern, for example.
Not really sure why you want to do it, but you could if you wanted.
main.m:
int someGlobal = 0; ///< Added outside any function, at the top say.
SomeClass.m:
extern int someGlobal; ///< Added at the top, outside the class implementation.
...
- (void)useGlobal {
NSLog(#"someGlobal = %i", someGlobal);
someGlobal = 5;
NSLog(#"someGlobal = %i", someGlobal);
}
But please, think carefully before embarking on using something like this!
Besides debugging, I see no reason to even try and modify the main.m file to directly interact with your application logic.
You can try to define a constant on Your_project_name_Prefix.pch file, if that suits your needs. Or declare a static variable on your application delegate, or any of the classes of your app.
To learn more about constants and static variables, follow this link:
http://iosdevelopertips.com/objective-c/java-developers-guide-to-static-variables-in-objective-c.html

How to use global variables in Objective-C?

How should I declare a global variable in my Objective-C project?
Traditionally, global variables are declared in a header, and defined in a source file. Other source files only need to know how it is declared to use it (i.e. its type and its name). As long as the variable is defined somewhere in a source file, the linker will be able to find it and appropriately link all the references in other source files to the definition.
Somewhere in your header, you would declare a global variable like this:
extern int GlobalInt;
The extern part tells the compiler that this is just a declaration that an object of type int identified by GlobalInt exists. It may be defined later or it may not (it is not the compiler's responsibility to ensure it exists, that is the linker's job). It is similar to a function prototype in this regard.
In one of your source files, you define the GlobalInt integer:
int GlobalInt = 4;
Now, each file that includes the header will have access to GlobalInt, because the header says it exists, so the compiler is happy, and the linker will see it in one of your source files, so it too will be happy. Just don't define it twice!
However
You should consider whether or not this approach is useful. Global variables get messy for a number of reasons (trying to find out exactly where it is defined or declared, threading issues), there is usually not a need for global variables. You should perhaps consider using a singleton approach.
Don't. Global variables are often a sign of poor design. A common replacement in Objective-C is a class method that returns an object (that may or may not be a singleton), such as [NSUserDefaults standardUserDefaults] or [UIDevice currentDevice].
However, if you must use a global variable, read on.
In your header:
extern NSString *someString;
extern NSInteger someInteger;
In your implementation file:
NSString *someString = #"DEFAULT_VALUE";
NSInteger someInteger = DEFAULT_VALUE;
In my experience there are few instances when a program doesn't need, at least, some sort of data or utility/helper methods that can be accessed throughout the program.
They way I deal with this, rather than using global variables is to create what I call a 'project applicance', which is essentially just a class with a bunch of static methods.
It could be implemented multiple ways, but I use a singleton and just have the static methods call through to the single instance of the appliance class. For example, in my project Oovium I have:
Oovium.h:
#interface Oovium : NSObject {
UIWindow* _window;
}
+ (UIWindow*) window;
Oovium.m:
#implementation Oovium
static Oovium* oovium;
- (UIWindow*) window {return _window;}
+ (void) initialize {
oovium = [[Oovium alloc] init];
}
+ (UIWindow*) window {return [oovium window];}
I then include Oovium.h in my Oovium_Prefix.pch file so that it is automatically included in all of my files.
Globals rock! I don't know what everyone is scared of. I used them successfully here.
Passing Data between View Controllers
Also used UIStepper to adjust values in another viewController.
I could see them being an issue is larger programs, and in my opinion the singleton thing is just a masked global. Keep it simple, if your app is simple that is.

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.