Global variables in IPHONE APP - objective-c

How to declare and use global variable with extern in Objective C and other files.
I want to define and assign the global variable in 1.h file and 1.m and want to use that in 2.m file
I am defining
1.h
extern const NSString *str;
1.m
NSString *str=#"HELLO";
in 2.m I am importing the 1.h
want to access str but giving me 2.o error.

If these are application settings you should consider using NSUserDefaults. If it's constants, you should define them in prefix header file.

Global variables is a good sign of a bad design. I am guessing, based on your previous comment, that what you want to do is sending a string from one view controller, to another. There are two proper ways to do this:
Let the sending class also define a protocol for receiving the result string. This is how for example a UIImagePickerController and all other Cocoa controllers for user input does it. An example:
#protocol MyTextInputDelegate;
#interface MyTextInput : UIViewController {
id<MyTextInputDelegate> textInputDelegate;
}
#property(nonatomic,assign) id<MyTextInputDelegate> textInputDelegate;
// More interfaces here...
#end
#protocol MyTextInputDelegate
-(void)textInput:(MyTextInput*)textInput didInputText:(NSString*)text;
#end
Then let the class that needs the result conform to the MyTextInputDelegate protocol, and set it as the delegate. This way you avoid global variables, and there is no question of who owns the text object.
The other method would be to send the result as a NSNotification. This is slightly harder setup, and should only be used if you want a loose connection between the sender and the receiver.

You say:
m defining 1.h extern const NSString
*str; 1.m NSString *str=#"HELLO"
This isn't a way to pass global strings around, its a way of using a constant NSString instead of having to type in the static string each time.
And anyway, writing
extern const NSString *str;
the const is pointless because NSString is immutable. You should really be declaring these as
extern NSString * const str;
In this case, the actual pointer is a constant, which is probably the desired behaviour.
Anyay; I agree with PeyloW, passing values around in a global should be rethought. I'm not saying it shouldn't be done, just that you shouldn't reach for that as the first method of passing state around.

If you have central values you want to store and modify from a number of classes, think about putting them into either a singleton object, or the application delegate (really also a singleton). Then they are "global" but you have a better idea of what is accessing what.

Related

Objective-C propreties and private variable

I'm a debutant to objective-c and I don't understand something.
I practiced c++ so some practices are not instinctif ..
1)
#implementation Car {
// Private instance variables
double _odometer;
}
Why a private attribute is in the .m file ?
2)
#interface Car : NSObject {
// Protected instance variables (not recommended)
}
#property (copy) NSString *model;
-(void)drive
a)It seems model is declared like an attribute, but why it's not recommended to do it in the #interface ?
b) why the drive method is not in the interface ?
3)
What if i'm not use function allocation for exemple for a NString and initialise it directly with #"..." ?
4)
I don't understand the difference between + and - before method declaration too..
Thanks in advance
1.>Why a private attribute is in the .m file
Why not? Everything that is declared inside *.m is private because *.m file could not be imported (included) somewhere. In objective C you can declare instance variables in both files - *.h and *.m
2.a Recommended way is to use accessors (#properties in Objective C). For each property setter, getter and instance variable are generated. Default names for
#property (copy)NSString *str;
are:
- (void)setStr:(NSString*)obj; // setter
- (NSString*)str; //getter
NSString *_str; //instance variable
You can modify accessors names
#property (copy, setter = NewSetterName, getter = NewGetterName )NSString *str;
and instance variable name (should be done #implementation section)
#synthesize str = _newStingInstanceVariable;
Ofcource you can rewrite setters and getters that are generated by default.
2.b Interface is everything between #implementation and #end. {} area after #interface - is a place were you can declare instance variables.
3.It is ok for NSStrings
NSString *str = #"some text";
but for most classes it will not work as you expect:
NSMutableString *str = #"some text";
// You will receive warning here! And str will be NSString, not NSMutableString
4."+" - class methods (static in C++), "-" - instance methods.
There's a general principle in programming that you should make the smallest possible amount of information available to the outside. Anything that's in the .h file, anyone in the world can see, access, and mess up. If there's something wrong with an _odometer and it is in the header file, you have to go through all of your source code to find if something is using it wrong. If it's only in the .m file, you know that if there's a problem, it is in the .m file.
The other reason to not make things public is that you are free to change them if nobody knows about them. For some reason, you decide next month that having _odometer wasn't a good idea in the first place. By now three programmers have changed a dozen files to use _odometer because it was there. So removing that _odometer is now a lot, lot of work. If it was never in the .h file, nobody is using it so you only need to change your own .m file.

The difference between the ways of declaring a variable

I'm new to Objective-C, and I can not understand what is the difference between the declaration of variables (firstString, secondString and thirdString) in MyClass.h:
#interface MyClass {
NSString *firstString;
}
#end
in MyClass.m:
#interface MyClass() {
NSString *secondString;
}
#end
#implementation MyClass
NSString *thirdString;
#end
I guess that the first and the second case is the same thing, but in what case it is better to use?
Thanks a lot!
firstString is declared in the header, the file which is #imported by other classes. It is exposed to other classes and can therefore be accessed by subclasses and, since the symbol is available in the header file, it will be simpler for external objects to alter through key-value coding.
secondString is declared in your implementation file. The () in #interface MyClass () signifies that this is a class extension. secondString will not be exposed to external classes (though, as with everything in Objective-C, you cannot consider it to be truly private).
The first and second variables will be instance variables, whereas the third one will be a file-scope global variable. Typically you should use instance variables and avoid using global variables.
There is no functional difference between the three, it's mainly visibility control.
The first one is declared in a public header of you class, that means that you want the programmers the know about the variable. If the access to this property is restricted (e.g. #private), it should not appear in public header anymore and you should use the second or forth option.
The second is declared in the class continuation, meaning that it is needed only by the implementation.
The third one is a global variable, something you should use only in exceptional cases.
Missing another option
#implementation MyClass {
NSString *thirdString;
}
#end
(allowed by the latest Apple compilers) is the same as 2, without the need to create the class continuation.

On lazy instantiation and convenience methods

Assume you have a Singleton Constants class, instance of which you'd like to use throughout your application.
In someClass, therefore we can reference [Constants instance] someCleverConstant];
Typing this gets old really quick and it would be nice to get a shortcut to the instance.
In someClass, we can declare #property (nonatomic, weak, readonly) Constants *constants;
And a getter to the instance
-(Constants*) constants {
if (constants == nil)
constants = [Constants instance];
return constants;
}
This way in someClass, therefore we can reference constants.someCleverConstant; instead
A few questions on this:
Is what i described a reasonable approach?
Is it correct to declare a property weak?
Is there any performance concerns with what i have described? Would it actually be better to call instance directly?
Consider a situation where you have 20 classes, each needing it's own pointer to Constants instance. Would this approach work then?
Thank you for your time.
Following #vinceburn I would use the following example for constants and a singleton for more complex structures.
// Constants.h
// Replace PSMyApp for something more useful. e.g. company/name initials followed by app/class
// String example
NSString * const PSMyAppString = #"constantString";
// Logically related integers
typedef enum {
PSMyAppRelatedValuesOne = 0,
PSMyAppRelatedValuesTwo,
PSMyAppRelatedValuesThree
} PSMyAppRelatedValues;
// Float example
const CGFloat PSMyAppFloat = 0.3f;
// Integer that has no related values
const NSInteger PSMyAppInteger = 2;
I prefer this over #define as I get auto completion and compiler checking and it fits more naturally with the way Apple does thing in some of the UIKit classes.
This seems like a lot of work to get around just using a global variable or function. I think either of those is a more reasonable approach.
You could just create a global pointer to your singleton, like NSApp for [NSApplication sharedApplication].
Presumably you've already got something like
static Constants * defaultInstance = nil;
at the top of your implementation file. If you remove the static, and declare the variable in your header (keeping the definition in the .m file):
#interface Constants : NSObject
// etc.
#end
extern Constants * defaultInstance;
You can then access the singleton instance via the name defaultInstance (probably want to change that name, though) in any file that imports the header (which you must be doing anyways). You'll have to call your singleton setup method (+instance or whatever) somewhere very early in your program, such as -applicationDidFinishLaunching to be sure that the pointer is set before you use it.
Is what I described a reasonable approach?
I think there are other, better approaches, described above and in Paul.s's answer.
Is it correct to declare a property weak?
Yes, the class that has this pointer doesn't need to own it, because the singleton owns itself;
Is there any performance concerns with what i have described? Would it actually be better to call instance directly?
Either way, [Constants instance] or self.constants you're doing a message send. The first time you do self.constants, you're doing two. None of this should be a real concern, though.
Consider a situation where you have 20 classes, each needing it's own pointer to Constants instance. Would this approach work then?
To me, it seems unwieldy and inelegant.
For constant I prefer to use a .h file like this
// ConstanteDef.h
#pragma mark Entity Name Constante
#define kItemInfos #"ItemInfos"
#define kCategorie_DItems #"Categorie_DItems"
#define kCommerce #"Commerce"
#define kListe #"Liste"
#define kListeItem #"ListeItem"
#define kPrixElement #"PrixElement"
#define kTypeDe_CommerceOuListe #"TypeDe_CommerceOuListe"
While I would use the Singleton to return me more complex element.
Here is a singleton that I've made to simplify my live with core data, instead of rewriting the same code everywhere.
#interface CoreDataController : NSObject {
NSManagedObjectContext *leManagedObjectContext;
NSManagedObjectModel *leManagedObjectModel;
#private
Commerce_MO *leCommerceAucun;
}
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#pragma mark Objet par Défaut
#property (nonatomic, retain, readonly) Commerce_MO *commerceAucun;
#pragma mark Nouvel Objet
// new = retain count = 1, celui qui commande est responsable de la mémoire.
- (id)newMOforClass:(Class)uneClasse; // Pas le mieux, mais pourrais servir pendant le run time. Retourne nil si uneClasse ne correspond pas à quelque chose.
- (PrixElement_MO *)newPrixElement;
- (ItemInfos_MO *)newItemInfos;
- (Commerce_MO *)newCommerce;
- (Liste_MO *)newListe;
- (ListeItem_MO *)newListeItem;
#pragma mark Singleton call
+ (CoreDataController *)sharedCoreDataController;
#end
So in my code when I need to create a new entity I just need to do this :
CoreDataController *cdc = [CoreDataController sharedCoreDataController];
Liste_MO * = [cdc newListe];
For more on the Singleton concept, Look HERE in the Apple documentation at the section Creating a Singleton Instance, and look closely at the code they are giving to make a singleton, that should answer your interrogation about weak or strong link to it.
But in essence a strict singleton implementation will only have one instance of that class created for the whole duration of the application. So if you got 100 objects pointing to it doesn't change your memory foot print, there is only 1 singleton, but if you have thoses 100 objects that will definitely impact your memory.

Where to store fixed NSString variables in Cocoa Application?

I have different classes, that have NSString fixed variables (like #"/Users/user/media", or xml commands). I think to store everything in class is a bad design.
What is the best place to store fixed NSStrings? Might something like preferences file?
P.S. I'm new in Cocoa, please describe it with details, how I can store, and read that values. Thanks.
They are many ways, but I like to do this in my class implementation files:
NSString *const ABConstantStringname = #"name";
Where AB is the name spacing you're using (if you are using one), and ConstantStringName is some meaningful name for the constant.
Then later, you can just use the ABNameIdentifier variable whenever you like. You don't release it.
Depends on the scope - if you want to just une in implementation you can just put in .m, but if you want to expose publically to the consumers of the class (outside your .m implementation) you need to also extern it.
In header:
#import <Cocoa/Cocoa.h>
extern NSString* const BNRTableBgColorKey;
extern NSString* const BNREmptyDocKey;
#interface PreferenceController : NSWindowController
{
...
In implementation:
- (id)init
{
NSLog(#"init");
NSString * const BNRTableBgColorKey = #"TableBackgroundColor";
NSString * const BNREmptyDocKey = #"EmptyDocumentFlag";

Objective-C constants in protocol

In my objective-c project, I have a protocol like this:
#protocol MyProtocol
-(id) get:(NSString *) key;
-(void) set:(NSString *) key withValue:(id) value;
-(NSValue *) getSize;
-(void) setSize:(NSValue *) value;
-(NSValue *) getBounds;
-(void) setBounds:(NSValue *) value;
#end
OBJC_EXPORT const NSString *MYPROTOCOL_SIZE;
OBJC_EXPORT const NSString *MYPROTOCOL_BOUNDS;
And basically, those specific methods (getSize, getBounds, setSize, setBounds) are supposed the value that is supposed to be stored in MYPROTOCOL_SIZE and MYPROTOCOL_BOUNDS, respectively.
However, I cannot find an effective way to set those constant strings, by concatenating the results of other methods, because it gives me the error: initializer element is not constant when I try to set them directly. Is there a way I can guarantee that the objects will always be initialized. (e.g. in a classes load method), without having to manually call code when my program runs?
Well first of all, you should learn the naming convention, for accessors you have - (Type); and - (void)set:(Type)value; whereas in your case you did: - (Type)get; and - (void)set:(Type)value;
I advise you to use #property for your size and bounds accessors too.
Now about the "const" in the NSString variable declaration, it doesn't make sense. Const applies to the type on its left and in case it is at the beginning of the line it applies to the token directly on its right. So what you have is a "const NSString" which doesn't make sense because NSString is already immutable, and sending mutating messages to a const object doesn't issue any warning or errors...
What you actually want is "NSString *const" which states that the pointer to your NSString is constant, you can only assign it at initialization and then it doesn't change...
Now about the protocol... Are you sure you want a protocol in your case ? And not an abstract class that would have your 2 NSString as readonly accessors ?