I want to have macros for all constant strings in the project, which I am assigned to maintain.
The format of database fields are like #"first_name", #"last_name", etc.
What I want is like follows:
#define kFirstName #"first_name"
#define kLastName #"last_name" // And so on.
Problem: I have over 3500 unique fields with constant strings. I want each one of them to be defined as macro.
Any smarter way to do this. I am thinking of manually copy, paste & edit each one of them.
Tagging as iOS & Objective-C, as the project itself is an iPad Application.
In general, defining constants like this is the way to go on iOS, so you're on the right track.
You surely won't get around typing out each of the fields at least once.
I would recommend either of two approaches:
use multiple .h-files for the definition of all the constants. you can group the header files according to the definitions that they contain (e.g. all fields related to user data in UserDefinitions.h). that way you at least make sure that you don't have to import all the constants everywhere in your code. working with prefixes will also be helpful in this situation, so prefix all the Macros names with the .h-file that they contain, e.g. kUserFirstName so that you you know at first sight where this constant comes from
define all your constants in one (or multiple) property lists. that makes them easy to maintain. only make sure that you don't load the property file each time you use one of the constants, but rather cache the file once its loaded for the first time.
When using Core Data consider using mogenerator which creates constant values for you that you can reference for all of the attribute and relationship names.
the cleanest way is to make a pair of constants files (header and main). Create a new class (inheriting from whatever, NSObject say) call it constants. Delete the #interface and #implementation, so you have an empty header (except for #import Foundation/Foundation.h) and empty main (except for importing the header.)
then declare each in the header like this
extern NSString *const kFirstName;
and implement each (in the .m file) just like this
NSString *const kFirstName = #"Johnny";
make sure the .m file is added to your target, import the header where need be.
Related
I am mostly writing this for other newbie folks and to remind myself in a few years when I forget what I did
I had a long list of localized strings in the application I was building. I really hated the lack of readability as I plodded my way through a whole bunch of statements like
[_myUILabelObject setText:NSLocalizedStringFromTable(_myString, applicationLanguage,nil)]
Then I was going to need another one that was different for UIButtons and UITextView and so on. There had to be a better way. What I wanted was something like
[_myUILabelObject translateMe:#"This text");
So here's what I did:
I created a bunch of class extensions (technically categories) for each object: UIButton, UILabel, UITextView... whatever I needed.
Each one has a simple .h file that simply declares that the extension is related to the main class. Here's an example for my translateMe for UITextField:
#interface UITextField (translateMe)
- (void) translateMe: (NSString *) usingString;
#end
The first line tells the compiler that translateMe is going to be an extension of UITextField.
The second line tells the compiler that translateMe is expecting to be a method of UITextField that receives an NSString that I've called usingString.
Then in the .m implementation file, I've done this:
extern NSString *applicationLanguage;
- (void) translateMe: (NSString *) string {
[self setText:NSLocalizedStringFromTable(string, applicationLanguage,nil)];
[self sizeToFit];
}
The applicationLanguage string is a string that I set elsewhere based on the user's selection of language and it essentially is the name of the .strings file.
The rest of the code here simply includes all the laborious coding that I wanted to avoid in my ViewController's code.
Now the magic here is that one can create similar combinations of the .h and .m files for every object you have in your ViewControllers. If you call all of the methods translateMe, then you don't have to worry at coding time which of the objects you're actually calling. The result is you get something that looks simple like this:
[_standardDemoPlanTitle translateMe: #"Standard Demo Plan"];
[_linkSampleDemoVideoButton translateMe: #"Link to sample demo"];
[_linkCustomerPresentationButton translateMe: #"Link to customer presentation"];
[_personalNotesTitle translateMe: #"Your Personal Notes"];
[_theSaveButton translateMe: #"Save"];
[_emailPlanButton translateMe: #"Email this plan to a colleague"];
Note that the fact that some are buttons and some are labels (Titles) doesn't matter at all.
As an additional short cut, I learned from another post that it is possible to deal with long sections of text in a short way too.
Instead of:
[_longTextRequiredByLawyers translateMe: #"blah blah blah blah blah forever..."];
What I can do is to put in a short handle for the text in the implementation file and put the longer text in the .strings file. Here's an example:
[longTextRequiredByLawyers translateMe: #"#lawyerText"];
by the way, the #-sign is not required, but I used it throughout my .m files as a personal reminder so that I knew that what was going to inserted did not necessarily match with what was in the prototype in the interface builder.
Then my english.strings file included something like this:
"#lawyerText" = "When in the course of human events it becomes necessary for one people to dissolve the bonds which have connected them with another and to assume among the powers of the earth the separate and equal station to which the laws of God...";
and my spanish.strings file had the translation:
"#lawyerText" = "En México no hay abogados, entonces el texto es mas corto.";
You could do the same thing for Albanian and Klingon.
So, key tricks (or good programming ideas here):
Use Cateogries to extend the class definitions for the UI objects you have on your pages. Those categories can include everything you need to make your main code more readable.
Name the method the same thing in every extension so that you don't have to think about it when you do the magic in your .m files.
Use short handles for long strings of text and jam the longer stuff into the .strings files.
One thing I wish I had figured out:
I now have a long list of .h files that I now have to #include at the top of all of my ViewController .m files. I wish that I could have a .h file that #includes all of the translateMe .h files... kind of a nested .h.
UIButton+translateMe.h
UITextView+translateMe.h
UILabel+translateMe.h
UIButton+translateMe.h
and so on
Wouldn't it be nice to have a single .h file, perhaps allMyTranslates.h that has the list above inside of it, and then I just include allMyTranslates.h in the code I am writing.
I would end up replacing:
#include "UIButton+translateMe.h"
#include "UITextView+translateMe.h"
#include "UILabel+translateMe.h"
#include "UIButton+translateMe.h"
#include and so on
with this
#include "allMyTranslateHeaders.h"
Well, there you go... a few notes from a newbie... All the experts have been helpful of course, but every once in a while we need a note like this one to get us over the hump!
I have an iOS application I'm writing. I've moved away from #define to create my constant values. I have a few questions regarding the use of these style declarations: NSString *const segueToMainMenu
If I'm using these internally, I'm placing them inside the .m file. However, should I be placing these wrapped around the #implementation block or outside of it or does it matter? I'm thinking inside, because they are specific to the implementation and not global, but I'm not sure. Any details are appreciated.
If I'm creating a more global scope using the extern keyword and I'm using a Constants file pair (Constants.h/Constants.m) do I need to place those in the #interface section and then define them in the #implementation section? What is the benefit of that vs the old way of just using a Constants.h file and including it with other headers? Why do I now need two files?
Is the standard practice still to name the constants with a "k" prefix (e.g. kAnimationDuration) or should I now be doing something like MainMenuViewControllerAnimationDuration? I'm imagining yes and if so, does it matter for the constants from number 1 (i.e. not extern) how I name them? In other words, are those visible outside of my implementation?
Clarification is much appreciated.
Doesn't matter whether you place them inside the implementation block or not—only methods are part of the class implementation, so the scope of constants won't change regardless.
The k prefix is a bit dated now. The usual way is to name constants as <prefix><name>, such as "MDSomeConstant".
I have a file called ViewMessages.m which is becoming quite verbose. I'd like to refactor and put part of my methods into a separate file. It seems that Categories are the right way to go, so I've created a Category on ViewMessages called DataEngineViewMessages
It created 2 files, DataEngineViewMessages.h and DataEngineViewMessages.m
My Question: Do I need to #import "DataEngineViewMessage.h" in my original ViewMessage.h or .m in order to access my new methods?
Not into the .h file. The category header should import ViewMessages.h, and if required the category header should be imported into ViewMessages.m. This prevents any kind of circularity.
Usually you want to differentiate between category methods that should be public (defined in a header perhaps like ViewMessages+DataEngine.h) and category methods that are for internal use (defined in a header perhaps like ViewMessages+Private.h). The former shouldn't be included by ViewMessages and the latter should (again, in the .m file).
Any code that calls the methods will raise a compiler warning if the compiler can't see the method definition. They may also raise an error if the compiler can't figure out exactly what to do about the return type and you're expecting it to be an atomic C type.
In terms of keeping the external interface untouched, you can probably just add a #import for your category methods at the bottom of the main class's header file.
I have a project, with a file that I call 'Keys.h'
In that file, I declare strings and integers that are used across the project, some of which are integers, some of which are strings.
All of the strings work fine; however, if I use integers, I get an unused variable warning.
For a string, (lfPrefs is a dictionary of user preferences)
static NSString * kUserLFPrefs = #"lfPrefs";
This works fine, and does not produce any errors.
For an integer, (I have integers to define the current mode because it seems a bit snappier than comparing strings all the time).
static int kModeLiveFeed = 1001;
static int kModeEventFeed = 2002;
These work just fine, except that they are showing an unused entity warning.
I'd prefer to use the integers over strings, mostly because I read that comparisons are much faster, takes up less memory, etc.
My question is how can I stop the warnings while still getting access to my integer keys?
(Or, should I just use strings)
I can suggest two different methods.
If you want to keep such variables in .h file, you may prefer using define if you will not be changing the value run time like;
#define kModeLiveFeed 1001
If you will be changing the variable value run time, I suggest keeping them in a .m file instead of in a .h file and creating only one instance of the .m file by using singleton. Then, even if you continue to get a warning from the .m file, you can disable it by the steps below:
Select your project from the left navigator to open project settings view.
Then, select your target.
Go to Build Phases tab and open compile resources area.
Click to the right side of your .m file to add a compiler flag as -w
I hope it helps.
You may be misunderstanding the meaning of static in C/Objective-C (this question should help). You should use const rather than static to define constants, and you should define the value of an integer/string constant in a .m file, with a corresponding declaration in the .h file. Or better yet, use an enum if you have a related set of integer constants.
Here is Apple's documentation on constants, which includes the above information as well as naming recommendations (e.g., PRConstant is preferred over the classic Mac OS-style kConstant).
I am making a multiple choice quiz app. In my main class, I have an integer called "points" that is used to display the current points earned in the quiz view. However, I also want to display the points in the view of another class, which tells the user that his answer is correct.
I know that you can do this if one class is a subclass of the other, but can you do it if they are not related?
One way to do this is to set up points as a global variable. Like so:
In your AppDelegate.h file insert this line after the #end:
extern int points;
In any classes that needed to read/write to points, in the .h files after the #end, add this line:
int points;
I would look into something like Singleton Objects
This link provides a basic example of simple Singleton Objects, which you could use to share a variable between classes.