If I want to declare a constant string (not necessarily changing based on language) that can be used in multiple .m files should I do that in my InfoPlist.strings or should I create a separate global.h file and use #define?
The research I've done makes me thing global.h is the way to go but I want to make sure.
It depends on what type of constant you need. For a simple string constant, using a .strings file has an advantage in that it doesn't need to re-compile the binary to have the values available inside the app, on the other hand, makes it easier for a hacker to modify.
Using a .h to store constants is better if you want to store numerics, as parsing an integer from a string is no small task.
Most of the time, I would say that a .h is better, but beware of pitfalls of using one! You cannot take an address of a constant in a .h (which normally you don't have to use), and comparing a string with == and a constant is a no-no.
Related
I have an Objective C++ program used to handle the setup of our different applications. Is there a way to use preprocessor defines to create text to be substituted in the strings used by NSTextFieldCell, NSButtonCell?
FOR EXAMPLE, instead of have an NSTextField that says "Options for setting up Foo", there would be a preprocessor macro (GCC_PREPROCESSOR_DEFINITIONS):
MY_PROGRAM_NAME=Bar
and then the text for NSTextField would be:
"Options for setting up $(MY_PROGRAM_NAME)"
Which would then have the desired result: "Options for setting up Bar"
NOTE 1: obviously, I could do the substitution programmatically in code.
Note 2: this is for Xcode 7, so perhaps there isn't a feature like this?
In a word, no. The Xcode nib compiler doesn't perform any kind of variable substitution and—once encoded—all archived property values are static.
However, if this is a "thing" for you application, and there aren't too many view classes involved (say, just NSTextField), it wouldn't be hard to roll your own solution.
I'd consider this approach:
Concoct a simple-to-substitute syntax, a la "Some string {VAR_NAME}".
Define your variables as key/value pairs in a dictionary. Store the
dictionary as an XML file / dictionary in the app bundle.
At app startup, load the dictionary and make it public by putting it in
a global variable or adding it to -[NSUserDefaults registerDefaults:]
Subclass NSTextField (as an example). Override either
-initWithCoder: or -awakeFromNib. In the override, get the string
value of the view object, scan it for substitutions using the public
variable dictionary, and update the string property as appropriate.
In IB, change the class of any NSTextField that needs this feature to
your custom subclass.
Another possible approach would be to have multiple targets in your project and a separate Localizable.strings file for each of these. This of course assumes, that you use Localizable.strings, even if you may support only one language.
While a class usually has the same name as it's contained class - how about the filename of a struct? The below example actually works.
File names and files themselves are completely arbitrary. You can put multiple object type declarations in one file, and they need have nothing to do with the name of the file. (You can also spread out an object type declaration over multiple files, thanks to extensions.) And the names of those types are unrelated to the name of the file.
The reason for giving a file a name that has something to do with its contents is so that you can find those contents; it does not affect the behavior or compilation of the program in any way.
Okay, exceptions:
In Swift, only main.swift has special behavior based on its name - and you don't have a main.swift.
Privacy in Swift is file-based, so you want to separate object type declarations that need to keep things private from each other into separate files.
They usually do but in Swift you honestly can call any file anything you want. I have many different files with not directly related names, some with one class, some with multiple, some with just structs, some with class(es) and structs. The new class function in Xcode will give it a specific name but that was never necessary.
There are some enum types in my iOS objective-C app that are used in different classes, for them I guess its fine to put them in a constants.h file, but what about others that are not necessarily used in multiple classes? would it be considered a bad practice?
While sapi's answer isn't wrong, here's what I have a tendency to do...
A group of constants that are used across multiple files will go into a file. Let's say all my Foo constants go in FooConstants.h.
Now another group, say the Bar constants, they'll all go in BarConstants.h.
These files will have constants, enums, and protocol definitions in them.
In the files that need the Foo constants only, I'll import FooConstants.h.
In the files that need the Bar constants only, I'll import BarConstants.h.
And depending on the project, I may have just 1 of these files, or I may have 10 or more. Usually I'll have a file called SegueNames.h, where all of my storyboard segue identifiers are created as constants and put in this file so I never misspell a segue name. I'll also usually have DefaultsKeys.h, where I keep the keys to anything I'm putting in NSUserDefaults.
And then I started realizing every now and then, I might have a file that uses 6 of these constants files, so I started creating Constants.h.
Constants.h has nothing in it except importing all the other constants files. This cleans up the top of some of my files.
But at the end of the day, I do still keep the constants organized in their own files with some sort of grouping putting common constants together. And as sapi points out, any constant that is used only in a single file should be defined within that file.
Yes, it is bad practice.
If you place all of your constants, including enums, into the one file, then importing that file becomes necessary whenever you want to reuse part of your code.
A better practice would be to group your constants by function (at whatever level is appropriate for your app), and to include constants used only in a single class in the class file itself or, if you must, in a separate header.
It depends on the context. How well organized are your classes? If it's a bit of a mess, it doesn't hurt to start with an Errors.h/m file where you define your error codes as enums in the .h file and your error domains as NSStrings in the .m file (with corresponding extern NSString * const in your .h file).
If your organization is a bit better, then you've divided your classes into modules and each module has an entry point, where you should be defining these things. The result doesn't change though: Error header for enum values and extern declarations, error implementation for extern assignments.
All my error declaration files look like this:
// ErrorFile.h
typedef enum {
ModuleErrorOne = 1,
ModuleErrorTwo,
ModuleErrorThree
} ModuleError;
extern NSString * const ModuleErrorDomain;
// ErrorFile.m
NSString * const ModuleErrorDomain = #"ModuleErrorDomain";
You can stick it in your pre-compiled header for a compilation speed boost.
EDIT: Thanks for the comments nhgrif and GraniteRobert, they've improved my answer.
I’m developing an iOS application. One of my tasks is localization. For this reason, I’ve taken all strings and put them each in a NSLocalizedString(key,comment), and everything’s been OK.
But my new solution is to create a Singleton class, which stores every String that I use in the project. With this I have one small, but tricky problem: naming. Do I need to create some dictionaries for every class (view) that needs localized strings? Or should I use prefixes for this, or functions that return objects with good, understandable property names?
P.S: i don't want to invent new wheel. I want to create STORAGE of localized strings, that will be used in project. So, my target is to make singleton:
[[[StringStorage sharedInstance] getStringsForClass:self] objectForKey:#"title"];
or something like this:
[StringStorage sharedInstance].stringTitleForMainView
You really should stick with NSLocalizedString and NSLocalizedStringFromTable. You also can use the NSBundle method localizedStringForKey:value:table:.
But if you take any other route you are reinventing the wheel, and you lose the ability to use the genstrings command line tool to extract all your strings from the source code.
I noticed that in many community Objective-C classes and in Apple's frameworks they name some of the variables using a convention that prefixes variables with an underscore, such as: _name. What is the reason for having the underscore. Should I be doing this in my own classes? If so where and when should I use it?
That's called uglification. The point is that you never use it, so no variable name or #define you create could ever interfere with Apple's code.
Ironically, many people create header guards with such names, because they see the system headers do it.
From C99 7.1.3 "Reserved identifiers":
All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
(They mean reserved for the system library.)
Note: I'm not sure of the exact relationship between C99 and Apple ObjC, but you might as well have naming conventions that work across the entire C language family. In particular ObjC++ would require valid C++ names, which have the additional requirement of no double underscores anywhere.
In Cocoa, it's a convention to indicate the something is private and shouldn't be used externally. However, it's unofficial convention, particularly in light of wording like this in the documentation:
Method names beginning with “_”, a single underscore character, are reserved for use by Apple.
However, that recommendation specifically applies to methods, not variables. So if you'd like to prefix your variables with underscores, go right ahead. That being said, if you're using the underscore prefix to indicate the private nature of some data, perhaps you shouldn't be exposing it in the first place...
Underscores get in the way of readability. Also with LLVM in place of GCC, I am getting rid of header side ivars and using header side properties. Be sure to make your properties non atomic unless you really want reads and writes synchronized for thread safety. unless you specify non atomic, it will default to atomic - which will deprive you of some performance.
also by convention, never start accessors with get. setters Should start with set but no getters with get. Read up on KVO and KVC for more about the conventions and what they are good for.
I do however like underscores in Enumeration naming list. Here the underscores help me pick out the suffix in 5 or more lines that all start with the same stem.
Like
typedef NSInteger COMPASS_DIRECTION;
enum {
COMPASS_DIRECTION_NORTH,
COMPASS_DIRECTION_EAST,
COMPASS_DIRECTION_SOUTH,
COMPASS_DIRECTION_WEST,
};