original link address:http://www.raywenderlich.com/2712/using-properties-in-objective-c-tutorial
Copyright Notice: This article is by Http://www.cnblogs.com/andyque Translation, Welcome to reprint share. Please respect the author Labor, reproduced when the statement and the author of the blog link, thank you!
Tutorial:
This is the third tutorial on the iphone using OBJC, which is related to memory management.
In the first tutorial, we introduced the use of instance variables and reference counts to manage memory in objective-c.
In the second tutorial, we show you how to detect memory leaks, memory-related errors, use instruments, and other assistive tools.
In this third tutorial, which is also the last tutorial in this series, we will talk about the property of OBJC. We'll show you what the property is, how it works, what the rules are, and how you can use them to avoid most of the memory-related issues.
If you don't have a sample project for this tutorial series, you can download it here and we'll start with this project.
Retain Your Memory
Let's take a look at where the project needs to manage memory.
Currently Rootviewcontroller has two instance variables: _sushitypes, and _lastsushiselected.
@interface Rootviewcontroller:uitableviewcontroller { Nsarray * _sushitypes;
For _sushitypes, we created it in the Viewdidload Alloc/init way, and then we release it in Viewdidunload and Dealloc.
In Viewdidload. Afterwards, retain count is 1._sushitypes = [[Nsarray alloc] initwithobjects:@ ' California roll ', @ ' Tuna roll ', @ ' Salm On roll ", @" Unagi roll ", @" Philadelphia Roll ", @" Rainbow roll ", @" vegetable Roll ", @" Spider roll ", @" Shrimp Tempura Roll ", @" Cucumber roll ", @" yellowtail roll ", @" spicy Tuna Roll ", @" avocado roll ", @" Scallop roll ", Nil]; In Viewdidunload and Dealloc.
For _lastsushiselected, it is assigned when the user selects a row of Table view. It has release in two places. One is before the assignment, and the other is at Dealloc, see the following code:
This method is certainly feasible, but it requires you to think very carefully, every time you assign a variable to a value, you have to seriously consider the related memory problems. If you want to first release and then assign value Ah, want to retain Ah, in short, when the variable, a large number of projects, a variety of memory problems will follow.
So, next, I'll introduce you to an easy way---use the property to manage memory.
Move the chair and start coding.
If you are familiar with other programming languages, such as Java or C #, you are certainly not unfamiliar with the concepts of getters and setters. When you have a _sushitypes instance variable, you often need to let other classes of objects access the variable. However, if the direct use of the. Number way to access is not good, it destroys the principle of encapsulation, the implementation of the class to the outside, the master of programming said. Whether you believe it or not, I believe it anyway. :)
Therefore, you need a method called "Getsushitypes" (or just "sushitypes", so that you have less than 3 letters), and you need a method called "Setsushitypes". Use these two methods to access the instance variables of the class. This is a good coding habit, because you can change the name of the instance variable, but you will not affect other classes, because the interface does not change. Therefore, when we encode the code, we also need to encode more for the interface, less for the implementation of coding. Of course, there are other benefits of using getter and setter, you can use NSLog to output some content, so you know if anyone wants to spy on your private variables. The equivalent of a bodyguard.
As I said above, the corresponding getter and setter methods are defined for each instance variable, assuming that you want to have external access to the variable you define, you don't have to expose all the variables, so what is the meaning of encapsulation? This will make the memory management work easier. Next, let's see how I add getters and setters to these two variables.
First, in RootViewController.h, declare the following four methods:
Then, add its implementation at the bottom of the ROOTVIEWCONTROLLER.M:
-(Nsarray *) sushitypes { return _sushitypes;}-(void) Setsushitypes: (Nsarray *) sushitypes { [sushitypes retain ]; [_sushitypes release]; _sushitypes = Sushitypes;} -(NSString *) lastsushiselected { return _lastsushiselected;}-(void) setlastsushiselected: (NSString *) lastsushiselected { [lastsushiselected retain]; [_lastsushiselected release]; _lastsushiselected = lastsushiselected;}
The Getter method here is simple, and they simply return the respective variables.
The setter method, first the incoming parameter reference count plus 1, while the previous instance variable reference count minus 1, and then assign the input variable to the instance variable. (Translator: The wording here is not good enough to consider the self-assignment.) If you have a C + + string class, then write the copy constructor and assignment operators, it is important to consider the case of self-assignment, or it will be problematic. However, there is no problem with the author's wording. Because it first retain, after release. If you write the reverse, release first, then there is a problem. But if I think about self-assignment, then I don't have to think about this sequencing problem. Please refer to my original, OBJC @property detailed). In this way, the newly passed parameter is referenced by the instance variable, because it is the owner, so it conforms to the "who owns, who retain" principle.
You may wonder why the setter method calls Retain/release first and then assigns values, and the order cannot change. Of course, it must be a case of preventing self-assignment. If you still do not understand, then forget it, some things, one day you will understand. :)
Note, why do you want to add an underscore to the name of the instance variable? This allows the getter and setter methods to be named for easy access to the parameters. If our instance variable is named "Sushitypes", then the parameter name of our Setsushitypes function can no longer be "sushitypes", because that will cause the conflict, the compilation will error. Also, if you add an underscore to all the instance variables, and your colleague looks at your code, you'll know immediately that this is an instance variable that I use with caution. Of course, there are Apple's KVC and KVO mechanism, but also by the underscore to search for key, specifically I do not expand to say, read it.
Finally, note that the getter and setter methods here are not thread-safe, but, for this application, getter and setter methods will only be accessed within the main thread, so "thread safety is not safe", it's okay with us!
Now, you have the foundation, open the dry!
Now that you have a new getter and setter, modify the other code in this class and start using getter and setter. Let's start with the Sushitypes first:
in viewdidloadself.sushitypes = [[[Nsarray alloc] initwithobjects:@ ' California roll ', @ ' Tuna roll ', @ ' Salmon roll @ "Unagi Roll", @ "Philadelphia Roll", @ "Rainbow roll", @ "vegetable Roll", @ " Spider Roll", @ " Shrimp Tempura Roll ", @" Cucumber roll ", @" yellowtail roll ", @" spicy Tuna Roll ", @" avocado roll ", @" Scallop roll ",
Call "self.sushitypes = XXX" and call "[Self setsushitypes:xxx]", both of which are exactly equivalent--here's "." The number, for me, is "good".
Therefore, instead of accessing the _sushitypes instance variable directly, we use the setter to set its value. Recall that the setter adds 1 to the incoming logarithmic reference count. So now, we can't directly assign the value of Alloc/init to _sushitypes (because, when we go through the setter, that alloc/ The reference count for the variable created by Init would be 2, which would be problematic because it has only one owner, which means that in the future, only the owner will release it once. However, at this point the reference count is still 1 and will never be released. In other words, congratulations! The memory leaks! So, after calling Alloc/init, we also need to call autorelease.
In the Viewdidunload and Dealloc methods, we are no longer manually relase set to nil. We just need to use a setter, a design self.xxx = nil to get it done. If you use Self._sushitypes = nil, then the following code will be generated:
[Nil retain];
By the way, give you a wake up----some people may have told you, "never use getter or setter methods in Init or Dealloc methods." Why do they say that? Because, if you use a setter or getter in a alloc or Dealloc function, its subclasses rewrite the getter and setter, because all of the OBJC methods are "virtual methods", meaning they can be overridden. So when the subclass Init method calls [(self = [super init]), the parent class's Init method is first called, and the getter and setter are used, and the two methods are overwritten by you, and if you do something in the two covered methods, Then there will be a problem. Think carefully, why! Because, your sub-class has not been the beginning of the completion AH!!! You are still calling the "constructor" of the parent class, but you have already used the Subclass Method!!! However, I would like to say that I am here in violation of the principles provided by some people. Why, because I knew there might be side effects. Therefore, I do not easily reload the parent class getter or setter method. Our writing here can help us simplify the code. This is of course my personal opinion, for reference only.
Now, modify the code so that lastsushiselected also uses the setter method to assign values:
Wow---now, we're a lot less worried about memory issues, aren't we? You do not have the brains to think hard, where need retain Ah, which needs release AH. Here's the setter method, which in some way completes the memory management work for you.
A simple suggestion.
Therefore, writing getter and setter can make it easier for other classes to access instance variables within your class, and sometimes makes your memory management work easier.
But, after writing a bunch of these getter and setter methods over and over again, I'm going to freak out. Why aren't you crazy about Java? Because eclipse can be generated automatically. Why the C + + is not crazy, because, can be directly public. However, OBJC's @public is useless. Don't worry, no one will want to do repetitive things over and over again, so objc2.0 provides a new, very useful feature called @property, also called attributes.
We can comment out all the getter and setter methods we wrote earlier, just write the following two lines of code. Try it yourself, open RootViewController.h, and find the getter and setter declaration, and replace it with the following 2 lines of code:
This is the first step in using properties to create a property declaration.
The declaration of the property begins with the @property keyword, and then passes in the parentheses some parameters (such as Atomic/nonatomic/assign/copy/retain, etc.). Finally, you indicate the type and name of the property.
Propetyceov is a special keyword that tells the compiler how to generate getter and setter. Here, you specify two parameters, one is nonatomic, it is to tell the compiler, you do not have to worry about multithreading problems. Another one is Reatin, which tells the compiler to retain the setter arguments before passing them to the instance variable.
In other cases, you might want to use the "assign" parameter instead of Reatin, "assign" tells the compiler not to retain the incoming arguments. Or, sometimes you need to specify the "copy" parameter, which will copy the setter parameter before assigning it to the instance variable.
Well, to complete the use of the property, you first go to ROOTVIEWCONTROLLER.M, delete the getter and setter that was written before, and then add the following 2 lines of code at the top of the file:
The above code tells the compiler that you should generate the appropriate getter and setter methods for me based on the property and its parameters that I defined earlier. You use the @synthesize keyword to start, and then give the property name, (if the property name and the instance variable name is not the same), then must write on the = to sign, so that in the generation setter method, the compiler will know, the parameters to be assigned to whom. Remember to write the equals sign once!!! If the instance variable name and the property name are the same, then there is no need.
Just so much! Compile and run the code, which is OK and works well. But is it easier to understand compared to the pile of code you wrote earlier? It also causes the probability of errors to fall.
So far, you should use the Horn propety and how it works! Next, I'll give some suggestions for using the property.
General strategy
I would like to add some of these strategies in this tutorial, because it helps me to manage OBJC memory more easily and less prone to mistakes.
If you follow these rules, then, most of the time, you'll be away from memory-related problems. Of course, blindly recite these rules without understanding why there are these rules, why these rules can be useful. This is definitely not going to work! However, if you are a novice, you can follow the rules I have given you, so you will avoid a lot of memory-related errors, making your daily programming activities easier.
I will list these rules first, and then I will discuss them in detail.
- Properties are always defined for all instance variables.
- If it is a class, then set "retain" as the attribute parameter, otherwise, it will be set to assign.
- Whenever you create an instance of a class, you create it using the Alloc/init/autorelease method.
- At any time, when assigning a value to a variable, always use e "self.xxx = yyy". In other words, the property is used.
- For each of your instance variables, call "SELF.XXX = nil" inside the Dealloc function. If it's a outlet, then create it in Viewdidload, and remember to destroy it in Viewdidunload.
OK, let's start the discussion now!
Rule 1: By defining the property for each instance variable, you can have the compiler write memory-related code for you. The downside is that you break the encapsulation of your class, which can make your class more coupled, less maintainable, and more code-efficient.
Rule 2: By specifying the property parameters of the class as retain, you can access them at any time. You also keep a reference count of them, the memory will not be released, you are the owner, you are responsible for releasing.
Rule 3: When you create a class object, use the Alloc/init/autorelease idiom (just like the array you created Sushitypes earlier). In this case, the memory is automatically freed. If you want it to not be released, then in the instance variable that you want to assign, declare a retain in the argument that declares its property.
Rule 4: Whenever you assign a value to an instance variable, use the SELF.XXX syntax, so that when you assign a value to an instance variable, the old value is freed and the new variable value is retain. Note that some programmers worry about the side effects of using getter and setter functions inside the init and dealloc functions, but I don't think that's okay. As long as you are fully aware of the memory management rules, you will not do things like "override the parent's getter and setter" method in a subclass. Or, even if you actually need to rewrite the getter and setter of the parent class, you'll be very careful not to bring any side effects to the code in the process of rewriting, right?
Rule 5: In the Dealloc function, use "self.xxx = nil", so that the property can use its reference count minus 1. You don't have to forget about the viewdidunload!.
Simple strategies related to cocos2d
I know, now my blog has a large number of cocos2d fans, so the next tips are specially prepared for you!
The above-mentioned 5-point rule, for coocs2d, is a bit too strict, or directly said, too dead. Because, most of the time, our objects are added to the layer, and we define some instance variables within the class just to use it in methods other than the Init method. (In fact, many people like to define the tag, then specify a tag when Addchild, and then in other ways, use [self getchildbytag:xxx] to get the object you want.) Because there is a ccarray array in the layer, it is used to save all the child nodes of the layer, when the call Addchild, is actually called Ccarray AddObject method, so, add to the layer inside the child, its reference count will add 1.
So, to avoid defining some unnecessary property, here are some of my suggestions for cocos2d users:
- Never use property.
- Assign the sprite instance you created directly to the instance variable you defined.
- Because these sprites will be added to the current layer, coocs2d will automatically retain, making its reference count plus 1.
- When you remove an object from the current layer, remember to assign it the value nil.
I personally feel that using the above 4 methods to develop cocos2d game, feel good, simple, fast.
Note that if an object is not added to the current layer, such as action. Then, the above 4 rules will not be used. Let's go reatin/release manually.
Remember, the rules are dead, people are alive! As long as you understand the OBJC memory management rules, you can forget all the rules above!
Go?
Here is the full source code for this tutorial.
If you have any questions about property or memory management, please leave a message. Of course, if you look at what good, about memory management tips, tips, also welcome to come, share, under very grateful!
So far, the series of memory management tutorials on OBJC is all over. Sincerely hope that through the translation of these 3 tutorials, as well as my own writing of the tutorial, can help you out of OBJC memory management mire.
If you have any good comments or suggestions, please leave a message below. Please leave a message if you want to get a tutorial, or if you're not familiar with it. Although I am very busy (in fact, we are very busy:), but, I have time, still will try to meet the requirements of everyone.
Thank you again for your reading, see the next tutorial!
Raywenderlich written about memory management, third, about the use of attributes