I have a method , which takes the following argument.
void callAMethood(const void *iVar){}
now here i am not clear on how should i pointer
the following seems to be quite simple,where i just pass the address instead of value.
NSString *a=#"Hi";
callAMethood(&a);
But, the following seems to work well, but understanding the syntax is difficult.
char const * const a="HI";
callAMethood(&a);
or even this works callAMethood(a);
As xlc points out, both are wrong.
NSString *a=#"Hi";
callAMethood(&a); // This passes a NSString **
char const * const a="HI";
callAMethood(&a); // This passes a char const * const *
Both work, because a pointer to a pointer can stil be cast to a void *.
It is incredibly unlikely that you intended either, though.
Take advantage of C being type-checked at compile time and be more specific with your types.
void awesome_function(NSString *amazingString);
NSString *yay = #"oh my god yes";
awesome_function(yay); // ok
awesome_function(&yay); // compiler error
In short: unless you have a very good reason for using a void * (which I would consider unlikely for a Cocoa(Touch) app), don't.
If you don't want compile-time type checking, use something like Python. If you want to be able to handle different Objective C object types, that's what id is for.
You ask what you should pass to the function (it is not the declaration of a method):
void callAMethood(const void *iVar) {...}
The answer is nobody can tell you!
Your function takes a value of type void * - this type is typically used in C to mean a "pointer to anything". It is not a type that would be used for a function that took a pointer to any object, that would be id.
But that doesn't get us very far, as we've no idea what callAMethood is expecting we've no idea what to pass it - we cannot tell you the answer.
Now you give the example:
NSString *a = #"Hi";
callAMethood(&a);
That is a valid call, it passes a pointer to the variable a. However:
callAMethood(a);
is also a valid call, it passes the pointer which is stored in the variable a. Without any knowledge of what callAMethood is expecting we cannot tell you which is the correct call. The same applies to your second example.
HTH
Every pointer can be converted to void * implicitly.
EDIT:
As Kevin said, only data pointer.
As CRD said,
The answer is nobody can tell you!
without the information of the function of callAMethood. All of those invoking are valid grammatically(can be compiled), howerver, invalid semantically usually unless callAMethood really doesn't care about which type iVar(e.g. it just prints the pointer).
What people said above is correct but you can also use UTF8String to get a const char * from a NSString
const char * myStr = [a UTF8string];
callMehtod(myStr);
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html
Related
I wrote the following code in X-Code,
NSString *myString = #"testString";
NSLog(#"*myString = %#", *myString);
and I got the following error,
Cannot pass object with interface type 'NSString' by value to variadic function; expected type from format string was 'id'
can someone tell me what does it mean? What does "*myString" stand for?
As we know, if we write the code like below, there is no error,
char testchar = 'f';
char *char1 = &testchar;
NSLog(#"*char1 = %c",*char1);
Why NSString cannot write like this case?
#Avi,Thanks for your explanation, originally, what I want to ask is I saw the below declaration and definition:
NSString const *BNRNextItemValuePrefsKey1 = #"NextItemValue";
From my understanding BNRNextItemValuePrefsKey1 a pointer to a constant #"NextItemValue"
but when I do the following, there is no error,
BNRNextItemValuePrefsKey1 = #"jijijij";
why this happen,can you explain it?
The syntax *myString is dereferencing the pointer myString. It tells the compiler to pass the value contained at the memory location pointed to by the pointer, instead of passing the value of the pointer itself. The reason that example gives you an error is because Objective-C does not allow passing of objects by value. You are only allowed to pass pointers to objects. The reference to id in the error message is pointing out that the %# format string is used to print objects. Exactly what gets printed for any object depends on the implementation of - description for that object's type.
Your second example with the pointer to a char works because Objective-C has no issues with passing the value of a char.
question edit
In that statement the const attribute refers to the value being pointed to, not the value of the pointer. In terms of implementation, it doesn't really mean much, as that string will not be changeable anyway. I believe it allows for compiler optimizations.
In my iOS/Objective C projects, I often have a constants.h file with my API keys and such. Until today, I've been declaring my constants as static const like so:
static NSString * const kAPIKey = #"wembvkejrvb43789gvbiu2bvfake";
This works fine, but with the unfortunate downside that I can only create constants for primitives and NSString literals, essentially. Other objects, such as UIColor objects, cannot be stored in this constant as they cannot be initialized with a static literal syntax (my understanding, citation required).
After reading some C++ docs, I understand a few things:
The static is unnecessary, as const are implicitly static.
Calling NSString * const x is actually declaring a constant and immutable value in x. I cannot change the value, but may be able to change what x points to.
This const has internal linkage, meaning the the value is defined right away (presumable at compile time).
Are these conclusions correct?
How does an extern const differ? I assume they are externally linked (thus the extern keyword). Are they defined at run time? Can I create some sort of dynamic extern const that can be set with a value returned by a class method?
For example, I would like to create a globally-scoped constant that contains a UIColor value. I would like to construct this color value using the [UIColor colorWithRed:green:blue:alpha:] class method. This clearly doesn't work with the internally linked constants I've been using (I'm assuming because it happens at compile-time) - but is it possible using an external constant, possibly set up in the +initialize method?
Any elaboration on the details of this behavior would be immensely helpful.
The static is unnecessary, as const are implicitly static.
No, that's not true.
static when used at file scope (i.e. outside any method or function) means that the variable is visible only within that file.
extern means that the variable is defined in some other file.
const means that the variable cannot be modified.
Consider strings. Often, you'll have an implementation file (name ends in .m) that defines some constant string pointer:
NSString *const SomeString = #"some string";
You might want to use that same constant from other files. If so, you could add a declaration to the header (name ends in .h) file that explains to the compiler that the variable is defined elsewhere:
extern NSString *const SomeString;
and that would let you use SomeString in any file that imports the header file. On the other hand, you might decide that you definitely do not want the constant used outside the implementation file. In that case, you could declare it static (in the implementation file again):
static NSString *const SomeString = #"some string";
and that would prevent its use from outside the file.
Calling NSString * const x is actually declaring a constant and immutable value in x. I cannot change the value, but may be able to change what x points to.
Right, it declares the pointer x to be constant -- you can't change it. You also can't change the value that it points to if it's actually a NSString because an instance NSString isn't mutable.
This const has internal linkage, meaning the the value is defined right away (presumable at compile time).
I'll take the 5th on that -- I'm not sure exactly how the compiler deals with constant strings. I think it's safe to use that as a mental model, though; the string will in any case be defined before your code ever gets to use it.
On your specific programming question, how to create a compile-time defined color object: you can't, because, apart from the handful for which the language supplies literal syntax, objects are created at runtime.
But you can still do it elegantly at runtime, without any addition to global scope, the same way the sdk does...
#interface UIColor (RainbowAddition)
+ (UIColor *)chartruseColor;
#end
#implementation UIColor (RainbowAddition)
+ (UIColor *)chartruseColor {
// bonus: this is really chartruse... according to the internet
return [self colorWithRed:0.5 green:1.0 blue:0.0 alpha:1.0];
}
#end
http://cloford.com/resources/colours/500col.htm
Objective-C is a pure extension of C, C++ is not.
At global scope:
in C (and Objective-C) writing const is equivalent to extern const (external linkage);
in C++ writing const is equivalent to static const (internal linkage).
Both in C (and Objective-C) and C++, to create a global-scoped const you can define it, just one time, in one source file like extern const TYPE identifier = VALUE; and declare it (typically in an header file) like: extern const TYPE identifier; (read it: I defined this const elsewhere at global linkage level).
Struggling with this one. Hoping it's possible and I don't sound silly.
I'm hacking forwardInvocation in a class I'm writing. What I want to do is forward the invocation to one selector or another depending on if it is an object or primitive type. The end goal is I want to "box" the primitives so they can be added to arrays/dictionaries. For simplicity, the two types of values that typically come through here are NSStrings and enums.
In short, given a pointer, is there a way to tell if it is an object?
__unsafe_unretained id argument;
[anInvocation getArgument:&argument atIndex:2];
// EXC_BAD_ACCESS if primitive (i.e. NSInteger value of 2 ($1 = 0x00000002) )
if (![argument isKindOfClass:[NSObject class]]) {
// Box the value
...
}
Is there a test I can run? Right now my code is hackishly doing this nasty trick:
// All my enums have at most 10 elements. I'm so bad at code.
if ((NSInteger)argument < 10) {
// Box the value
...
}
Thanks in advance.
You can get the type from the method signature:
NSMethodSignature *signature = [invocation methodSignature];
const char* argType = [signature getArgumentTypeAtIndex:2];
The types are listed under Type Encodings in the Objective-C Runtime Guide
You should also make sure you know the type before calling getArgument:atIndex::
This method copies the argument stored at index into the storage pointed to by buffer. The size of buffer must be large enough to accommodate the argument value.
__unsafe_unretained id argument;
[anInvocation getArgument:&argument atIndex:2];
This will write past argument on the stack if the size of the actual argument is greater than sizeof(id)
Pointers in C are just values that represent addresses. The thing at the address pointed to by a void pointer is explicitly untyped. If the goal is to have a method that can take any type — object pointer, scalar or composite — that just isn't going to work. And besides the impossibility of recovering a type from a void pointer, if you're literally trying to pass in a scalar directly instead of passing in its address, that is doubly impossible because the compiler needs to know right type of the value in order to emit the correct code, and most types cannot be converted to a pointer with any fidelity. Either way, Objective-C's type system is just not powerful enough to do what you want.
Hi this is third day of mine using Objective-C today I was writing few simple programs and i ecncountered the following warning
main.m:19:5: warning: passing argument 1 of 'NSLog' makes pointer from integer without a cast [enabled by default]
NSLog(res);
which finally resulted in the Segmentation fault.. Here is my program..
#import <Foundation/Foundation.h>
#interface SomeClass: NSObject
{
int x;
}
#property int x;
#end
#implementation SomeClass
#synthesize x;
#end
int main(){
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
SomeClass * obj = [[SomeClass alloc]init];
obj.x =20;
int res = obj.x;
NSLog(res); //error
/* But the error was not seen when I replaced the above statement with
NSLog(#"The value is : %d",res);
*/
[pool drain];
return 0;
}
The error message that I got was :
Compiling the source code....
$gcc `gnustep-config --objc-flags` -L/usr/GNUstep/System/Library/Libraries -lgnustep-base main.m -o demo -lm -pthread -lgmpxx -lreadline 2>&1
main.m: In function 'main':
main.m:19:5: warning: passing argument 1 of 'NSLog' makes pointer from integer without a cast [enabled by default]
NSLog(res);
^
In file included from /usr/GNUstep/System/Library/Headers/Foundation/NSObject.h:30:0,
from /usr/GNUstep/System/Library/Headers/Foundation/FoundationErrors.h:29,
from /usr/GNUstep/System/Library/Headers/Foundation/Foundation.h:33,
from main.m:1:
/usr/GNUstep/System/Library/Headers/Foundation/NSObjCRuntime.h:146:16: note: expected 'struct NSString *' but argument is of type 'int'
GS_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
^
Executing the program....
$demo
Segmentation fault (core dumped)
Please help by making me understand why NSLog behaves like this ? Where did I go wrong?
Thank you...
You can't use the NSLog like this, You need to specify the control string and use like:
NSLog(#"%d",res);
The format should be specified for NSLog(), please check the NSLog and NSLogv reference for more information
NSLog
Logs an error message to the Apple System Log facility.
void NSLog ( NSString *format, ... );
Discussion
Simply calls NSLogv, passing it a variable number of arguments.
Availability
NSLogv
Logs an error message to the Apple System Log facility.
void NSLogv ( NSString *format, va_list args );
Discussion
Logs an error message to the Apple System Log facility (see man 3
asl). If the STDERR_FILENO file descriptor has been redirected away
from the default or is going to a tty, it will also be written there.
If you want to direct output elsewhere, you need to use a custom
logging facility.
The message consists of a timestamp and the process ID prefixed to the
string you pass in. You compose this string with a format string,
format, and one or more arguments to be inserted into the string. The
format specification allowed by these functions is that which is
understood by NSString’s formatting capabilities (which is not
necessarily the set of format escapes and flags understood by printf).
The supported format specifiers are described in “String Format
Specifiers”. A final hard return is added to the error message if one
is not present in the format.
In general, you should use the NSLog function instead of calling this
function directly. If you do use this function directly, you must have
prepared the variable argument list in the args argument by calling
the standard C macro va_start. Upon completion, you must similarly
call the standard C macro va_end for this list.
Output from NSLogv is serialized, in that only one thread in a process
can be doing the writing/logging described above at a time. All
attempts at writing/logging a message complete before the next thread
can begin its attempts.
The effects of NSLogv are not serialized with subsystems other than
those discussed above (such as the standard I/O package) and do not
produce side effects on those subsystems (such as causing buffered
output to be flushed, which may be undesirable). Availability
You cant declare the NSLog like that see the tutorial for NSLog its may be useful for you.
Objective-C has a number of built-in data types:
int – integer constant
float – real numbers with fractional component
double – double precision floating point number
char – a single character
short – short integer (2 bytes)
long – double short
long long – double long
BOOL – boolean
The utility function NSLog() can be used to print to the debug console in Xcode. NSLog() uses the NSString formatting services. The easiest way to create a NSString is to use the #”" notation. Inside a format string a % is a placeholder for a value. The character after the % determines the value expected, be it an int or a float and so on. If we declare an integer “int i = 5″ and want to print the value of i with NSLog() we can do it with NSLog(#”The value of i is %d”, i);
You can use %d to print the value of an int, %f for a float and double, %c for a char. For a full listing of all format specifiers supported by NSString formatting methods read through the documentation.
For More Reference Click Here
keep learning..:)
The 1st argument to NSLog is an NSString that should be a string with 0 or more format specifiers.
Use:
NSLog(#"res = %d", res);
or just:
NSLog(#"%d", res);
Have a look at the reference docs for NSLog for details.
You should specify the compiler that what kind of data type you want to print in Log,
NSLog(#"%d",res);
You should not never use NSLog(variable) directly. Instead, use NSLog(#"%d", variable) for integers or NSLog(#"%#", object) for objects.
I have a library of my own. And there are lots of constants defined in headers (for example animation duration). But, all my headers are visible and changeable. How can I prevent others to change my default values?
There are some const value in headers of Apple libraries like this:
CA_EXTERN NSString * const kCATransitionMoveIn
__OSX_AVAILABLE_STARTING (__MAC_10_5, __IPHONE_2_0);
Objective-C is still, well, C. Maybe older systems had issues, which is why you see the macros there. Anyway, you should still be safe with any built-in type.
If you declare something as "extern" the compiler will treat it something like, "OK, I see that someone has declared and external thingy. I don't have to know what it is, because some external unit will define it. The linker will handle the rest.
That paragraph will get me in trouble with the C-police, but it's close enough for a practical explanation. Thus, you can do this in your header file...
extern int const TheAnswerToLifeTheUniverseAndEverything;
And then, in one of your implementation files (outside of the #implementation/#end section)...
int const TheAnswerToLifeTheUniverseAndEverything = 42;
Note, in "modern" Xcode versions, you can do the same thing with objects. Note the "const" which means we have a constant-pointer-to-NSString.
// In header
extern NSString * const TheAnswerToLifeTheUniverseAndEverythingString;
// In source
NSString * const TheAnswerToLifeTheUniverseAndEverythingString = #"42";