Accessing instance variables.. Apple approved way?

Discussion in 'iOS Programming' started by Tander, Jul 4, 2013.

  1. Tander macrumors 6502a

    Tander

    Joined:
    Oct 21, 2011
    Location:
    Johannesburg, South Africa
    #1
    Hi guys,

    So I am busy reading a book by Apress: iOS 6 Programming.

    Really enjoying the book at the moment and learning a great deal. :D

    However, I do have a question regarding the book's code.

    In the book - we create 5 buttons with drag-to-code method from the .xib file - the outlets are properties in the header file. No problem there (Unless we wanted them to be private, of course )

    Here is the code the book uses for positioning theseGUI objects on the screen during different rotations of the device:

    Code:
    - (void)doLayoutForOrientation:(UIInterfaceOrientation)orientation {
        if (UIInterfaceOrientationIsPortrait(orientation)) {
            _bigButton.frame = CGRectMake(20, 20, 280, 280);
            _actionButton1.frame = CGRectMake(20, 320, 120, 40);
            _actionButton2.frame = CGRectMake(20, 400, 120, 40);
            _actionButton3.frame = CGRectMake(180, 320, 120, 40);
            _actionButton4.frame = CGRectMake(180, 400, 120, 40);
        } else {
            _bigButton.frame = CGRectMake(20, 20, 260, 260);
            _actionButton1.frame = CGRectMake(320, 20, 120, 40);
            _actionButton2.frame = CGRectMake(320, 90, 120, 40);
            _actionButton3.frame = CGRectMake(320, 160, 120, 40);
            _actionButton4.frame = CGRectMake(320, 230, 120, 40);
    } }
    
    So, this code access the ivars directly. Which from what I read should never be done, unless we are impliementing our getter or setter, right?

    So I tweaked the code to my understanding:

    Code:
    -(void)doLayoutForOrientation:(UIInterfaceOrientation)orientation
    {
    
        if (UIInterfaceOrientationIsPortrait(orientation)){
    
            self.bigButton.frame = CGRectMake(20, 20, 280, 280);
            self.actionButton1.frame = CGRectMake(20, 320, 120, 40);
            self.actionButton2.frame = CGRectMake(20, 400, 120, 40);
            self.actionButton3.frame = CGRectMake(180, 320, 120, 40);
            self.actionButton4.frame = CGRectMake(180, 400, 120, 40);
        }else{
    
            self.bigButton.frame = CGRectMake(20, 20, 260, 260);
            self.actionButton1.frame = CGRectMake(320, 20, 120, 40);
            self.actionButton2.frame = CGRectMake(320, 90, 120, 40);
            self.actionButton3.frame = CGRectMake(320, 160, 120, 40);
            self.actionButton4.frame = CGRectMake(320, 230, 120, 40);
        }
    }
    
    
    Here I am accessing the ivars using
    Code:
     self.propertyName. 
    Of course, both versions work. My question is which way is "more correct" here and why?

    Thanks.
     
  2. dantastic macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #2
    This thing with ARC is a bit of a dangerous thing when learning if you want to learn the right way. When you synthesize your bigButton getters and setters are created in the background and they looks pretty much like this
    Code:
    - (void) setBigButton:(UIButton *) bigButton {
    	
    	if (_bigButton == bigButton) {
    		return;
    	}
    	
    	[_bigButton release];
    	_bigButton = [bigButton retain];
    }
    
    - (UIButton *) bigButton {
    	
    	return _bigButton;
    }
    In many cases the getter would be lazy initialized such as

    Code:
    - (NSString *) myString {
    
    	if (!_myString {
    		_myString = @"Hello World";
    	}
    
    	return _myString;
    }
    
    So to answer your question, in the piece of code you showed you can use either, it really does not matter. If you are referencing outlets in a nib you can reference the ivar directly throughout your code as it is already initialized as the nib is loaded.

    The really important bit is the setter, you must not set an ivar directly as you can see from the above setter. In terms of getting, you should know your code well enough to know if you need to use the getter or if you can accress the ivar directly.

    Personally I only use the self. where I need to, everywhere else I use the ivar directly. This is personal preference, shortly someone will say I'm wrong in doing this! :)
     
  3. Tander thread starter macrumors 6502a

    Tander

    Joined:
    Oct 21, 2011
    Location:
    Johannesburg, South Africa
    #3
    Right I see.

    So it could be a little careless if we access the ivars using self. when they haven't been initialised properly yet?

    In the case of our .nib file - that's not an issue as they're always properly initialised before we get to the code?

    Since viewDidLoad comes first - right?
     
  4. dantastic macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #4
    The other way around - self. is the prudent approach. But for thing you know are initlialized it is perfectly fine to access by ivar direct.
     
  5. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #5

    Actually, things are different with ARC.

    Before ARC, you either needed to manually manage the memory management for objects everywhere (releasing any old object in an iVar before replacing it, retaining the new one, and releasing it when you were done with it) or using retained properties, and always using the getter/setter (except in very special circumstances like writing custom getter/setter code.)

    With ARC, memory management happens for you, under the covers, with or without properties. WIthout properties, an instance variable that's declared as strong (the default) acts like a retain property. It takes ownership of any object that you store into it, and releases that ownership when you store something else there.

    The "always use the property" rule mostly pre-dates ARC.

    You still need to decide which iVars should be strong and which should be weak. Two objects that have strong (owning) references to each other will create a "retain cycle" and a likely memory leak. The convention is for "back pointers" like delegates, back pointers in linked lists, etc, to be weak references. The same goes for outlets. Those should be weak, so the superview is what owns the object. That way if you remove a view from it's superview, it gets released and discarded.

    Since the advent of ARC I tend to use more iVars and less properties. I use properties when I want to access a value from outside an object, or if I need custom behavior in the setter/getter, but otherwise I use iVars.

    I ALWAYS use properties to access the iVars of other objects. I treat the other object's iVars as private. That way the property becomes the public interface.

    Properties do have a non-zero cost to them. Every time you use a getter or a setter, you're making a method call. That is slightly slower than directly accessing the variable in memory. For most things the difference is too small to matter, but if you're doing something millions of times, like processing every pixel in an image, it can make a big difference in performance.
     

Share This Page