typedef After anonymus enum declaration - objective-c

I was looking at enums in cocoa frameworks and I saw this:
enum {
NSNetServiceNoAutoRename = 1UL << 0
};
typedef NSUInteger NSNetServiceOptions;
and my question is how is this possible?
How is NSNetServiceOptions tied to that enum?
And is it only possible in objective c or also in c?

NSNetServiceOptions tied to that enum in the context that the enum is going to hold an integer value anyway. In the above example you will create a variable for the enum as,
NSNetServiceOptions _netServiceOptions;
You can even ignore the typedef and directly use,
NSUIInteger _netServiceOptions;

enums in C (and consequently Obj-C and C++) are weakly typed, which means you can implicitly casts between enums and ints however you like as they are just ints.
For example, this is perfectly valid:
enum {A = 1};
enum {B = A+1};
const int C = A | B;
The reason the the enum uses a typedef instead of the shortform typedef enum {...} Name; is because enums defaults to being of type int. By using a typedef you can define the enum as being an unsigned integer instead.

Related

When should we use two-dimensional pointer in objective c

I want to know when should we use two-dimensional pointer in objective c. I read a article about the runtime mechanism. The implementation details of method objc_msgSend is as follows:
Any NSObject objective has a attribute of isa which will point to the corresponding Class object.
#interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
Class objective is as follows:
struct objc_class {
Class isa;
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists; // Method list of the class
Cache cache;
struct old_protocol_list *protocols;
}
The question I want to ask is that why methodLists is two-dimensional pointer, what if we use one-dimensional or do not use pointer, can sb explain this question to me?Thanks in advance.
The struct old_method_list is as below:
struct old_method_list {
void *obsolete;
int method_count;
/* variable length structure */
struct old_method method_list[1]; //The address of the first Method
};
OK, I read another article about why old_method_list use two-dimensional pointer, the reason is that, it may point to an array.My another question is that for struct old_method method_list[1], the comment is "The address of the first Method", but method_list is an old_method array which length is 1. How it can store address?
I solved this question by reading another article.
The array struct old_method method_list[1] is dynamic, it can be changed by adding elements(methods) to it.
Because it points at array of pointers at old_method_list.
Update for old_method_list.
old_method_list * can point not just at old_method_list. It also can point at for example:
struct old_method_list_with_10_methods
{
struct old_method_list list;
struct old_method method_list[9];
};
Or if you need dynamic size:
old_method_list* list = malloc(sizeof(old_method_list) + (n-1) * sizeof(old_method));
list->method_count = n;
It's such variable length structure.

Why there are 2 keywords when we define enum in c/objective-c

I define enum this way:
typedef enum sortByWhatUpperType{
//sortByRating=0,
sortbyDistance=1,
sortbyBuildingorProminent=0
} sortbyWhatBottomType;
Then I created a property
#property enum sortByWhatUpperType sortByWhat;
This is what autocomplete suggest me to make
-(void) setSortByWhat:(enum sortByWhatUpperType)sortByWhat
{
[[NSUserDefaults standardUserDefaults]setInteger:sortByWhat forKey:SortByWhat];
}
-(sortbyWhatBottomType) sortByWhat
{
return [[[NSUserDefaults standardUserDefaults] objectForKey:SortByWhat] unsignedIntValue];
}
So that enum seems to have 2 types. sortByWhatUpperType and sortbyWhatBottomType.
Why do we have 2 keywords? Why not just one? What am I missing? Which one is the true type?
Is enum sortByWhatUpperType are synonym with sortbyWhatBottomType?
Is there any insight?
This is the standard way of doing enum in objective-c right?
You've defined TWO types. An enum called sortByWhatUpperType, and an alias to is called sortbyWhatBottomType. The typedef enum statement has two parts to is - the enum and the typedef. You could've omitted the typedef and typed
enum sortByWhatUpperType{
//sortByRating=0,
sortbyDistance=1,
sortbyBuildingorProminent=0
};
But then whenever you want to declare a variable of that type, you'd need ty type enum. Aliasing lets you omit that.
The same syntax is true for structs. But only in C. In C++ you can omit enum/struct/class by default even without a typedef.

Objective-C: How to check if a variable is an object, a struct or another primitive

I want to write a function or a directive like NSLog() that takes any kind of variable, primitives and objects. In that function I want to distinguish those.
I know how it works for objects:
- (void)test:(id)object {
if ([object isKindOfClass:[NSString class]])
...
but how do I distinguish objects from structs or even integer or floats.
Something like:
"isKindOfStruct:CGRect" or "isInt"
for example?
Is this possible?
I thought since you can send everything to NSLog(#"...", objects, ints, structs) it must be possible?
Thanks for any help!
EDIT
My ultimate goal is to implement some kind of polymorphism.
I want to be able to call my function:
MY_FUNCTION(int)
MY_FUNCTION(CGRect)
MY_FUNCTION(NSString *)
...
or [self MYFUNCTION:int]...
and in MY_FUNCTION
-(void)MYFUNCTION:(???)value {
if ([value isKindOf:int])
...
else if ([value isKindOf:CGRect])
...
else if ([value isKindOfClass:[NSString class]])
...
}
I know that isKindOf doesn't exists and you can't even perform such methods on primitives. I'm also not sure about the "???" generic type of "value" in the function header.
Is that possible?
#define IS_OBJECT(T) _Generic( (T), id: YES, default: NO)
NSRect a = (NSRect){1,2,3,4};
NSString* b = #"whatAmI?";
NSInteger c = 9;
NSLog(#"%#", IS_OBJECT(a)?#"YES":#"NO"); // -> NO
NSLog(#"%#", IS_OBJECT(b)?#"YES":#"NO"); // -> YES
NSLog(#"%#", IS_OBJECT(c)?#"YES":#"NO"); // -> NO
Also, check out Vincent Gable's The Most Useful Objective-C Code I’ve Ever Written for some very handy stuff that uses the #encode() compiler directive (that) returns a string describing any type it’s given..."
LOG_EXPR(x) is a macro that prints out x, no matter what type x is, without having to worry about format-strings (and related crashes from eg. printing a C-string the same way as an NSString). It works on Mac OS X and iOS.
A function like NSLog() can tell what types to expect in its parameter list from the format string that you pass as the first parameter. So you don't query the parameter to figure out it's type -- you figure out what type you expect based on the format string, and then you interpret the parameter accordingly.
You can't pass a C struct or primitive as a parameter of type id. To do so, you'll have to wrap the primitive in an NSNumber or NSValue object.
e.g.
[self test: [NSNumber numberWithInt: 3.0]];
id is defined as a pointer to an Objective-C object.
#alex gray answer did not work(or at least did not work on iOS SDK 8.0). You can use #deepax11 answer, however I want to point how this 'magic macro' works. It relies on type encodings provided from the system. As per the Apple documentation:
To assist the runtime system, the compiler encodes the return and argument types for each method in a character string and associates the string with the method selector. The coding scheme it uses is also useful in other contexts and so is made publicly available with the #encode() compiler directive. When given a type specification, #encode() returns a string encoding that type. The type can be a basic type such as an int, a pointer, a tagged structure or union, or a class name—any type, in fact, that can be used as an argument to the C sizeof() operator.
To break the macro apart, we first get "typeOf" our variable, then call #encode() on that type, and finally compare returned value to 'object' and 'class' types from encoding table.
Full example should look like:
const char* myType = #encode(typeof(myVar));//myVar declared somewhere
if( [#"#" isEqualToString:#(myType)] || [#"#" isEqualToString:#(myType)] )
{
//myVar is object(id) or a Class
}
else if ( NSNotFound != [[NSString stringWithFormat:#"%s", myType] rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:#"{}"]].location )
{
//myVar is struct
}
else if ( [#"i" isEqualToString:#(myType)] )
{
//my var is int
}
Please note that NSInteger will return int on 32-bit devices, and long on 64-bit devices. Full list of encodings:
‘c’ - char
‘i’ - int
’s’ - short
‘l’ - long
‘q’ - long long
‘C’ - unsigned char
‘I’ - unsigned int
’S’ - unsigned short
‘L’ - unsigned long
‘Q’ - unsigned long long
‘f’ - float
‘d’ - double
‘B’ - C++ bool or a C99 _Bool
‘v’ - void
‘*’ - character string(char *)
‘#’ - object(whether statically typed or typed id)
‘#’ - class object(Class)
‘:’ - method selector(SEL)
‘[<some-type>]’ - array
‘{<some-name>=<type1><type2>}’ - struct
‘bnum’ - bit field of <num> bits
‘^type’ - pointer to <type>
‘?’ - unknown type(may be used for function pointers)
Read more about Type Encodings at Apple
#define IS_OBJECT(x) ( strchr("##", #encode(typeof(x))[0]) != NULL )
This micro works which I got somewhere in stack overflow.
It's important to note that id represents any Objective-C object. And by Objective-C object, I mean one that is defined using #interface. It does not represent a struct or primitive type (int, char etc).
Also, you can only send messages (the [...] syntax) to Objective-C objects, so you cannot send the isKindOf: message to a normal struct or primitive.
But you can convert a integer etc to a NSNumber, a char* to a NSString and wrap a structure inside a NSObject-dervied class. Then they will be Objective-C objects.

"Generics" in Objective-C to do a RangeValidator?

In C# I could do this:
class RangeValidator<T> {
public T MinValue { get; set; }
public T MaxValue { get; set; }
}
Where T could be any primitive type; int, float, double... or any "object"-type; String, DateTime etc.
If in Obj-C, I did it like this:
#interface RangeValidator {
id minValue;
id maxValue;
}
#property ...
It would work for let's say a NSNumber or NSString, but if I assigned a NSInteger to minValue I'd get something like a
warning: initialization makes pointer from integer without a cast
// Since an id is a pointer to an object, not an integer. Correct?
The obvious solution here is maybe to use a NSNumber instead. I was just curious if there are any other solutions to this kind of problem?
Thanks!
The correct way would be to use a NSNumber and initialize from the integer with
[NSNumber numberWithInt:someInt];
This way the class does not need generics, you could easily perform validation by checking if minValue and maxValue e.g. understands intValue (or some comparison selector maybe, depending on what you want to do).
if([minValue respondsToSelector:#selector(intValue)]) {
return [minValue intValue];
} else {
....
}
If you want to use generics in Objective C, I recommend you using Objective C++ which supports C++ template instead of this ugly untyped code.
The code above doesn't work because NSInteger is a typedef for appropriate primitive type and not a pointer type. You should use a NSNumber wrapper instead.
I think that the idiomatic Objective-C solution would be exactly what you propose, use the id type and wrap primitive number values in an NSNumber. NSInteger, as Konstantin mentions, is a primitive type – see the Foundation Data Type Reference:
#if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
#else
typedef int NSInteger;
#endif
This inconsistency between primitive types and objects is a bit unfortunate, you have to learn to recognize the non-object types like NSInteger, CGRect or CMTime.

Class dump and CFObjects

Does class dump get confused by CFObjects/structs? I used class dump on an application and one of the method's argument was a struct arg1 which is a BInstantMessage:
struct BInstantMessage {
void **_field1;
struct CFString _field2;
unsigned short *_field3;
struct DTextStyle _field4;
struct BUser *_field5;
struct BChat *_field6;
};
struct CFString {
void **_vptr$CFObject;
struct __CFString *mCFRef;
_Bool mIsMutable;
};
struct __CFString;
So, how can I get a CFStringRef or NSString* from this arg1? I am guess that class dump is replacing some CFStringRef by CFString definitions, but it's just a guess...
All I want is to get a CFStringRef from arg1 which is a BInstantMessage.
Thnaks!
The application is using a C++ wrapper for Core Foundation objects. the struct CFString in BInstantMessage is an object of this type. You want (NSString *)(arg1._field2.mCFRef).
The void **_vptr$CFObject field is the major hint here – it represents the vtable for a virtual superclass CFObject – combined with the common C++ m prefix naming convention.