What overhead is there #defining objects? - ios

We have a constants file and want to be able to whitelabel our app.
Part of the white labelling is defining images that can be swapped by our clients.
What overhead would defining all these images be?
e.g. #define kMPNavigationBarBackgroundImage [UIImage imageNamed:#"nav_bar"]
Would it be worth defining NSString constants for the image names? Or will this be ok?
Bear in mind there will be hundreds of these images, are they all going to load into memory at this point? Or is the #define just a palceholder for lines of code which won't get run until they are called?
Thanks

"#define" is preprocessed by the compiler, before the compilation takes on all your kMPNavigationBarBackgroundImages will be replaced by your definition. It doesn't have anything to do with runtime.
http://www.cplusplus.com/doc/tutorial/preprocessor/

When you use #define to define some sort of constant it is just a preprocessor directive to tell it to replace the defined text in the code.
So if you use:
#define image [UIImage imageNamed:#"name"];
UIImage *myImage = image;
Then before compilation it will get changed to:
UIImage *myImage = [UIImage imageNamed:#"name"];
It just gets replaced everywhere that you use it.
Hope that helps!
:)

Well in short, your last statement is correct; the code which forms part of the #define won't be evaluated until it's referenced in the code.
Perhaps a better approach to the issue would be to put all these Assets into a dictionary that can be optionally swapped out by "the client" if they wish. The dictionary would map the well known name to the asset filename.
The issue with using #defines is that it relies on the customer putting the right code in the definition, which is tedious and error prone, for example:
// (Missing end quote)
#define kMPNavigationBarBackgroundImage [UIImage imageNamed:#"nav_bar]
Will cause a non-obvious compilation warning.
A more elegant approach would be to provide a method (somewhere) where you simply supply the well known name:
- (UIImage *)imageWithWellKnownName:(NSString *)wellKnownName;
Which looks-up the asset filename and loads it, throwing an exception if the file could not be loaded.

Related

How to keep expressions in HandleBars.Net for later evaluation?

This seems to be a simple matter and maybe it's solved already, but I'm not sure how to do it. I'd like to keep arbitrary unresolved expressions for later evaluation. Note that I still don't know which expressions are already defined.
For example, suppose I have the expression...
{{source.path}}/mainmenu{{ext}}"
...and the context defines ext as .js, but source.path is still undefined. What I get is/mainmenu.js", but I'd like to get {{source.path}}/mainmenu.js" instead so that I can evaluate {{source.path}} at a later time. HandlebarsConfiguration.UnresolvedBindingFormatter seemed promising, but it doesn't handle the complete original expression. HandlebarsConfiguration.ExpressionNameResolver also didn't help.
So, is it possible to do this at all? Thanks in advance for any help.

Xcode 5 weird errors

Something strange is going on with my Xcode 5. All of a sudden I'm getting Undeclared Identifier errors for all the values in my Constants.h file, which is imported in my Prefix.pch file.
Two things are weird here:
This hasn't happened before.
When I do build and run, the build succeeds and the app runs with no problems.
I tried restarting Xcode and the simulator, and even restarting the whole machine. No luck.
What's going on? How can I get rid of these false errors?
EDIT following rmaddy's request. The error is Use of undeclared identifier kOffsetFromTop (for example, there are other similar errors with different constants.)
I don't really want to post my entire constants file, but the constant in question is defined like this:
static int const kOffsetFromTop = 20;
When this happens I normally do the following
Comment out the import from the .pch
Clean all ⌘⌥⇧K
Delete derived data
Build
Then uncomment the import from the .pch and build again. I'm not sure which step is actually sorting the issue but this normally gets me going again.
Multiple points here :
You have a warning, not an error. A warning is just that, it warns you but does not prevent the code to compile. That is just to warning you that something is odd or unexpected, or to tell you that what you wrote may not be actually what you were intended, because the compiler finds it odd or not standard.
You didn't have the warning before probably because it wasn't activated by default in previous versions of Xcode. The latest version of Xcode5 activates more warnings (which is a good thing, as it warns you about more things that could go wrong in your code and encourage you to fix them), hence this new one you have but didn't have before.
As I understand what you describe, tour usage of a constant is incorrect (and that's probably why Xcode emits a warning).
The correct way to declare a constant that you want to be accessible from multiple files is to:
Declare it (define its existence and type) in a header (or in your pch) like this: extern <type> const <name>;
And define it (give it a value) only in one implementation file (like your main.m, your AppDelegate.m, some Constants.m file, whatever) like this: <type> const <name> = <value>
Some details and reminders about constants declaration (also valid in standard C)
You use static <type> const <name> = <value>; in an implementation file only, when the constant is local to the file and does not need to be used by other files. In that case, you declare it typically in the .m file in which you will use it, and other files won't have access to it (which is quite what the static keyword means, actually (making the constant attached/local to the file).
In that matter, you should never declare a constant that way in a header file (and especially not in your .pch file), because header (and pre-compiled header) files will be included multiple times. If you do that, this would declare as many independent constants as the number of implementation files you include your headers into (this has evil side effects especially for pointers/objects, for exemple declaring an NSString* const that way -- for, say, using it as a notification name of error domain -- will create multiple string constants, with the same value but different addresses, which will probably not behave like you will expect)
When you need to declare a constant that you need to use / be accessible from multiple implementation files, so declaring this constant in a header file so that it is known to all implementation fiels that includes this header, you need to only declare it in the header, and not making it static (at this would run against the purpose of having the same constant for all files instead of multiple independent instances of the constant) but instead indicate extern to let the compiler know that its definition (value) is set elsewhere. Hence the solution given above.

What do I need to do to use tgmath on iOS?

I'm compiling my first project with 64 bit support enabled. I'm running into a bunch of compiler warnings about implicit conversions to float. This is happening because I'm using fabsf() and assigning the result to a CGFloat (which is a double, not float on the new 64 bit architecture).
According to the answer on this question:
CGFloat-based math functions?
I just need to #include <tgmath.h> to solve this problem and probably change fabsf to fabs. I have at least one file where this doesn't seem to be helping. I still get the warning: implicit conversion loses floating-point precision 'double' to 'CGFloat' aka (float). Here's the line that generates that warning:
CGFloat deltaX = fabs(item.center.x-point.x);
Has anyone else run across this? How did you solve it? I'd rather not disable this warning or litter my code with a ton of typecasts.
I guess, you are using CGPoint types, so the conversion doesn't occur within fabs(DOUBLE -> FLOAT), but on assignment CGFloat = DOUBLE. That's probably because compiler used fabs from math.h which operates on doubles.
Problem with math.h is that it's internally imported by OSX headers (carbon if I remember correctly), so I guess some iOS header might also do that. After quick look, it seems that basic set of frameworks doesn't import math.h, so probably you should look for it being manually imported. In case it's imported internally by some system libs, you'll probably won't be able to use those libs and tgmath in a single implementation file.
If you want to check if there are some math.h dependencies, you can use a dirty trick to prevent it's inclusion - add this line to a file (or better on top of prefix file):
#define __MATH_H__
I was able to get the tgmath.h functions to work by including the header at the top of my PCH file.
At some point (read: Xcode update) I had to start disabling Modules to get this to work. The details of such are in the question Dima links to below.

Path Parameter in UIImage imageWithContentsOfFile: for XCAsset

Is there any way to retrieve a UIImage object with imageWithContentsOfFile: if the image is stored in an xcasset Bundle (Xcode 5 Image Catalog)?
It's easy to access it with the imageNamed: method, but imageWithContentsOfFile: has a slightly different behavior, so what do I pass in the path parameter?
I've tried to use a variety of formats, but they all return a nil value:
ImageName#2x.png
ImageName#2x
ImageName
NSBundle File Path to Image
Apple's documentation doesn't specify a format for this. Any ideas?
You can't load an image from xcasset via imageWithContentsOfFile:, because every entry in xcasset is compiled into a single binary file Assets.car. The format of this file is not documented and yet not reverse-engeneered well afaik (see "What you should know if you want to try reverse-engineering this stuff." section for explanations).
This is done for performance and low memory consume reasons, that's why imageNamed: is a good solution.

imageNamed and localization issue

I've localized my images via Xcode, and all the images are in the proper lproj folder.
However, when I use imageNamed I don't get the correct image, but I keep getting the default image even if I change language.
_myImageView.image = [UIImage imageNamed:#"image_name"];
This kind of issue made me waste some time, but then I realized it was a false issue and I hope to save you precious time.
If you switch language and the images are not in the new language, that's because of cached images. The documentation is straightforward:
This method looks in the system caches for an image object with the specified name and returns that object if it exists
Hence, when you switch language, and you ask for the same name to the cache, you'll get the old image! That's it. :)
Instead of:
_myImageView.image = [UIImage imageNamed:#"image_name"];
use:
NSString *imageName = NSLocalizedString(#"image_name", #"image_name");
_myImageView.image = [UIImage imageNamed:imageName];
and localize your image names using the Localizable.strings files like any other resource in your project.

Resources