Where to store fixed NSString variables in Cocoa Application? - objective-c

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";

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.

How Exactly To Use a Global Variable?

I'm a beginner with Objective-C, and am trying to use a global variable. I know that this question has been asked a hundred times, but none of the answers have worked for me. I'm trying to declare a BOOL variable in one class, and check its value in another. This is what I'm working with:
SController.h:
#interface SController : UIViewController {
BOOL leftSide;
BOOL rightSide;
}
SController.m:
- (void)viewDidLoad {
leftSide = YES;
rightSide = YES;
}
Now, for the class I'm trying to access the value of the BOOLs in:
#import "SController.h"
#interface VViewController : UIViewController
{
}
And VViewController's .m:
- (void)viewDidLoad {
// See what the BOOL values from SController are.
}
What I've tried:
Going off of the previous related questions on here, I've tried putting "extern" in front of the BOOLs declaration in SController.h, but that did not work. I tried simply importing the SControllers header file into VViewController, and that did not work either. I'm very new to Objective-C and programming in general, so I'm having a tough time wrapping my head around basic concepts like this. I understand the potential issues surrounding using a global variable, but this program is very small and for personal use. If anyone can show me what to change to make this happen, that would be great.
Like the others said, don't use a global variable for that (and most other) purpose.
You created iVars and in order to access them, you need to expose them to other objects.
You generally do that by defining #properties in your SControllers header file. When doing that, you don't need to create iVars yourself, they are created implicitly. And methods to access the iVars are also automagically created (getters and setters).
Your SControllers header could look something like this:
#interface SController: UIViewController
//no need to declare the iVars here, they are created by the #property definitions
#property (nonatomic, assign) BOOL leftSide;
#property (nonatomic, assign) BOOL rightSide;
#end
In your other viewController you need a reference to the instance of SController you previously created and want to "talk" to (it is important you understand this), then you could access the instance variable through the generated getter/setter methods like so:
//this is "dot notation", the first line would be equivalent
//to writing: [sControllerInstance setLeftSide: YES]
sControllerInstance.leftSide = YES;
BOOL valueRightSide = sControllerInstance.rightSide;
Please read up on: objective-c properties, getters/setters and dot notation.
You will find plenty of information on google and SO
I know this is not the answer you're looking for, but try rethinking your app. Global variables is not the best way to go for Object oriented programming.
Create GlobalVariable.h header class file and defined following externs as follows
extern NSString * googleURL;
And then in your implementation GlobalVariable.m file
#import "GlobalVariable.h"
NSString * googleURL = #"www.google.co.uk";
And then import the class wherever you want to use it across.
By default the variables (as defined in your code) are protected. You can add the #public keyword before the 2 variables to make them public but it's not recommended. Generally you want to expose those as properties using the #property keyword
Example:
#interface SController : UIViewController {
#public
BOOL leftSide;
BOOL rightSide;
#protected
//other protected variables here
}

Where's the best place to store constants in an iOS app?

I'm developing an app just now that fetches resources from a JSON API.
all of the resources have the same base URL:
http://api.mysite.com/resources.json
http://api.mysite.com/other_resources.json
I want to store the http://api.mysite.com/ string so it's available to all of my Controllers and Models, removing some duplication when writing the resource URLs.
Where's the best place to do this? The -prefix.pch file?
Any advice appreciated
I agree with Alex Coplan's answer with an important addition.
Put all your constants in a file named "Constants.h" (or w/e you want)
EDIT:
When I answered this question three years ago, I was on the #define bandwagon, check below for a revision.
Constants.h
#define kFilterDate #"date"
#define kFilterRadius #"radius"
#define kFilterSort #"sort"
//Global Strings
#define kDividingString #" / "
//Strings
#define kTour #"Tour"
#define kToursKey #"tours"
But instead of importing it in any file you need it, import it in your prefix file so that all of your headers import it automatically throughout your project.
Project_Prefix.pch
//
// Prefix header for all source files of the project
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Constants.h"
#endif
REVISION
All though all the previous information will still work, there are some things we can do to be a little bit more safe about our constants.
Create your constants in your Constants.h file using const variables
//Filters
FOUNDATION_EXPORT NSString *const kFilterDate;
FOUNDATION_EXPORT NSString *const kFilterRadius;
FOUNDATION_EXPORT NSString *const kFilterSort;
//Global Strings
FOUNDATION_EXPORT NSString *const kDividingString;
//Strings
FOUNDATION_EXPORT NSString *const kTour;
FOUNDATION_EXPORT NSString *const kToursKey;
And in Constants.m
//Filters
NSString *const kFilterDate = #"date";
NSString *const kFilterRadius = #"radius";
NSString *const kFilterSort = #"sort";
//Global Strings
NSString *const kDividingString = #" / ";
//Strings
NSString *const kTour = #"Tour";
NSString *const kToursKey = #"tours";
This can still be imported into your prefix file like above, but only use constants that are truly global in the file to do that. Ones that are used frequently in many places. Dumping all your constants into this file will cause your code that uses any constant to be coupled to the constants file. Thus, if you try to reuse the code, the constants file has to come with it. This isn't always necessarily bad, and many times is intended (which is fine), but limiting dependencies is always a good idea.
A few things about the revision:
FOUNDATION_EXPORT vs extern. The first one compiles different for C and C++. It basically means extern, but in C++ will add the "C" flag.
consts vs defines. consts are type safe and respect scope. defines are the exact opposite.
Personally I prefer using actual const variables rather than defines.
In a MyConstants.m file I have:
NSString *const kXYMySiteBaseURL = #"http://api.mysite.com/";
NSString *const kXYSomeOtherURL = #"http://www.google.com/";
where XY is my initials or some other "unique" prefix to avoid collisions with other constants.
Then I have a MyConstants.h file like this:
extern NSString *const kXYMySitBaseURL;
extern NSString *const kXYSomeOtherURL;
Depending on how many files need to access these constants, I might include it in the precompiled header like ColdFusion suggests in his answer.
This is how Apple defines their constants in most of the Core frameworks.
I just create a file called Globals.h with something like the following:
#define kBaseURL #"http://api.mysite.com/"
Then to use:
#import "Globals.h" // at the top
NSString *url = [NSString stringWithFormat:#"%#resources.json",kBaseURL];
I would create a singleton or use the AppDelegate and put the constants there.
Yes, a global header would be an ideal solution. I wouldn't go as far as a singleton pattern unless plan on using it for other things like managing your data store. A singleton for globals is somewhat overkill.

Global NSString

I need to create an NSString, so I can set its value in one class and get it in another. How can I do it?
if you write:
NSString *globalString = #"someString";
anywhere outside a method, class definition, function, etc... it will be able to be referenced anywhere. (it is global!)
The file that accesses it will declare it as external
extern NSString *globalString;
This declaration signifies that it is being accessed from another file.
Make it a global variable.
In one file in global scope:
NSMutableString *myString = #"some funny string";
In the other file:
extern NSMutableString *myString;
Global NSString Variable for Complete iPhone Project/Apps
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 easily this variable as Globally.
Carefully follow these Steps and it'll work Surely.
If you're creating a global NSString variable, you should use probably use a class method.
In MyClass.h:
#interface MyClass : NSObject {}
+ (NSString *)myGlobalVariable;
+ (void)setMyGlobalVariable:(NSString *)val;
#end
In MyClass.m:
#implementation MyClass
NSString *myGlobalVariable = #"default value";
+ (NSString *)myGlobalVariable {
return myGlobalVariable;
}
+ (void)setMyGlobalVariable:(NSString *)val {
myGlobalVariable = val;
}
#end
Remember that you should keep memory allocation and freeing in mind. This is not the same thing as a global int value - you need to manage the memory with any NSObject.
Repeatedly just setting the global to new strings will leak. Accessing through threads will create all manner of issues. Then there is shutdown where the last string will still be around.
I think you should use a singleton. A good article that discusses this is Singletons, AppDelegates and top-level data.
Additional information on a singleton class is at MVC on the iPhone: The Model

Global variables in IPHONE APP

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.