#define macros and xcode warning and lack of code hinting - objective-c

I wrote up some small macros to help in setting application-wide font styles, colors and gradients. The issue is that xcode is throwing warnings whenever I use the color or font defined in the macro. Is there any way to get xcode to validate the macro, and hopefully get code hinting as well?
#define HEX_COLOR(colorname, hexcolor) \
\
#implementation UIColor(Style##colorname) \
\
+ (UIColor*) colorname \
{ \
static UIColor * staticColor = nil; \
if(! staticColor) { \
float red = ((hexcolor & 0xFF0000) >> 16)/255.0; \
float green = ((hexcolor & 0xFF00) >> 8)/255.0; \
float blue = (hexcolor & 0xFF)/255.0; \
float alpha = (hexcolor >> 24)/255.0; \
\
staticColor = [[UIColor colorWithRed:red \
green:green \
blue:blue \
alpha:alpha] retain]; \
} \
return staticColor; \
} \
#end
In my app delegate i set the application-wide fonts and colors like this:
HEX_COLOR(specialGreenColor, 0x66BAD455);
.....
This line throws the warning that the property might not exist.
[[UIColor specialGreenColor] set];
Also I do not want to lessen the error reporting in xcode as not seeing warning is a backwards step. I just would like to find a way to regiester the marco with xcode.

If you want to define constants, you should use #define like so:
#define COLOUR_NAME 0x66BAD455
Then, the preprocessor will go through your file and replace all instances of COLOUR_NAME verbatim with 0x66BAD455.
There are arguably better ways to define application-wide constants though.
Edit: there's also this nice post which seems to provide a better implementation of what you're going for. You can define the macro and then define your colour constants using the question linked above.

Code hinting for the marco works in xCode 4.2

Related

'VA_ARGS', an invalid preprocessing token in macros Obj-C

I use following technique to manage my logs. I print logs to asl_log and before, regards to flag [DebugManager shared] isDebugging I want to send log line to other class (method addLogEvent)
#if !defined(TheLog)
#define TheLog(fmt, ...) { \
if ([[DebugManager shared] isDebugging]) \
addLogEvent(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__); \
}
#endif
#define __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) \
inline void NAME(NSString *format, ...)\
{ \
TheLog(__PRETTY_FUNCTION__,format,##__VA_ARGS__);\
va_list arg_list; \
va_start(arg_list, format); \
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list]; \
asl_add_log_file(NULL, STDERR_FILENO); \
asl_log(NULL, NULL, (LEVEL), "PREFIX: %s", [formattedString UTF8String]); \
va_end(arg_list); \
}
// Something has failed.
__AF_MAKE_LOG_FUNCTION(ASL_LEVEL_ERR, AFLogError)
// Something is amiss and might fail if not corrected.
__AF_MAKE_LOG_FUNCTION(ASL_LEVEL_WARNING, AFLogWarning)
// The lowest priority for user log
__AF_MAKE_LOG_FUNCTION(ASL_LEVEL_INFO, AFLogDebug)
I map log level with __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) and I need to call TheLog(__PRETTY_FUNCTION__,format,##__VA_ARGS__);\ from inline void NAME(NSString *format, ...)
I get an error:
Pasting formed ',__VA_ARGS__', an invalid preprocessing token
How can I fetch ,__VA_ARGS__ and __PRETTY_FUNCTION__?
This line:
TheLog(__PRETTY_FUNCTION__,format,##__VA_ARGS__);\
is part of the definition of this macro:
#define __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) \
Note that that macro does not take a variable argument list. Therefore, there's no __VA_ARGS__ defined within its definition.
The fact that the function being defined by an instantiation of __AF_MAKE_LOG_FUNCTION — the inline void NAME() — takes a variable argument list isn't relevant. If that function wants to pass the variable argument list along to another function, it needs to do it using the stdarg functionality, as it does for -[NSString initWithFormat:arguments:], but that doesn't work for your TheLog macro, because it's not designed to accept a va_list.
You can't do what you're attempting. Your TheLog macro is incompatible with how you're trying to use it. You would need to design an alternative version, such as:
#define TheLogv(fmt, args) { \
if ([[DebugManager shared] isDebugging]) \
addLogEventv(__PRETTY_FUNCTION__,fmt,args); \
}
Note that this would, in turn, require the existence of a function addLogEventv() which accepts a va_list instead of an actual variable argument list. Within the body of the function being defined by __AF_MAKE_LOG_FUNCTION, you'd have to start and end the list twice, once around each time you pass it to another function, because each function will "consume" it:
#define __AF_MAKE_LOG_FUNCTION(LEVEL, NAME) \
inline void NAME(NSString *format, ...)\
{ \
va_list arg_list; \
va_start(arg_list, format); \
TheLogv(__PRETTY_FUNCTION__,format,arg_list);\
va_end(arg_list); \
va_start(arg_list, format); \
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list]; \
asl_add_log_file(NULL, STDERR_FILENO); \
asl_log(NULL, NULL, (LEVEL), "PREFIX: %s", [formattedString UTF8String]); \
va_end(arg_list); \
}
You could also change your TheLog() macro to take an NSString* and simply pass in the formattedString that's already being created.

Making a function globally available in Objective-C

In previous project I had this function defined in AppDeligate.m and it was globally available to all the parts of the app:
#define UIColorFromRGB(rgbValue) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
Now for some reason when I place this code in a new project, only the specific class can see the function, but the child classes do not see it.
How do I make this function globally available?
You can define your macro in the .pch file of your project, but it's generally a bad idea, since it will produce code which is difficult to read, maintain and debug.
In your specific case I'd rather create a category on UIColor.
Here's a implementation with extra stuff which may come in handy.
UIColor+Extra.h
#import <UIKit/UIKit.h>
#interface UIColor (Extra)
+ (instancetype)extra_colorWith255BasedRed:(NSUInteger)red green:(NSUInteger)green blue:(NSUInteger)blue;
+ (instancetype)extra_colorWith255BasedRed:(NSUInteger)red green:(NSUInteger)green blue:(NSUInteger)blue alpha:(CGFloat)alpha;
+ (instancetype)extra_colorWithHex:(NSInteger)hex;
#end
UIColor+Extra.m
#import "UIColor+Extra.h"
#implementation UIColor (Extra)
+ (instancetype)extra_colorWith255BasedRed:(NSUInteger)red green:(NSUInteger)green blue:(NSUInteger)blue {
return [self colorWith255BasedRed:red green:green blue:blue alpha:1.0];
}
+ (instancetype)extra_colorWith255BasedRed:(NSUInteger)red green:(NSUInteger)green blue:(NSUInteger)blue alpha:(CGFloat)alpha {
return [self colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha];
}
+ (instancetype)extra_colorWithHex:(NSInteger)hex {
return [UIColor colorWith255BasedRed:((hex & 0xFF0000) >> 16) green:((hex & 0xFF00) >> 8) blue:(hex & 0xFF)];
}
#end
Then just place
#import "UIColor+Extra.h"
in your .pch file and use it elsewhere.
Examples
UIColor * cyan = [UIColor extra_colorWithHex:0x00FFFF];
UIColor * magenta = [UIColor extra_colorWith255BasedRed:255 green:0 blue:255];
If you add the file to YOURPROJECTNAME-Prefix.pch, it will be added as a precompiled header, and available in all your code-files.
Audun Kjelstrup has the best answer.
You also have the option to setup a static method inside a class.
+ (UIColor *)UIColorFromRGB {}
I agree with Gabriele about macros (undesirable as functions) and that what you are trying to do would be nice/appropriate in a category. However, I also want to point out that Objective-C can also do C-style functions (as opposed to the macro that you have shown).
For example:
// Header
UIColor * UIColorFromRGB(NSInteger rgbValue);
// Implementation
UIColor * UIColorFromRGB(NSInteger rgbValue)
{
return [UIColor colorWithRed: ((float)((rgbValue & 0xFF0000) >> 16))/255.0
green: ((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue: ((float)(rgbValue & 0xFF))/255.0 alpha:1.0];
}

performSelector ARC warning [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
performSelector may cause a leak because its selector is unknown
I have this code in non-ARC that works without errors or warnings:
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
{
// Only care about value changed controlEvent
_target = target;
_action = action;
}
- (void)setValue:(float)value
{
if (value > _maximumValue)
{
value = _maximumValue;
} else if (value < _minimumValue){
value = _minimumValue;
}
// Check range
if (value <= _maximumValue & value >= _minimumValue)
{
_value = value;
// Rotate knob to proper angle
rotation = [self calculateAngleForValue:_value];
// Rotate image
thumbImageView.transform = CGAffineTransformMakeRotation(rotation);
}
if (continuous)
{
[_target performSelector:_action withObject:self]; //warning here
}
}
However, after I convert to project to ARC, I get this warning:
"Perform Selector may cause a leak because its selector is unknown."
I would appreciate ideas on how to revise my code accordingly..
The only way I've found to avoid the warning is to suppress it. You could disable it in your build settings, but I prefer to just use pragmas to disable it where I know it's spurious.
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_target performSelector:_action withObject:self];
# pragma clang diagnostic pop
If you're getting the error in several places, you can define a macro to make it easier to suppress the warning:
#define SuppressPerformSelectorLeakWarning(Stuff) \
do { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
Stuff; \
_Pragma("clang diagnostic pop") \
} while (0)
You can use the macro like this:
SuppressPerformSelectorLeakWarning([_target performSelector:_action withObject:self]);

does anyone know how to use colorcodes instead of just assigning colors with UIColor

Like the title says I want to use a color code instead of doing something like this
lblTemp.textColor = [UIColor colorWithRed: 0 green:0x99/255.0 blue:0 alpha:1.0];
for instance I have the following colorcode #30ae36 how can I use this one instead of doing the above.
I use this handy macro:
#define UIColorFromRGB(rgbValue) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
(I might have gotten it from here, but you can find it in many places. In any case it's worth reading the discussion about macros vs inline functions at this link.)
If you want to initialize the color from a string (for example from a plist), you can use this:
unsigned rgbValues;
[[NSScanner scannerWithString:#"0xFF0000"] scanHexInt: &rgbValues];
UIColor* redColor = UIColorFromRGB(rgbValues);
UIColor doesn't offer a default method for that, but, you could create a so called category for UIColor which takes the hex value (sans the #) and turns it in to the corresponding RGB components and uses those components to feed to UIColor's colorWithRed:green:blue:alpha:.
this should do the trick for this code #30ae36
lblTemp4.textColor = [UIColor colorWithRed:0x*30*/255.0 green:0x*AE*/255.0 blue:0x*36*/255.0 alpha:1.0];
In the previous answer, from jovany the * * stars should be omitted. So #30ae36 becomes:
lblTemp4.textColor = [UIColor colorWithRed:0x30/255.0 green:0xAE/255.0 blue:0x36/255.0 alpha:1.0];
(Maybe obvious, but I didn´t get it at first sight)

Is Macro Better Than UIColor for Setting RGB Color?

I have this macro in my header file:
#define UIColorFromRGB(rgbValue) \
[UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 \
alpha:1.0]
And I am using this as something like this in my .m file:
cell.textColor = UIColorFromRGB(0x663333);
So I want to ask everyone is this better or should I use this approach:
cell.textColor = [UIColor colorWithRed:66/255.0
green:33/255.0
blue:33/255.0
alpha:1.0];
Which one is the better approach?
or create a separate category, so you only need to import one .h file:
#interface UIColor (util)
+ (UIColor *) colorWithHexString:(NSString *)hex;
+ (UIColor *) colorWithHexValue: (NSInteger) hex;
#end
and
#import "UIColor-util.h"
#implementation UIColor (util)
// Create a color using a string with a webcolor
// ex. [UIColor colorWithHexString:#"#03047F"]
+ (UIColor *) colorWithHexString:(NSString *)hexstr {
NSScanner *scanner;
unsigned int rgbval;
scanner = [NSScanner scannerWithString: hexstr];
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:#"#"]];
[scanner scanHexInt: &rgbval];
return [UIColor colorWithHexValue: rgbval];
}
// Create a color using a hex RGB value
// ex. [UIColor colorWithHexValue: 0x03047F]
+ (UIColor *) colorWithHexValue: (NSInteger) rgbValue {
return [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0
green:((float)((rgbValue & 0xFF00) >> 8))/255.0
blue:((float)(rgbValue & 0xFF))/255.0
alpha:1.0];
}
#end
How about creating your own:
#define RGB(r, g, b) \
[UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
#define RGBA(r, g, b, a) \
[UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)]
Then use it:
cell.textColor = RGB(0x66, 0x33, 0x33);
Seems simple enough to use, uses hex values for colors and without needing additional calculation overhead.
A middle ground might be your best option. You could define either a regular C or objective-C function to do what your macro is doing now:
// As a C function:
UIColor* UIColorFromRGB(NSInteger rgbValue) {
return [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0
green:((float)((rgbValue & 0xFF00) >> 8))/255.0
blue:((float)(rgbValue & 0xFF))/255.0
alpha:1.0];
}
// As an Objective-C function:
- (UIColor *)UIColorFromRGB:(NSInteger)rgbValue {
return [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0
green:((float)((rgbValue & 0xFF00) >> 8))/255.0
blue:((float)(rgbValue & 0xFF))/255.0
alpha:1.0];
}
If you decide to stick with the macro, though, you should put parentheses around rgbValue wherever it appears. If I decide to call your macro with:
UIColorFromRGB(0xFF0000 + 0x00CC00 + 0x000099);
you may run into trouble.
The last bit of code is certainly the most readable, but probably the least portable - you can't call it simply from anywhere in your program.
All in all, I'd suggest refactoring your macro into a function and leaving it at that.
I typically recommend functions rather than complex #defines. If inlining has a real benefit, the compiler will generally do it for you. #defines make debugging difficult, particularly when they're complex (and this one is).
But there's nothing wrong with using a function here. The only nitpick I'd say is that you should be using CGFloat rather than float, but there's nothing wrong with the hex notation if it's more comfortable for you. If you have a lot of these, I can see where using Web color notation may be convenient. But avoid macros.
I.m.h.o the UIcolor method is more readable. I think macro's are great if they solve a problem; i.e. provide more performance and/or readable code.
It is not clear to me what the advantage of using a macro is in this case, so I'd prefer the second option.
Keep in mind that 33 != 0x33. The first is decimal notation and the second is hexadecimal. They're both valid, but they are different. Your second option should read
cell.textColor = [UIColor colorWithRed:0x66/255.0
green:0x33/255.0
blue:0x33/255.0
alpha:1.0];
or
cell.textColor = [UIColor colorWithRed:102/255.0
green:51/255.0
blue:51/255.0
alpha:1.0];
Nice Marius, but to compile I had to get rid of the parenthesis, as follows (otherwise, Objective C takes it literally and you get a syntax compilation error:
#define RGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0]
...
NSArray *palette;
...
palette = [NSArray arrayWithObjects:
RGB(0,0,0),
RGB(255,0,0), // red
...