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]);
Related
I use weakify/strongify macros and I want to move next logic to the macros.
#weakify(self);
BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){
#strongify(self);
if (self == nil) return; // I want to move it to the macros
strongify definition:
#define strongify(...) \
rac_keywordify \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
_Pragma("clang diagnostic pop")
Any suggestions?
I have spent some time to figure it out...
#define myStrongify(first, ...) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
if (!first) { NS_VALUERETURN(NO, BOOL); } \
_Pragma("clang diagnostic pop")
The usage would be like:
BOOL (^matchesFooOrBar)(id) = ^BOOL(id obj) {
NSLog(#"before");
myStrongify(obj);
NSLog(#"after");
// your custom logic here
...
return YES;
};
FYI, NS_VALUERETURN from apple documentation. Please feel free to test it.
This code isn't working due to Error that I couldn't get which is :
Expected ‘)’
type specifier missing default to ‘int’
Expected parameter declaration
conflicting types or ’NSLog'
this error only appear in line 4
please help thanks,
#import <Foundation/Foundation.h>
#define SYS
#ifdef SYS
NSLog (#"SYS is Define ");
#endif
#define minimum(x,y) (x < y ? x:y)
#define Lower_case(x) ((x>'a') && (x<'z'))
#define ToUper_case(x) ((x-'a')+'A')
#define Uper_case(x) (Lower_case(x) ? (x-'a')+'A':x)
#interface NewDef : NSObject
#end
You have a code statement:
NSLog (#"SYS is Define ");
which is not inside any method/function. This is not allowed in (Objective-)C(++).
You can probably achieve what you wish using:
#pragma message "SYS is Define "
This is a compile-time instruction, just as #define is, to the compiler to (somehow) present a message. In Xcode if this line is reached it will be marked with a warning icon:
If you comment out the #define SYS then the mark will go away as the line is no longer reached:
HTH
Is it possible to use some thing like this in Objective-C:
#define number_of_items 10
and then using it as:
int arr[number_of_items];
Yes, assuming you mean Objective C. It's pretty much a superset of "proper" C so this is perfectly okay. It's also okay in both C and C++.
You can see that it works in the following transcript:
pax> cat qq.m
#import <objc/Object.h>
// First method.
#define number_of_items 10
int arr[number_of_items];
// Second method.
#define NUMBER_OF_ROWS 10
#interface test : Object{ int xyzzy[NUMBER_OF_ROWS]; }
#end;
pax> vi qq.m ; gcc -o qq.o -c qq.m -lobjc
pax> # no errors occurred
And, now that we've finally seen what you're actually using:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define NUMBER_OF_ROWS_ (IS_IPAD? 18: 18)
NUMBER_OF_ROWS_ is not a constant, since it depends on the return value of the function UI_USER_INTERFACE_IDIOM().
In other words, it cannot be calculated at compile time. That's why you're getting the error. You can see this by compiling the following code:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define NUMBER_OF_ROWS_ (IS_IPAD ? 18: 20)
int UI_USER_INTERFACE_IDIOM(void) {return 20;}
int UIUserInterfaceIdiomPad;
int main (void) {
int arr[NUMBER_OF_ROWS_];
return 0;
}
Under gcc --pedantic, you get:
qq.m: In function ‘main’:
qq.m:8: warning: ISO C90 forbids variable length array ‘arr’
You either need to use a dynamically adjustable collection like NSMutableArray or use an array of the maximum size desired and only use what you need of that.
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
Update: I'm working with the GNU-runtime on Linux. The problem does not occur on MacOS with the Apple-runtime.
Update 2: I compiled the GNU-runtime on MacOS and build the example with it. The error does not occur on MacOS with the GNU-runtime. I would say the problem is the glibc (since backtrace and backtrace_symbols are glibc extensions).
When printing a backtrace in a GCC compiled Objective-C app using backtraceand backtrace_symbols, I don't get any Objective-C symbols. Only the filenames, addresses and C-symbols appear.
I compiled with -g and linked with -rdynamic.
My test app:
void _printTrace()
{
void *addr[1024];
int aCount = backtrace(addr, 1024);
char **frameStrings = backtrace_symbols(addr, aCount);
for (int i = 0; i < aCount; i++) {
printf("%s\n", frameStrings[i]);
}
free(frameStrings);
}
#interface TheObject
+ (void)_printTrace;
+ (void)printTrace;
#end
#implementation TheObject
+ (void)_printTrace
{
_printTrace();
}
+ (void)printTrace
{
[self _printTrace];
}
#end
void printTrace()
{
[TheObject printTrace];
}
int main(int argc, char **argv)
{
printTrace();
return 0;
}
and it's output:
./test.bin(_printTrace+0x1f) [0x8048e05]
./test.bin() [0x8048e60]
./test.bin() [0x8048e8b]
./test.bin(printTrace+0x34) [0x8048ec5]
./test.bin(main+0xf) [0x8048eda]
/lib/libc.so.6(__libc_start_main+0xe5) [0xb7643bb5]
./test.bin() [0x8048b51]
Is there a way to let the Objective-C symbols appear in this backtrace?
dladdr() only reports global and weak symbols. But all Objective-C function symbols are local:
$ readelf -s so_backtrace
Symbol table '.dynsym' contains 29 entries:
…
Symbol table '.symtab' contains 121 entries:
Num: Value Size Type Bind Vis Ndx Name
…
49: 08048a01 13 FUNC LOCAL DEFAULT 14 _c_TheObject___printTrace
50: 08048a0e 47 FUNC LOCAL DEFAULT 14 _c_TheObject__printTrace
…
You can verify that local symbols are never returned by looking at the GNU libc source code yourself. backtrace_symbols() is defined in sysdeps/generic/elf/backtracesyms.c. It relies on _dl_addr(), which is defined in elf/dl-addr.c, to provide it with the symbol names. That ultimately calls determine_info(). If it can, it uses the the GNU hash table, which does not include local symbols by design:
49 /* We look at all symbol table entries referenced by the hash
50 table. */
…
60 /* The hash table never references local symbols so
61 we can omit that test here. */
If the GNU hash table isn't present, it falls back to standard hash table. This includes all the symbols, but the determine_info() code filters out all but the global symbols and weak symbols:
90 if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
91 || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
To symbolicate the Objective-C function addresses, you would have to perform the look-up yourself and not filter out the local function symbols. Further, you would have to demangle the Objective-C function symbols to restore _c_TheObject___printTrace to +[TheObject _printTrace].
GNUstep's NSException implementation doesn't use backtrace, instead it uses libbfd (binary file descriptor). I think the function that actually does the work is called static void find_address, which you can view here. Using this trivial example, I get the results that follow.
#include <Foundation/Foundation.h>
#interface Test : NSObject {}
+ (void) test;
#end
#implementation Test
+ (void) test
{
Class GSStackTrace = objc_getClass("GSStackTrace");
id stack = [GSStackTrace currentStack];
for (int i = 0; i < [stack frameCount]; i++)
{
NSLog (#"%#", [[stack frameAt:i] function]);
}
}
#end
int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[Test test];
[pool release];
return 0;
}
Output (when compiled with debug symbols):
2010-10-18 14:14:46.188 a.out[29091] +[GSStackTrace currentStack]
2010-10-18 14:14:46.190 a.out[29091] +[Test test]
2010-10-18 14:14:46.190 a.out[29091] main
2010-10-18 14:14:46.190 a.out[29091] __libc_start_main
You may be able to pick apart GSStackTrace. It is a “private” class (that's why I need to use objc_getClass, you'll also get lots of unrecognised selector warnings), but it seems to contain all the code necessary to read Objective-C class names.
Tested on Ubuntu 9.04 with GNUstep configured with --enable-debug (so that GSFunctionInfo is included in the build).
I expect you'll need to ask the ObjC run time about the addresses to get symbol information. The addresses returned from backtrace() could probably be passed to something like object_getClass() to get the class, for example. I haven't tried any of this but it's where I'd look next in this case.