I'm trying to use as little memory as possible in my code. I've tried two ways of sending a custom class object to a method. I'm not sure if there is any difference between these two approaches. Say I have 2 classes, Class1 and Class2 each with their own class variables and methods of course.
All code is written in Class1
Approach 1:
Class2 *class2Object = [[Class2 alloc] init];
[self doSomething: class2Object];
[class2Object release];
-(void) doSomething: (Class2 *) var {
int a = var.a;
}
Approach 2:
Class2 *class2Object = [[Class2 alloc] init];
[self doSomething: &class2Object];
[class2Object release];
-(void) doSomething: (Class2 **) var {
int a = var->a;
}
Is there any performance difference between these two methods? Is the second approach completely pointless? Why is it that I can use the dot notation in Approach 1, but have to use -> in Approach 2?
Thanks.
Is there any performance difference between these two methods?
indeed, there is a negligible difference in performance, due to the fact that in approach 2 you have one more indirection (i.e., pointer dereferencing, see also below); so, approach 1 will save you a few clock cycles.
Is the second approach completely pointless?
approach 2 is useful,e.g., when you would like to allocate a new instance of type Class2 and pass it back to the caller through the same argument; say:
- (bool)cloneObject:(Class2 **)var;
you pass an object in; the object is cloned and returned in var; since it is the address of the object itself which changes, you need to have a pointer to the pointer to the object in order to set the new address; the return value only states if the operation was executed correctly.
Of course, in this example, it would be more natural doing:
- (Class2)cloneObject:(Class2*)var;
i.e., you return the pointer to the object newly allocated, but the use case still holds.
Why is it that I can use the dot notation in Approach 1, but have to use -> in Approach 2?
in the second case you have to use ->
because you are not dealing with a pointer to an object directly; you are dealing with a pointer to a pointer to an object; what you need do in such cases is, first of all, "dereferencing" your pointer (i.e., applying operator *) in order to get a pointer to the object, then accessing the latter as you would do otherwise; this could be written like:
(*var).a
here, var
is a pointer to a pointer to an object of Class2
; *var
is the result of dereferencing it, so you have a pointer to an object of Class2
; finally, .a
is the syntax to access an object property. the syntax:
var->a
is simply a "shorthand" for the operations described above.
In Approach 1, you're accessing a property named a
. This looks fine.
In Approach 2, I'm shocked that your code compiles. It's also utterly useless to be passing a pointer to class2Object
. The only reason to ever pass pointers to objects is if the called method needs to update that parameter (e.g. if it's an out-parameter), which is not the case here. Passing a pointer to an object has absolutely no bearing on memory usage. Objects are already held as pointers (which is why you write Class2 *
), so there's no overhead of copying objects like you might see when passing around a stack-allocated object in C++ (Obj-C doesn't have the concept of stack-allocated objects, except for blocks which is a weird corner case that you don't have to worry about).
So basically, just go with Approach 1 here.
x->y
in C syntax is the same as (*x).y
, so there is no difference in what it's doing except an extra (unnecessary) pointer taking and dereference, as others have said. But I wish to elaborate on a more interesting related point.
You should understand that in
-(void) doSomething: (Class2 *) var {
int a = var.a;
}
the dot is a property access. (It cannot be a struct field access since var
is a pointer.) It is exactly equivalent to int a = [var a];
(unless the getter was explicitly set to another method).
As with all method calls, it will go through the dynamic message passing mechanism. If you want to avoid the slight overhead of that, you might be able to access the variable directly.
If the property a
is synthesized from an instance variable a
(could have been called something else, we will say a
now), instead of accessing the variable through a property, you can instead declare it public (via @public
; otherwise instance variables are protected by default), and then access it directly through ->
:
-(void) doSomething: (Class2 *) var {
int a = var->a;
}
(Note that this is different from what you have, because var
is the object pointer itself, not a pointer to pointer.)
However, public instance variables are generally considered bad style and discouraged. Using it breaks the abstraction in object-oriented programming. I bring it up here for completeness, because technically it is the "fastest" method of accessing an instance variable.