How dangerous is it to use pointer style assignment versus setter methods in Objective-C?

Suppose I have a simple class like:

@interface A { 
// @public
    int var;
}
// @property(some_property) int var;
@end

      

When I want to access the var variable, I have some parameters. If I make var public I can do this:

A objectA = [ [ A alloc ] init ];
NSLog( @"%d", objectA->var );
objectA->var = someNumber;

      

If I make this a property, I will need to do something more like this:

A objectA = [ [ A alloc ] init ];
NSLog( @"%d", objectA.var ); // dot-syntax
NSLog( @"%d", [ objectA var ] ); // get-syntax
[ objectA setVar: someNumber ];

      

I've tried both and they work fine, but my question is, how dangerous is it to use old-style pointer notation to access variables inside an object? Should I be concerned now that I should be concerned about standardizing my method access? Or can I get away with this, but I want it while it works?

+2


source to share


5 answers


I'll throw my own 2 cents as my comment on another question started a similar discussion a few days ago.

You should always use accessor methods to set and get properties of an object outside of that object class's implementation. You should almost always use accessor methods to access the properties of a class, even within the implementation of the specified class.

Here is a list of reasons why:



  • Encapsulation . A class can expose a property that looks the same to the outside world as any other but is not internally supported by the corresponding ivar. Perhaps this is actually doing some transformation of another intrinsic property. More importantly, this implementation may change sometime along the line. One of the main reasons for OO encapsulation is that the internal implementation of a class can be changed without the need for external users of that class to make changes. (I made just such a change - from ivar to a completely different backing method - in an important and old class this morning. If a bunch of other classes, or even methods in the same class accessed the IVAR directly, I would have to change a lot more code than I am.)

  • Memory management. ... This is not such a big deal with ARC, as it will (mostly see below) be handled properly anyway, but with manual memory management, the accessor for the property will take care of holding and disposing of the underlying object correctly. Keeping this code in one place greatly reduces the likelihood of memory management errors (leaks and overrides), makes it easier to read, easier to modify, and less verbose code. Even with ARC enabled, properties declared using copy behavior rely on the setter method to perform the copy, and you get around this if you access ivar directly.

  • Custom behavior in the set. This is really just another piece of encapsulation. It is very common for a class to want to do something other than set the ivar value to a new value when the appropriate setter is called. One very simple, straightforward example is that a subclass of NSView calls [self setNeedsDisplay]

    when a property changes that affects its appearance. If you don't call the installer, install ipar directly instead, you bypass this behavior entirely. Again, you might think this is fine if you know the setter doesn't need to do anything, but the requirements change, and by using a setter from the start you make it much easier to change the string.

  • Custom behavior on get / lazy instance . One of the most common reasons for this is to make a lazy instance. You implement a getter method on a property so that it checks if the underlying ivar is null, and if so, it initializes the ivar first before returning it. The next time it calls, the ivar will be installed, so the initialization will not be repeated. This is an easy way to defer the creation of expensive (CPU-intensive and CPU intensive) objects until you need them. For example, this is often done as a performance optimization to improve startup time, which is a great example of encapsulation that allows simple improvements to a class's implementation without breaking the external use of an existing class.

  • KVO . Objective-C provides a mechanism called Key Value Observing that allows one object to request notification at any time when a given property of another object changes. If you use properly named accessors or synthesized @properties, you get KVO support automatically. However, for KVO to work, you actually need to call accessor methods. If you change the ivar directly, the observers of the corresponding ivar property will not be notified. Regardless of whether you set another property on an object or a property on yourself, you don't know if observers are registered for changes to that property, and you short-circuit their change notification.

  • readability. This doesn't really apply to your example objectA->var

    , it is more applicable to direct ivar access in a native class implementation ( var = ...

    ) where self->

    it is implied / inserted by the compiler. The problem is that, especially in a long method, you may see the assignment operator and not know at first glance if the variable being assigned is local to the current scope or instance variable. This can be mitigated with naming conventions like the ivars underscore prefix, Hungarian notation, and so on, but still Objective-C conventions mean it's best to use self.var = ...

    or [self setVar:...]

    (which, by the way, are just the same semantically).

  • Why not? There are those that don't use accessor methods, but I can't think of any compelling reasons. Actually it is not much faster as the variable name is prefixed with "i". just doesn't print that much. There, when you add the optional ObjC message dispatch, there is an execution penalty on the accessor call. However, this punishment is very small and, of course, premature optimization is bad. It is very rare that the overhead of calling an accessor method is sufficient to seriously affect the performance of an application.

Remember that I used an "almost" qualifier regarding the use of direct ivar access within a class implementation. If you implement special accessor methods (as opposed to @synthesizing a property), you will of course have to access the ivar directly inside the accessory implementation. Also, there are some who disagree, but it is a good idea (and Apple's recommendation) to set ivars directly inside the class's initializer ( -init

) method . The reason for this is that you can avoid setter side effects as long as the class is not fully initialized. For example, you don't want KVO observers to be notified of a change when they can find a notifier in an inconsistent / partially initialized state.

+11


source


How dangerous is it to use old-style pointer notation to access variables inside an object?

Very dangerous.

Should I be worried that I have to worry about standardizing my method access later?



Yes. These other things to worry about include: memory management ( Memory. Management !!! ), "Key-value monitoring" not working, etc. This all happens because by using ->

, you are accessing the instance (some overly strict OO fans will even say that this breaks encapsulation, which it does quite often), while the dot notation calls the correct getter and setter methods ( which take care of memory management decently, notifying KVO listeners etc ... etc)

So, in general, use accessor methods (and dot notation, if you like) and don't access instance variables directly.

+5


source


You must use ownership. This approach is more standard, so it will play well as a team. It also has the distinct advantage of allowing you to change the implementation later without changing the interface that the callers are using.

+2


source


Before ARC, there was a big difference in that the property type reference (using either [thing setMyVar:value];

or thing.myVar = value;

follows save / release semantics, whereas a direct iVar ( thing ->myVar = value;

) reference ) However, this is a little more confusing with ARC.

+2


source


Yes, using the old style pointer notation is more dangerous. In Objective-C, using dot notation is exactly the same as using the setVar method.

[objectA setVar:someNumber]; // Exactly the same as objectA.var = someNumber;

      

When I say exactly the same thing, I mean. When you use objectA.var = someNumber , you call the setter method (which you can change and check the values ​​before changing the instance variables). When using pointer-style assignments, you modify directly, allowing values ​​that might be incorrect to be stored according to the business logic of your application.

In other words: always use Objective-C setter / getter conventions (they are there for a reason).

I particularly like to use the syntax objectA.var = someNumber because it is easier to understand by other language programmers (Objective-C method calls are weird and, if you don’t know, t know that Objective-C automatically creates setters / getters when synthesizing properties, they are harder to read for them).

0


source







All Articles