IBOutlets, Variables, and Instance Properties: Best Practices

Today I have done all kinds of research on best practices regarding declaring IBOutlets and instance variables, managing them, using the right accessories and their proper release. I have a lot there, but I have some niche questions that I hope someone can advise on the best practice. I will format them as code and comment on the questions to make it easier to understand. I excluded some obvious parts that, in my opinion, were not relevant, and we can safely assume that they work (for example, material in front of the processor, @end, necessary implementation methods, etc.).

Myviewcontroller.h

@class OtherViewController; @interface MyViewController : UIViewController { NSString *_myString; BOOL _myBOOL; } // The first two properties aren't declared in the interface // above as per best practices when compiling with LLVM 2.0 @property (nonatomic, retain) OtherViewController *otherViewController; @property (nonatomic, retain) UIButton *myButton; @property (nonatomic, copy) NSString *myString; @property (readwrite) BOOL myBOOL; 

MyViewController.m

 @implementation MyViewController // Synthesizing IBOutlets on iOS will cause them to be // retained when they are created by the nib @synthesize otherViewController; @synthesize myButton; // Assign instance variables so as to force compiler // warnings when not using self.variable @synthesize myString = _myString; @synthesize myBOOL = _myBOOL; - (void)viewDidLoad { // QUESTIONS: // 1. Ignoring convenience methods, can you still alloc and init in dot notation // even when it being properly synthesized? self.myString = [[NSString alloc] initWithString:@"myString"]; self.myString = existingNSStringObject; // 2. Should you always call methods for IBOutlets and instance variables using dot notation? // Is there any difference seeing as these aren't directly invoking setters/getters? [self.myButton setText:self.myString]; [myButton setText:self.myString]; [self.otherViewController.view addSubview:mySubview]; [otherViewController.view addSubview:mySubview]; [self.myButton setAlpha:0.1f]; [myButton setAlpha:0.1f]; self.myButton.alpha = 0.1f; myButton.alpha = 0.1f; // 3. How fussy are scalar variables in terms of getters and setters, // given that there is a @synthesize declaration for them? self.myBOOL = YES; myBOOL = NO; if(self.myBOOL) { ... } if(myBOOL) { ... } // 4. On instantiation of new view controllers from NIBs, should you use // dot notation? (I haven't been doing this previously). otherViewController = [[OtherViewController alloc] initWithNibName:@"OtherView" bundle:nil]; self.otherViewController = [[OtherViewController alloc] ... ] } - (void)viewDidUnload { // 5. Best practice states that you nil-value retained IBOutlets in viewDidUnload // Should you also nil-value the other instance variables in here? self.otherViewController = nil; self.myButton = nil; self.myString = nil; } - (void)dealloc { [otherViewController release]; [myButton release]; [_myString release]; } 
+7
source share
3 answers

1) You misunderstood @synthesize a bit. @synthesize does nothing with the object. It only tells the compiler to generate getter and setter methods according to the parameters used in the @property declaration

// Synthesis of IBOutlets on iOS will make them be

// saved when they are created nib

outputs are not saved (outputs are only notifications for the interface constructor and do not affect the code), objects are saved when the setter generated by @ is synthesized. When the tip loads, the boot system calls your generated setter.

2) The decision on whether to use accessories in object C is no different from deciding on the use of access devices in any object-oriented language. It is a choice of style, need and reliability. The fact that the accessor acts as an IBOutlet does not matter.

But in the C lens, I would advise you NOT to use accessors in two places: dealloc and inside the var access method itself.

And if you use Accessors in init, then you need to be careful about your accounts.

 self.myString = [[NSString alloc] initWithString:@"myString"]; 

This line is a memory leak. Using your accessory for copying saves the object, so you must let it go after creation.

3) Not sure what you mean by fussy. Perhaps the answer is 2)

4) See 2) and be careful in managing memory. If you call alloc / init, you are now responsible for freeing the object - this is completely independent of the save / releases used by accessories and dealloc.

5) No, you should not ignore other instance variables in viewDidUnload. It is expected that your controller will retain its state even if the view disappears. viewDidUnload is intended only for cleaning objects with potentially dangerous memory when the controller view is not currently displayed.

Consider a navigation controller. View controller 1 is on the stack, and then view controller 2 by clicking and is now visible. If the memory conditions decrease, the system may try to unload the view of controller 1 and then call viewDidUnload.

Then popping view controller 2 will not create the View 1 controller object again, but it will load the view of controller 1 and call viewDidLoad.

Re comments

2) That's for sure - you can use the convenience constructor or release it immediately after allocation / initialization and assignment or release before the block exits or automatically alerts. You mainly choose a style question (although some of them will argue with an abstract, but not me!)

3) There are accessors for scalars - you created some in your code

 @property (readwrite) BOOL myBOOL; 

This creates the myBOOL and setMyBOOL methods for your class.

Remember that there is nothing special about point notation. This is just a convenience, and when the code is compiled, myObject.property is exactly equivalent to [the myObject property], and myObject.property = x is exactly equivalent to [myObject setProperty: x]. Using dot notation is just a style choice.

+3
source

I always declare and explicitly set the class variable of the property instance. This works a little more, but, in my opinion, it is worthwhile to clearly distinguish between variables and properties and immediately see which instance variables have a class. I also prefix the instance variable names, so the compiler complains if I accidentally enter property instead of object.property .

  • A call to alloc / init creates an object with saving the number 1. Your synthesized property will also save the object, causing a memory leak when it is released (unless you release your property immediately after, but this bad form), It is better to select / and release the object on a separate line .

  • The dot notation actually matches the call to [self setObject:obj] . Without using dot notation, it directly accesses the main instance variable. In init and dealloc always access the instance variable directly, because access methods can include additional operations (for example, notifications about compliance with a key value) that are not valid when creating or destroying an object. All other times use synthesized access methods. Even if you are not doing anything right now, you can later override these methods to change what happens when the variable is set.

  • Scalars work the same way, but you don’t need to worry so much about memory.

  • Access to synthesized access methods, other access directly to the instance variable. See Questions one and two again and be careful with memory leaks!

  • The view controller may again be clicked on the screen, in which case your viewDidLoad method will be called a second time. If you set the initial values ​​in viewDidLoad, go and set your properties to nil here. This makes sense for properties that use a lot of memory and will not affect the state of the view. On the other hand, if you want the property to persist until you are sure that it is no longer needed, create it in your init method and do not release it until dealloc .

+3
source
  • Point symbols and brackets are denoted approximately identically.
  • In self.myVariable you get access to the receiver of the instance variable property myVariable , and through myVariable you get access to the local variable. This is not the same thing.
  • You can configure setters and recipients by overriding methods and defining some specific conditions for them.
  • See first answer (parentheses are preferred - a better understanding of the code)
  • Better make a separate method.

how

 - (void) releaseOutlets { self.firstOutlet = nil; self.mySecondOutlet = nil; …………………… self.myLastOutlet = nil; } 

and then call this method in both the viewDidUnload and dealloc methods.

Hope this helps!

+1
source

All Articles