id
In Objective-C, object identifiers are of a distinct data type: id. This type is the general type for any kind of object regardless of class and can be used for instances of a class and for class objects themselves.
id anObject;
Till here its simple and clear
For the object-oriented constructs of Objective-C, such as method return values, id replaces int as the default data type. (For strictly C constructs, such as function return values, int remains the default type.)
didn't understand what its talking about id replaces int? and in last inside brackets int remains the default value?
The keyword nil is defined as a null object, an id with a value of 0. id, nil, and the other basic types of Objective-C are defined in the header file objc/objc.h.
id is defined as pointer to an object data structure:
typedef struct objc_object {
Class isa;
} *id;
the above is not a obj-c syntax what is it and what it is explaining?
Every object thus has an isa variable that tells it of what class it is an instance. Since the Class type is itself defined as a pointer:
typedef struct objc_class *Class;
the isa variable is frequently referred to as the “isa pointer.”
also didn't understand this last para.
For the object-oriented constructs of Objective-C, such as method return values, id replaces int as the default data type. (For strictly C constructs, such as function return values, int remains the default type.)
Your book's just being a bit confusing here. All it's saying is that if you're working with objects and you don't want to get more specific, id is a good data type to use.
id is defined as pointer to an object data structure:
typedef struct objc_object {
Class isa;
} *id;
the above is not a obj-c syntax what is it and what it is explaining?
That's the internal representation of an object. Your book is trying to show that an objective C object isn't magic: under the surface it's just a struct. The data type id is a pointer to such a struct.
Every object thus has an isa variable that tells it of what class it is an instance. Since the Class type is itself defined as a pointer:
typedef struct objc_class *Class;
the isa variable is frequently referred to as the “isa pointer.”
In its internal data structure, each object has a pointer to another object that represents its class.
You don't need to know this stuff if you're just interested in programming in Objective-C (at least not while you're learning). It does come in handy if you're doing some advanced stuff, such as when you're interacting with the Objective-C runtime directly.
didn't understand what its talking about id replaces int?
Objective-C is a superset of C.
In C, a function must have a return value. If a return value is not specified, then a function returns int by default.
Objective-C overrides this default behaviour of C and returns id as a default value from any class method that doesn't specify its return value. But at the same time leaves the default behaviour for other (C-)functions the same (i.e. int is still the default return value for everything else)
Related
I'm trying to cast a Class object to a certain protocol, which defines class methods (+) that that class implements.
I know how to do this with (id< protocol>), as outlined in this question, but I can't seem to figure out the right way for Class objects.
The basic scenario is as follows.
I have a protocol:
#protocol Protocol <NSObject>
+ (id)classMethod:(id)arg;
#end
I then have a function which accepts a Class object, which it knows sometimes conforms to the protocol based on another argument (this is obviously very simplified):
- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
{
id instance;
if (arg != nil) {
instance = [(Class<Protocol>)cls classMethod:arg];
}
}
Now I don't get any warnings on this, and it looks right to me. (I'm not going to see any errors in any case, because I can guarantee that if arg != nil then the class conforms.)
However, I'm not getting autocompletion in Xcode, which makes me wonder if this is the right way to do it. Any thoughts? (Note that I am not interested in instance being id< Protocol>.)
If you want to determine whether cls conforms to a particular protocol (and assuming that classMethod: is a required class method of that protocol), you can simply:
- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
{
id instance;
if ([cls conformsToProtocol:#protocol(Protocol)]) {
instance = [cls classMethod:arg];
}
return instance;
}
Alternatively, just see if it responds to a particular class method selector:
- (id)someMethodWithClass:(Class)cls andUseArg:(BOOL)arg
{
id instance;
if ([cls respondsToSelector:#selector(classMethod:)]) {
instance = [cls classMethod:arg];
}
return instance;
}
The question is 11 years old and there is nothing wrong with the Rob's answer, but I find it unfortunate that the centrepiece part of it (whether type-casting a Class object with a protocol is a correct syntax) never got proper attention.
First of all static typing in Objective-C is very artificial thing, and it exists solely for the compiler to emit a warning (not even an error). Let's start with what Class objects really is - if you take a look at the documentation, you will find that the Class type is actually an alias for objc_class * type:
typedef struct objc_class *Class;
You can find definition of objc_class type in the source codes of Apple's objc runtime library:
// inherits objc_object with some adjustments
struct objc_class : objc_object { ... }
As you can see, objc_class is just an extension to a objc_object. Any Objective-C class is in fact instance of this objc_object. E.g. here is how NSObject or id aliases look like:
// "translation" of an Objective-C class declaration
typedef struct objc_object NSObject;
// the same for `id` type but with the pointer type included
typedef struct objc_object *id;
It means that "static typing" doesn't exist in Objective-C, the "typing" of an instance happens via introspection of a given instance (different kind of meta-information objc_object stores). It makes all Objective-C classes compatible with each other (first - because it's a pointer, second - because it's a pointer to the same structure). E.g. you can write code like this:
Class obj = [NSObject new];
..and it will happily compile.
However this purely dynamic nature of the language makes it very error-prone, exposing all kinds of mistakes a programmer can make. In order to avoid that clang in fact does compile time checking of the specified types, but it purely relies on the programmer to provide correct data for a type of an instance, and if the types are incompatible from Objective-C perspective, the compiler can emit a warning for you. This works for instance objects, but unfortunately there is no syntax in Objective-C to type a class object other than with the Class alias. It means that for the compiler all such objects are indistinguishable during compile time.
And all of this is true for protocols typing. Here I mean that when you add a protocol conformance token to a variable type (id<TDWLoadable> var) you merely ask the compiler to check whether the assigned to the variable object conforms to the given protocol:
#protocol TDWLoadable
+ (void)classMethod;
- (void)instanceMethod;
#end
#interface TDWObject : NSObject
#end
// Initializing '__strong id<TDWLoadable>' with an expression of incompatible type 'TDWObject *'
id<TDWLoadable> loadable = [TDWObject new];
For a class object, however, the same check is just ignored, because Class objects cannot be typed:
Class<TDWLoadable> loadable = [[TDWObject new] class];
This behavior is described in the Type Checking section of Protocols part in The Objective-C Programming Language (emphasis mine):
...the declaration
id <Formatting> anObject;
groups all objects that conform to the Formatting protocol into a type, regardless of their positions in the class hierarchy. The compiler can make sure only objects that conform to the protocol are assigned to the type.
In each case, the type groups similar objects—either because they share a common inheritance, or because they converge on a common set of methods.
The two types can be combined in a single declaration:
Formatter <Formatting> *anObject;
Protocols can’t be used to type class objects. Only instances can be statically typed to a protocol, just as only instances can be statically typed to a class. (However, at runtime, both classes and instances respond to a conformsToProtocol: message.)
Also, if we take into account that objc_class is in fact just an extension to objc_object then two expressions of kind:
Class<TDWLoadable> classObj;
id<TDWLoadable> obj;
Should follow the same contract (i.e. + (void)classMethod has to refer to metaclass of classObj and - (void)instanceMethod to the class object itself).
Having that said, since the syntax essentially has no effect and just ignored by the compiler, you are free to come up with your own convention to the Class<Protocol> typing.
I am bit confused, as my title mentioned,
Is id in Objective C is primitive data type? or Object type? I always thought that id is Object type as it is pointing towards an object.
So, Is it Object type or Primitive data type?
Definitly not a primitive type. From Apple:
In Objective-C, object identifiers are of a distinct data type: id. This type is the general type for any kind of object regardless of class and can be used for instances of a class and for class objects themselves.
id is declared in objc.h as
typedef struct objc_object {
Class isa;
} *id;
so yes, I'd say it's primitive (pointers are primitive types in C).
I believe that 'id' from Objective-C is a similar type to void pointer from plain 'c'. As pointers are primitives I would guess that 'id' is indeed a primitive type.
Can you guys help me understand a concept real quick, I'm having trouble understanding the conversion from C to objective-C:
If I had a particular instance method that look like this:
-(void)addOwnerNamesObject:(NSString *)n;
{
// ownerNames defined as NSMutableSet
[ownerNames addObject:n];
}
I understand a few things...
It is an instance method that can be called by the program.
In C this would not return anything (just execute the code in the curlies)
In C, the syntax is slightly less confusing - (void)InstanceMethod(Char *nameOfArgument)
Here's where I need help:
When you call this method are you still sending it an argument?
If so, is that argument an NSString instance that the method names n?
And finally... off topic
If you have a method...
-(id)someMethod:(NSString *)pn
{
}
What is the (id) for? does that tell the compiler that it can return any type of object?
Thanks for helping the Newbie... Much appreciated.
First of all, you should really take a look at the basic Objective-C documentation.
In Objective-C, a method can be preceded by a + or - sign.
+ is for class methods, - is for instance methods.
Then you have the return type, inside parenthesis, and the method name.
- ( int )foo;
An instance method named foo, returning an int.
A similar C function would be:
int foo( void );
In Objective-C, the method name is a bit special when you have arguments.
For instance:
- ( int )foo: ( double )num;
A member method named foo:, returning an int and taking a double argument named num.
Similar C function:
int foo( double num );
Now with multiple arguments:
- ( int )foo: ( double )num1 bar: ( float )num2;
A member method named foo:bar:, returning an int and taking a double argument named num1 and a float argument named num2.
Similar C function:
int foo( double num1, float num2 );
About your question on id, it's simply the method return type.
id is a typedef used for Objective-C instances.
Basically, it's a void *.
id does represent an Objective-C object pointer, for any class.
You already know what you're talking about.
1.) When you call this method are you still sending it an argument?
yes, whatever is after the colon
add multiple colons to pass additional parameters...
-(void)addOwnerNamesObject:(NSString *)n withSomeIntYouWantToPass:(int)value;
2.) If so, is that argument an NSString instance that the method names 'n'?
yes
3.) What is the (id) for? Does that tell the compiler that it can return any type of object?
yes, you will return an NSObject or subclass of NSObject
First the dash (-) in the method name says that this is an instance method which means you need an instance to send this message to. The call would look something like this:
NSString* s = #"a string";
[someInstance addOwnersNameObject:s];
In this case you are passing the NSString instance s to the addOwnersNameObject message.
id is like void * in C.
To add to those very valid answers already given with a further discussion of id:
Objects in Objective-C are typeless, which means that at a fundamental level you don't need to know the type to be able to talk to the object. That's one of the big differences between Objective-C and, say, C++.
Pointers to objects are usually typed, such as NSString * to make the code more readable and to indicate your intentions to the compiler so that it can provide suitable warnings if you do anything odd.
id is a typeless pointer to an object. Any object type can be passed as id and any id value can be assigned to any object pointer without casting.
99.99% of the time, id could be replaced with NSObject * since 99.99% of objects inherit from NSObject, meaning that you could use the fact of inheritance rather than the fact of typeless objects to pass things around generically. However NSObject is a little bit special in being both an object and a protocol and some objects aren't actually subclasses of NSObject — NSProxy and the classes that represent blocks jump immediately to mind. You'll rarely be particularly interested in those special cases but id is nevertheless often used as a convention because people prefer the semantics of passing an object with no indication of its type to passing an object with a known ancestor.
I am (trying to) learn Objective-C and I keep coming across a phrase like:
-(id) init;
And I understand id is an Objective C language keyword, but what does it mean to say "the compiler specifically treats id in terms of the pointer type conversion rules"?
Does id automatically designate the object to its right as a pointer?
id is a pointer to any type, but unlike void * it always points to an Objective-C object. For example, you can add anything of type id to an NSArray, but those objects must respond to retain and release.
The compiler is totally happy for you to implicitly cast any object to id, and for you to cast id to any object. This is unlike any other implicit casting in Objective-C, and is the basis for most container types in Cocoa.
id is a pointer to any Objective-C object (objc_object). It is not just a void pointer and you should not treat it as so. It references an object that should have a valid isa pointer. The values that can be stored in id are also not just limited to NSObject and its descendants, which starts to make sense of the existence of the NSObject protocol as well as the NSProxy class which does not even inherit from NSObject. The compiler will allow you to assign an object referenced by type id to any object type, assign any object type to id, as well as send it any message (that the compiler has seen) without warning.
id is a generic type. This means that the compiler will expect any object type there, and will not enforce restrictions. It can be useful if you're expecting to use more than one class of objects there; you can then use introspection to find out which class it is. id automatically assumes a pointer, as all objects in Objective-C are passed as pointers/references.
Some Additional Resources:
id vs NSObject vs id*
Objective-C Programming (Wikibooks)
Introspection
Dynamic Typing
id is a data type of object identifiers in Objective-C, which can
be use for an object of any type no matter what class does it have.
id is the final super type of all objects.
In java or c# we use like this
Object data = someValue;
String name =(Object)data;
but in objective c
id data= someValue;
NSString *name= data;
Yes and no. It's true that having id x designates x as a pointer, but saying that the pointer type conversion rules apply is wrong, because "id" has special type conversion rules. For example, with a void * pointer you can't do this:
void *x;
char *y = x; // error, this needs an explicit cast
On the contrary, it's possible with id:
id x;
NSString *y = x;
See more usage of type id in objective c examples.
In addition in the "modern" Objective C it's preferred to use instancetype instead of "id" on "init" methods. There's even an automatic conversion tool in Xcode for changing that.
Read about instancetype: Would it be beneficial to begin using instancetype instead of id?
I want to know why id is a weak reference pointer,how it is able to handle any class type pointer and at run time how can we detect that which type of class pointer is assigned to id.
Why is id a weak reference pointer?
id is not a weak reference pointer, at least not in the ARC ownership sense. Whether an id-typed reference to an object is weak or not depends on the reference having been declared __weak (and variations) and the object’s class actually supporting weak references.
However, you could say that id provides weak typing, although I think that dynamic/duck typing is a more accurate description. Since an id- typed reference contains no compile-time class-type information, the compiler isn’t able to, for example, determine if the underlying object can respond to a given selector, which could lead to runtime errors.
How is it able to handle any class type pointer?
That’s part of the definition of the Objective-C language. The compiler recognises id as being the supertype of every Objective-C class, and it treats id differently. See the answer below as well.
At runtime, how can we detect that which type of class pointer is assigned to id?
In Apple’s Objective-C runtime, the first bytes in the memory allocated to an object must point to that object’s class. You might see this referenced elsewhere as the isa pointer, and that’s how Apple’s runtime finds out the class of every1 object. The id type is defined to have this information as well. In fact, its only attribute is the isa pointer, which means that all1 Objective-C objects conform to this definition.
If you have an id reference and want to discover the class of the referenced object, you can send it -class:
id someObject;
// Assign something to someObject
// Log the corresponding class
Class c = [someObject class];
NSLog(#"class = %#", c);
// Test whether the object is of type NSString (or a subclass of NSString)
if ([someObject isKindOfClass:[NSString class]]) {
NSLog(#"it's a string");
}
1Tagged pointers are a notable deviation of this structure, and (partly) because of them one shouldn’t access the isa pointer directly.
It's nice to have a generic object type, so you can define collection types that can hold any kind of object, and other generic services that work with any object without knowing what kind of object it is.
There is no trick to make id work. At a binary level all pointers are interchangeable. They just represent a memory address as a numerical value. To make id accept any type of pointer, it's only necessary to disable the rules of the compiler that normally require pointer types to match.
You can find out information about the class of an id type variable in these kinds of ways:
id theObject = // ... something
Class theClass = [theObject class];
NSString *className = NSStringFromClass(theClass);
NSClassDescription *classDescription = [NSClassDescription classDescriptionForClass:theClass];
But it's rarely necessary to do those kinds of things in code. More often, you want to test if your id variable is an instance of a particular class, and if so cast it to that class and start treating it as that type.
if ([theObject isKindOfClass:[MySpecializedClass class]]) {
MySpecializedClass *specialObject = (MySpecializedClass *)theObject;
[specialObject doSomethingSpecial];
}
If you were to use -class to find out the class, but it returned a class you know nothing about, then there's nothing special you can do with the object based on its class anyway. So there is no reason to do anything but check if it matches classes you know about, and only if you intend to do special handling for those classes anyway.
You can sometimes use isMemberOfClass instead of isKindOfClass. It depends whether you want an exact match or to include subclasses.
It may be worth to take a look on header file objc/objc.h to find internals of id.
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
typedef struct objc_selector *SEL;
typedef id (*IMP)(id, SEL, ...);