When a new object is created and initialized why do we use id? Can't we use (NSObject*)?
Not every object in Objective C is NSObject. There are other root classes (for example, NSProxy), that are not derived from NSObject.
id means absolutely any object. Everything is Objective C that can receive messages (including Class) can be passed as id without type warnings.
NSObject* is only useful on objects that are actually derived from NSObject. If you pass something that is not derived from it, type checker will complain.
Because NSObject is a distinct Objective C class. It's the base class for most everything (* but not everything, +1 to HamsterGene), but it's still a class.
And if you assigned a new object (of any type that descends from NSObject) to it, you'd lose the inheritence & properties of whatever subclassed type you had created were.
id is roughly equivalent to void * in it's behavior where you can assign any Objective C object to an id, like how you can assign any random chunk of memory (with no care for it's contents or type) to a void *.
Related
Hey so I am new to Xcode and I have a few questions.
I want to make a Grade-book Application, that implements quite a few classes. For example, I created a class called "AssignmentList" which basically stores a list of assignment grades in the form of a double.
Another class, called "Course" has a NSMutableArray of AssignmentList objects.
If I wanted to retrieve an AssignmentList parameter for a course, my Java instinct would tell me to make a getter method like this:
-(AssignmentList)getAssignmentList(Course);
However, I can't seem to do that in Objective C, and only works when I do this:
-(id)getAssignmentList(Course);
How do I go about this? I wanted to create a UITableView listing all the AssignmentList objects of a Course, but I can't even set a UITableViewCell with the name of the AssignmentList because it won't let me use the getName method I made, because getName only works for an AssignmentList object, but the getAssignmentList method returns an (id).
Assuming an AssignmentList is a class with instances and not some kind of collection (e.g. an NSArray of Assignments), then your declaration needs to be something like:
-(AssignmentList *) getAssignmentList:(Course *) course;
The * is important: in Objective-C you don't really pass around objects, you pass around pointers to objects. (Well, that's true in Java, too, but you don't have to be explicit about it.)
When you declare something id that means pointer to something of unknown type so you don't need the *.
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 have an Objective-C class which contains a C-style struct. I need to call a C function passing a pointer to this object member (a.k.a. property). For the life of me, I can't figure out how to get the address of this C struct. Using the traditional & operator to get the address, I'm getting an LValue compiler error.
typedef struct _myStruct
{
int aNumber;
}MyStruct, *pMyStruct;
#interface MyClass : NSObject {
MyStruct mystruct;
}
#property (readwrite) MyStruct myStruct;
#end
The following code results in a compiler error:
MyClass* myClass = [[MyClass alloc] init];
MyStruct* p = &(myClass.myStruct);
How do I get a pointer to the myStruct member of the myClass object?
There are often pretty good reasons to do what the original post is asking, given that Objective-C apps often have to work with C/C++ API's that take pointers to structs and similar types, but in a Cocoa app you'll often want to store such data in Objective-C classes for data management, collection in arrays and dictionaries, etc.
Though this question has been up for awhile I don't see the clear answer, which is: you can have a method that returns the address of the data that's backing your property, but in that method don't use "self" or it will go through the accessor and still not work.
- (const MyStruct*) getMyStructPtr
{
return &mystruct;
}
Note that I'm using the declared property from the OP, but not referencing it as self.mystruct, which would generate a compiler error (because that invokes the synthesized getter method).
MyStruct mystruct is private in MyClass, I assume when you do myClass.myStruct you are only refering to generated accessor method not the actual structure.
I don't think you can access the instance variable (structure in this case) from outside because it is private.
To get a pointer to the myStruct instance variable, you need to write a method that returns a pointer to that instance variable.
- (void)getMyStructPointer:(MyStruct **)outStruct {
*outstruct = &myStruct;
}
I don't really think this is a good idea, though. Other objects should not be mutating that object's ivar out from under it, and that's the only thing you can do with a pointer to the struct that you can't do with a copy of the struct returned by value.
The question itself demostrates a lack of understanding of at least the terminology.
A property is an interface consisting of two (or one for readonly) methods made public by the object, namely the getter and setter methods, in this case:
- (MyStruct) myStruct;
- (void) setMyStruct: (MyStruct) newMyStruct;
It makes no sense to talk about "taking the address of a property".
You can take the address of an instance variable (ivar). In this case you have an ivar named mystruct, and you can take the address of it with &mystruct in a method of MyClass. Since it is marked #protected (by default), you can take the address of it in a subclass using &self->mystruct. If you mark it #public, then you could take the address of it using &myobj->mystruct. This is a terrible idea, and you should really really rethink this, but you could do it.
If you just want the address of the ivar for some short lived purpose (for example, if MyStruct was large) you could do this, but it would be very unusual, and you'd be better off writing an explicitly named method like:
- (MyStruct*) getAddressForSettingMyStruct;
and if it is just read only, even better would be to use const MyStruct*.
In Objective-C, what's the difference between declaring a variable id versus declaring it NSObject *?
With a variable typed id, you can send it any known message and the compiler will not complain. With a variable typed NSObject *, you can only send it messages declared by NSObject (not methods of any subclass) or else it will generate a warning. In general, id is what you want.
Further explanation: All objects are essentially of type id. The point of declaring a static type is to tell the compiler, "Assume that this object is a member of this class." So if you send it a message that the class doesn't declare, the compiler can tell you, "Wait, that object isn't supposed to get that message!" Also, if two classes have methods with the same name but different signatures (that is, argument or return types), it can guess which method you mean by the class you've declared for the variable. If it's declared as id, the compiler will just throw its hands up and tell you, "OK, I don't have enough information here. I'm picking a method signature at random." (This generally won't be helped by declaring NSObject*, though. Usually the conflict is between two more specific classes.)
id means "an object", NSObject * means "an instance of NSObject or one of its subclasses". There are objects in Objective-C which are not NSObjects (the ones you'll meet in Cocoa at the moment are NSProxy, Protocol and Class). If some code expects an object of a particular class, declaring that helps the compiler check that you're using it properly. If you really can take "any object" - for instance you are declaring a delegate and will test all method sends with respondsToSelector: calls - you can use an id.
Another way to declare an object variable is like "id <NSObject>", which means "any object which implements the NSObject protocol.
From my limited understanding of Objective-C, not all objects are derived from NSObject (unlike Java where all objects derive from Object). You can theoretically have other root objects. id could apply to any of those non-NSObject derived objects.
I would like to add another difference. When you add a protocol to id, it does not longer mean that it will be of type NSObject *, it just means that it will be any class that confirms to that protocol.
So, for example, this code will not throw any error, since NSObject's category NSDelayedPerforming has that method:
id testId;
[testId performSelector:#selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];
However, this code will show the error No known instance method for selector "performSelector:withObject:afterDelay:":
id<NSMutableCopying> testId;
[testId performSelector:#selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];