How can I use an NSString in a file where that string wasn't created?
ex.
I created a string in thisone.m, but I want to use the same sting (ie the same data) in thatone.m
the data from this string will be coming from a UITextField
If you don't have access to the thisone object, you can store the string as a ThisOne class variable, as long as you don't need a different one for each of your objects. Put the in your class (not inside a method, but outside of the #implementation)
extern BOOL theString;
The access is by
[ThisOne theString];
This is not as good as ennuikiller's answer, but it might be what you need.
I'm not sure exactly what your asking but there are many ways to share data between files (or objects). You can define it as an instance variable in one class and take a reference to the object instance in other class. You can pass the data to a method called on the other object, or you can share it as a global variable by making it an instance variable of UIApplication.
Again, without being more specific in your question, this should get you thinking along the right path.
As a simple example:
#interface MyObject : NSObject {
NSString *mystring;
}
I know some people don't like #define's, but they work well for this old-school C programmer.
In each project, I have a file "Strings.h" which contains a bunch of #define's, such as:
#define SK_String_I_Want_To_Display #"String I Want To Display"
(where SK_ is my preface to indicate "string constant".)
For localization, I have another file called "LocalStrings.h" with strings like:
#define SK_LOCAL(a) NSLocalizedString(#a, "") // keeps string defs simple
#define SK_Localized_String SK_LOCAL("Localized String")
#define SK_Another_String SK_LOCAL("Another String")
Then I just #import "Strings.h" or "LocalStrings.h" where needed. Because I have all localized strings in one file it's easy to make sure I have localized everything.
The biggest issue with this approach is that you have to be careful not to do something like this:
#define SK_Another_String SK_LOCAL("Another String");
--- as that semicolon at the end can cause tricky bugs that are hard to find.
The overhead of having the #define expanded in place is pretty low. Compiles take a bit longer if you change one of these .h files, but I find the solution works well.
Related
I am working on an iphone application and I am wondering what the correct practice is for abstracting out strings. I am used to creating a file with constant strings and referencing them in my application (such as urls, port numbers or even button labels). I am wondering if this is considered good practice in Obj-C and if so what the best way to do it is? Should I make a class with the strings? Or use the ".strings" file?
p.s I may be localizing my application at a later time. I havent looked into how to do it, but I figure abstracting out my strings is a good idea while i'm developping.
Thank you!
MGA
generally, you interface with NSBundle. You use a string to read a localized version of the string (which is loaded from a localized strings file).
there are also some macros some people use to lighten the syntax, these are prefixed with NSLocalizedString. NSLocalizedString implementations use NSBundle.
imo, you should use string constants to identify the localized string you read (like you should with dictionaries and object keys).
you can declare your constants using this form (objc assumed):
extern NSString* const MONAppString_Download;
and define like so:
NSString* const MONAppString_Download = #"Download";
then access it using:
NSString * tableName = nil; // << using the default
NSString * localized =
[[NSBundle mainBundle]
localizedStringForKey:MONAppString_Download
value:MONAppString_Download // << return the string using the default localization if not found
table:tableName];
sometimes it helps to create wrapper functions to reduce the noise, especially when you use them in many places:
// #return what's set to the above variable named 'localized'.
NSString * MONLocalized_Download();
then you set up your strings files like a map, one for each localization you support.
so, whenever you need to read a string which is visible to the user, you use the above form. also consider that there are other resources to localize (nibs, images, pdfs, etc.) which you may bundle with your app. much of the work here is also abstracted by NSBundle, of CFBundle, if you prefer.
good luck
I have two views with their own .h and .m files of course. How can I declare a bool (or any variable for that matter) in one view and be bale to access it in another view?
Thanks.
Objective C is a superset of plain ANSI C, so you would create and use global variables exactly the same way as in old-fashioned C.
In exactly one .m or .c file, put:
BOOL gMyGlobalBoolVar = NO; // or YES, depending on whatever initial state is needed
I might place these in a centralized singleton class, such as your appdelegate .m file, or in a separate .c file, such as myGlobals.c. I usually place these after the #imports/includes but before any class, method, or function definitions to clarify that they can be accessed outside of any object or function.
In the .h files for all classes where you want to access gMyGlobalBoolVar, put:
extern BOOL gMyGlobalBoolVar;
Then just use them anywhere in the class:
if ( [ self dogHasFleas ] ) {
gMyGlobalBoolVar = YES;
}
The use of global variables is currently not "politically correct", but for quick code that you will never try to publish, reuse, extend, or hunt for gnarly bugs, they work just fine like they did in almost every computer and programming language from 50+ years ago.
You can just take a reference to the view containing the bool and get the variable using a getter.
If you want app wide variables, you could put them in the AppDelegate, but I highly recommend against that since it tightly couples classes.
Create a data model class. Instantiate it in your app delegate, and pass it along to your view controllers. Use Key-Value Observing to track changes to the model in your view controllers. See my answer here: How do I display and calculate numbers from a database on iPhone?
"Why shouldn't I use globals? It can't hurt just this once." This is a bad habit to get into. Avoiding global variables makes your code easier to read and reuse, easier to extend, and easier to debug.
How do I use global variables in x-code(iphone). For example, lets say i want to declare a bunch of variables(NSStrings) in the viewcontroller file, then how would i access them throughout my different classes? Can someone help me?
Global variables are global variables. You use them the same way you would in any C program, which is to say typically they'd be declared in something like "globals.h" and imported wherever needed.
With that said, it's generally poor practice to rely on globals. You might have an "ApplicationController" object which in essence tracks the global state of the application, but its variables should be instance variables and either accessed only internally, or via getters/setters.
If you wanted to declare a bunch of strings in a single object to be referenced by many other objects, typically you'd make that object a Singleton and pass a reference to it to each object needing access to it.
However, you need to ask yourself WHY you need to do that and if there isn't a better way. I'll bet dollars to doughnuts there's not a good reason for what you're trying to do.
Give us some more details on what the overriding need is for these strings to be global, and then we can show you reasons why they don't. :)
You may use a singleton if it's not too over-killed. Another option is NSDefaults. Of course, the simplest way is simply define an extern in .h
extern NSString * const STR_1;
and the value in .m:
NSString * const STR_1 = #"String One";
just declare your variables in the .h file and then import this file in any class you want to use it. You can make any type of object or variable global.
If you declare the variable in delegates, You can access those variable in any other controllers using setter and getter methods to access.
See Warrior Answer
I hope,it will help you.
What is the easiest way to create a global object. I have tried declaring the object outside the method with no luck.
#implementation UV_TouchpadViewController;
NSMutableString *string = [NSMutableString stringWithFormat:#"text"];
Very close -- you can't initialize a non-local variable with a non-const expression, and a method call is inherently non-const, even if it looks like it should be. So basically, change it to
NSMutableString *string;
but if it's only going to be used inside the implementation file (eg. other classes would only get at it through UV_TouchpadViewController, not get/set it directly (this is also the recommended pattern)), then qualify it as static, like so
static NSMutableString *string;
If on the other hand you do want to be able to access it directly from outside UV_TouchpadViewController, leave off the static, but add
extern NSMutableString *string;
to your header file (outside the class #interface), and whomever includes the header will be able to access it. (Note that you could instead just put NSMutableString *string; in your header file, however this is quickly becomes unclear)
Also, if you are trying to do this for a singleton class, (I can't think of a good reason to have a global mutable string -- you know they're not thread safe right?) I recommend reading Apple's docs on singletons first, where they suggest you use ivars, not global variables, even for singletons. However, UV_TouchpadViewController should not even be a singleton (if it is in any way a view controller), it should just have a single instance, if that's all you want.
If on the other hand you just want all UV_TouchpadViewControllers to have access to this one variable, note that across almost all languages this is considered a bad design pattern (globals are bad), and that you should instead stick it in, say, your app delegate (which is guaranteed to have a single globally accessible instance), where it can be an ivar+accessors, and generally considered a setting and (with a little extra code) persisted.
EDIT:
If you want to have a singleton that maintains global state, which I still recommend against -- you should create a class, like for instance ApplicationState, which handles all of the application's global state as a model object in the traditional model-view-controller pattern. I wont go into detail here because that would be highly redundant of a google search.
In your Application Delegate, somewhere, add an ivar ApplicationState *state, and a corresponding #property (and #synthesize in the implementation file).
There are few easier ways to shoot yourself in the foot than by using global variables.
You should never expose a dumb object like a string which has no access control to every object in the app. Any random piece of code anywhere in the app can change the mutable string leading to chaos as the app grows larger.
Usually when people want a global variable what they actually need is either the user defaults or a data model.
The user defaults (NSUserDefaults) is the preference persistence system that saves application state and user's settings both between launches and as the app runs. You can park small bits of data, such as strings, in the defaults and access them easily from anywhere in the app.
A data model is dedicated object that holds the applications data and manages access to it such that only the data model has final control. This makes it easy to tell what has changed the data and how. The data model can be a simple custom class or something elaborate such as core date. You can park the data model in the app delegate or create it as a singleton as the other answered have explained.
I have been using the Apple API for years and I have never needed to use a real global variable. If you think you need one, you probably have misunderstood something about application design in the Apple API. You might want to post a question explaining what you're trying to do with a global variable and what the best strategy should be for doing it without the dangers of using a global variable.
Do you need it for each instance of the class? If so, you should make it an Instance variable. Put
NSMutableString *string;
In your header
And then you can set it in any method in your class.
If this isn't what you meant, update your question or comment.
You can achieve that by implementing getter and setters in the delegate class.
In delegate .h file
Include UIApplication delegate
#interface DevAppDelegate : NSObject <UIApplicationDelegate>
NSString * currentTitle;
- (void) setCurrentTitle:(NSString *) currentTitle;
- (NSString *) getCurrentTitle;
In Delegate implementation class .m
-(void) setCurrentLink:(NSString *) storydata{
currentLink = storydata;
}
-(NSString *) getCurrentLink{
if ( currentLink == nil ) {
currentLink = #"Display StoryLink";
}
return currentLink;
}
So the variable you to assess is set in the currentlink string by setters method and class where you want the string ,just use the getter method.
AppDelegate *del=(AppDelegate *)[[UIApplication sharedApplication]delegate];
TO set:
[del setCurrentLink];
TO Get:
NSString *value=[del getCurrentLink];
All the best
Add:
NSMutableString *globalString = nil;
to any .m file of any object. The nil initialization adds a little safety, since nil objects can be "safely" messaged without outright crashing the app.
Add:
extern NSMutableString *globalString;
to the headers of any other objects that needs to access this global.
Add:
if (globalString == nil) {
globalString = [ [ NSMutableString stringWithFormat:#"text"] retain ];
}
to the init of any class(es) that could be the very first to touch this global, or to some init that happens even earlier.
Globals are a less verbose form of singleton, but with no access restriction or tracking. Use with caution.
actually as per my r&d i got that by use of extern we have to create an instance but the final thing is to #define your variable and can access any where you want without any creating of instance and other thing just directly use variable by its name....
So, I read this post, and it's pretty much exactly what I was looking for. However... it doesn't work. I guess I'm not going to go with the singleton object, but rather making the array in either a Global.h file, or insert it into the _Prefix file.
Both times I do that though, I get the error:
Expected specifier-qualifier-list before 'static'
and it doesn't work. So... I'm not sure how to get it to work, I can remove extern and it works, but I feel like I need that to make it a constant.
The end goal is to have this Mutable Array be accessible from any object or any file in my project. Help would be appreciated!
This is the code for my Globals.h file:
#import <Foundation/Foundation.h>
static extern NSMutableArray * myGlobalArray;
I don't think I need anything in the implementation file. If I were to put that in the prefix file, the error was the same.
EDIT
So, I removed the .m file from Globals, and I just have the code about in Globals.h. Assuming I am going to continue with this terrible practice of having global variables (I know it's bad, I just want to test this out), I now have a new error. It says:
"Multiple storage classes in declaration specifiers"
If I remove "extern" it works and if I remove "static" it works, but having both doesn't... what now?
****Double Edit****
Aright, so I've tried adding the array to my UIApplication Delegate, but I'm doing it wrong because it isn't working. Could someone give me some example code as to where to place it an access it? I don't know if it should go in the implementation, or somewhere else, and once the array is initialized how to access it from the other files... Do I set a new variable to the array, or something?
Just a general programming suggestion--don't share an array. You have no control over it and it will be virtually impossible to trace if something changes it at a time and in a way you aren't expecting.
Instead, create an object with the array inside it and make that object a singleton (or better yet, make a factory for it).
Whenever you want to modify your array, call methods on the object to do so. If you do this, I bet you will find a lot of redundant code you can factor into this object (for instance, searching the array for a value--make a "search" method in the object instead and pass in a value).
It may seem like a lot of work you shouldn't have to do, but you'll find it's fairly fun work, and you should find that you DO have to do it once you see how much code belongs in this object...
Just add the array as a property of the application delegate, and access it like:
[[UIApplication sharedApplication] myArray];
The two (main) ways of making an array global are separate -- either you have a class with a method
static NSMutableArray *foo;
+(NSMutableArray *)foo {
return foo;
}
(in the .m file) with the static piece NOT in the header file, or just
static extern NSMutableArray * myGlobalArray;
with out the singleton wrapper (which I think is better as it saves you from having an extra bit of unnecessary code)
Either way, it is still a bad practice that I would try to avoid.
In general, the presence of a "Globals.h" file is a bad smell that there's an antipattern at work.
I would even advise against Bill K's advice and not use a Singleton pattern at all.
Instead, create the array in your app delegate, and pass it to your root view controller(s), and along the hierarchy to the components that need access to it.
This is what I was looking for:
http://derekneely.com/tag/app-delegate/
Thank you for pointing me in the right direction!
#import <Foundation/Foundation.h>
static extern NSMutableArray * myGlobalArray;
#interface Globals : NSObject {
}
#end