Use of `self->` instead of `self. `

Asked

Viewed 308 times

2

I am working on an app that was not I who started the code and I am having problems regarding the use of the command self->. At some point of the code I’m finding variables declared with self-> instead of self..

@interface UNBill ()
{
    NSMutableArray *billArray;
}
@end
...
- (void)payment:(id)billArray people:(int)peopleRow value:(NSString *)amountPay
{
    [[self->billArray objectAtIndex:peopleRow] setObject:amountPay forKey:columnPayment];
}

From what I’ve identified so far self-> is informing the compiler that it is the billArray global is being used and not the billArray of the method, but now I need to use the billArray of the method, and stating only [billArray objectAtIndex:i] I’m taking Warning.

Can someone explain to me how it works?

  • 2

    Here is a very good explanation for this: http://stackoverflow.com/questions/9072688/dot-operator-and-arrow-operator-use-in-c-vs-objective-c

  • Looking at the code better, I saw that there is the Array billArray as a global variable and as a method parameter. The command self-> is being used within the method to identify that the global variable is being used and not the method parameter variable.

3 answers

5


I will divide this answer into three parts: the difference between self-> and self., the compiler’s notice and how to avoid it, and comments on this question and other answers.


The difference

self-> is used to access an instance variable (Ivar, instance variable) directly within a method of the same class. In your example, the class UNBill has an instance variable called billArray. Methods of this class can be accessed directly by name bilArray or the qualified name self->billArray, which means the instance variable billArray belonging to the current object (self). The use of the operator -> is because self is a pointer to the current object, this object can be interpreted as a structure in C, and billArray can be interpreted as a member of that structure. In fact, most objects in Objective-C can be interpreted as an instance of structure.

self. is used to send a message to the current object. Generally, the notation objeto.x in an expression is an alternative to [objeto x], where x no parameters. A common message case without parameters are the properties reading methods, traditionally called getters: have no parameters and return the value of the property. Also, when that notation is used as the left expression in an assignment (e. g. objeto.x = valor), this assignment is translated as [objeto setX:valor], where -setX: is a Setter which receives a single parameter.

For example, consider the class below:

@interface Cliente : NSObject
@property (copy) NSString *nome
@end

By default, the compiler synthesizes two access methods for the property nome: the getter

- (NSString *)nome;

and the Setter

- (void)setNome:(NSString *)nome;

as well as an instance variable called _nome to store the name.

In this case, class clients can use the notation . to use access methods:

Pessoa *pessoa = [Pessoa new];
pessoa.nome = @"João"; // equivale a [pessoa setNome:@"João"]
NSLog(@"O nome é %@", pessoa.nome); // equivale a [pessoa nome]

Internally, methods of this class can use the same notation to access the property, this time with self:

@implementation Pessoa
- (void)imprimirDados {
    NSLog(@"Dados da pessoa");
    NSLog(@"Nome: %@", self.nome);   
}
@end

Alternatively, the above method could access the instance variable directly without having to go through the getter:

- (void)imprimirDados {
    NSLog(@"Dados da pessoa");
    NSLog(@"Nome: %@", _nome);
}

And the instance variable can be qualified with self->:

- (void)imprimirDados {
    NSLog(@"Dados da pessoa");
    NSLog(@"Nome: %@", self->_nome);
}

In short: self->_nome directly accesses the instance variable _nome, whereas self.nome sends a message called nome for the current object, which in turn executes the method called nome.


The warning

Your example has a feature that can be confusing: the name of the instance variable billArray matches the name of the first method parameter -payment:people:value:. When writing self->billArray within the method, it is obvious that you are referring to the instance variable. When writing only billArray, which value is used: the one of the instance variable or the one of the parameter? As this may not be clear to all programmers, the compiler, through the warning -Wshadow-ivar, warns that the local declaration of billArray (as parameter) blurs the instance variable -- this means that billArray refers to the parameter. If this is the behavior you want, you can ignore the warning. If you want to delete the warning, you have three options: change the names in such a way that the instance variable name is distinct from the parameter name, use -Wno-shadow-ivar when compiling that file, or using pragmas to disable the warning only in that method:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow-ivar"
- (void)payment:(id)billArray people:(int)peopleRow value:(NSString *)amountPay
{
    [[billArray objectAtIndex:peopleRow] setObject:amountPay forKey:columnPayment];
}
#pragma clang diagnostic pop

In your case, you may not want to adopt properties and/or instance variables prefixed with _. An alternative is to rename the billArray for aBillArray or pBillArray. Anyway, I recommend changing one of the names instead of disabling the warning.


Patchwork

Some comments on the original question and other answers:

the command self->

self-> is not a command. self is a reserved identifier created automatically by the compiler to refer to the current object. In fact, this identifier is actually the name of the first parameter hidden in all methods in Objective-C. -> is a C operator to dereference a structure and access a member of it.

self-> is informing the compiler that it is the billArray global

billArray is not (a variable) global: it is an instance variable, similar to a structure member in C.

what is bothering you is about the type of the billArray variable of the method that is id and how ID is just a classless object (similar to var in other languages) you cannot call methods of other classes like those of the NSMutableArray in it

Not the case. Objects of a type id, which is the generic type for objects, have no interface compliance check, so the compiler accepts the composition of any type of message for that object provided the corresponding selector has been previously declared. For example, -[NSArray objectAatIndex:] has type of return id. You can send any message (with a previously declared selector) to the object returned by this method and, being valid syntax in Objective-C, does not receive warning or error from the compiler. To the code below:

NSArray *a = [NSArray arrayWithObject:@"Uma string"];
NSLog(@"Length is %lu", [[a objectAtIndex:0] length]);

compiler does not issue any warning. What happens is run-time verification: if the object (of type id) does not reply to message with dial length, error occurs during execution.

the use of -> is just a pointer access, very common in C++ for example. The code is fully compatible with Objective-C, but I recommend avoiding, to facilitate a standard and clarity of code

Some people always recommend using self-> just to leave clearer which is directly accessing an instance variable.

I recommend you change the name of your method parameter to pBillArray, is the custom for parameter names in Objc.

Customs vary. Apple’s old custom was not to prefix with p, but with indefinite article (aBillArray). Apple’s latest custom is not to use any prefix in parameter names.

Also declare your "class instances" always using @property, so the compiler will automatically create the getters and setters for you, making you able to access the billArray using only self.billArray. In addition to ease of use, this is standard usage in what we call "modern Objective C".

"class instances" - in fact, they are called instance variables in Objective-C, similar to attributes (of instance) in other object-oriented languages.

As for properties, this is a somewhat (rather little, I would say) controversial topic. Generally speaking, Apple has always recommended using properties rather than instance variables directly. This recommendation was more important before the advent of ARC because the getters and setters generated by the compiler did the management (manual) of memory, sending retain and release when appropriate. With the advent of ARC, this management happens automatically even when using the instance variable directly.

Note that there is a philosophical current that advocates that no method other than the getter and of Setter, even from the class itself, you must directly access instance variables. This would bring more robustness because any change related to that variable would be located only in your getter and Setter. On the other hand, always use getter and Setter instead of the instance variable has cost: John Mccall, one of Apple’s engineers working on Clang/LLVM, detailed this in a mailing list. I play here his remarks:

Right. There are a Lot of Things that are hard to Individually Measure but which make a noticeable Difference in the Aggregate.

Properties affect performance in a Lot of Ways:

  1. As already discussed, sending a message to do a load/store is slower than just Doing the load/store inline.
  2. Sending a message to do a load/store is also quite a bit more code that needs to be Kept in i-cache: Even if the getter/Setter Added zero extra Instructions Beyond just the load/store, there’d be a Solid half-Dozen extra Instructions in the Caller to set up the message send and Handle the result.
  3. Sending a message forces an entry for that selector to be Kept in the method cache, and that memory generally sticks Around in d-cache. This increases Launch time, increases the Static memory Usage of your app, and makes context switches more Painful. Since the method cache is specific to the Dynamic class for an Object, this problem increases the more you use KVO on it.
  4. Sending a message forces all values in the Function to be Spilled to the stack (or Kept in callee-save Registers, which just Means spilling at a Different time).
  5. Sending a message can have arbitrary side-effects and therefore forces the Compiler to reset all of its assumptions about non-local memory.
  6. A message send can have arbitrary side-effects and therefore cannot be hoisted, sunk, re-ordered, Coalesced, or eliminated.
  7. In ARC, the result of a message send will Always get retained, either by the callee or the Caller, Even for +0 Returns: Even if the method doesn’t retain/autorelease its result, the Caller doesn’t know that and has to Try to take action to Prevent the result from Getting autoreleased. This can Never be eliminated because message sends are not statically analyzable.
  8. In ARC, because a Setter method generally takes its argument at +0, there is no way to "transfer" a retain of that Object (which, as discussed above, ARC usually has) into the Ivar, so the value generally has to get retain/Released Twice.

None of this Means that they’re Always bad, of Course - there are a Lot of good reasons to use properties. Just Keep in Mind that, like Many other language Features, they’re not free.

John.

I suppose most applications are not hampered by the loss of performance from using properties, but it’s good to know if you encounter an intensive processing situation. And this kind of performance loss is difficult to measure later with Instruments because, in an application with multiple properties, the loss of performance, even if remarkable, is diluted.


Resume: if possible, use properties. Otherwise, rename or the instance variable (e. g. _billArray) or the parameter (e. g. aBillArray or pBillArray).

1

**NSMutableArray** *billArray;

(void)payment:(**id**)billArray

The reason your warnings have no relation to him using pointer (->) or not in this case. As much as the default is to use [[self billArray] objectAtIndex:i] or [self.billArray objectAtIndex:i] or just billArray (depending on who you want to access) what’s holding you back is the type of the billArray variable of the method that is id and how ID is just a classless object (similar to var in other languages) you cannot call methods from other classes like the NSMutableArray in it.

How to solve?

First you need to convert the billArray id to a NSMutableArray or NSArray and after that use it normally. Until a cast resolves.

I hope it helped.

1

First it is worth commenting that the use of ->is just a pointer access, very common in C++ for example. The code is fully compatible with Objective-C, but I recommend avoiding, to facilitate a standard and clarity of code.

About the self, yes, it indicates that you are accessing the class attribute instead of the instance defined in the scope of your method. I recommend you change the name of your method parameter to pBillArray, is the custom for parameter names in Objc.

Also declare your "class instances" always using @property, so the compiler will automatically create the getters and setters for you, making you able to access the billArray using only self.billArray. In addition to ease of use, this is standard usage in what we call "modern Objective C".

Already on your Warning, you need to give more details, at least inform which Warning is being presented.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.