I a few simple questions to make sure I am using properties right in my application. I read a lot online but it is still unclear. Thanks a lot for any help or suggestions.
(1) I am not quite sure that the statement does, and why is it needed.
#synthesize personName = _personName;
Why do you need the _personName variable? What is the benefit of doing that as opposed to just creating a property and synthesizing that variable personName.
#property (nonatomic, retain) NSString *personName;
(2) In my application should I be accessing the property variable self.personName or use the _personName variable. I believe the self.personName is correct by then again why is the _personName even there?
(3) Also I am a little confused to which variable I should release in dealloc() and which variable should I set to nil in viewDidLoad(). I also do not know if any changes should be made to the didReceiveMemoryWarning() method.
#interface ViewController : UIViewController
{
NSString *_personName;
}
#property (nonatomic, retain) NSString *personName;
#end
#implementation ViewController
#synthesize personName = _personName;
- (void)viewDidLoad
{
[super viewDidLoad];
self.personName = [[NSString alloc] initWithString:#"John Doe"];
NSLog(#"Name = %#", self.personName);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)dealloc
{
[super dealloc];
}
#end
#synthesize personName = _personName;
That statement creates the accessor methods for the personName property. You've specified that the accessors should use an instance variable named _personName. If you just had #synthesize personName;, the accessors would use personName as the instance variable instead.
You should usually use the accessor methods, as in self.personName or somePerson.personName or somePerson.personName = #"Joe";. If you don't care what the name of the ivar that backs up the personName property, you don't need to specify it.
Use the accessors in -viewDidLoad, as in: self.personName = nil;. Same for -didReceiveMemoryWarning:. Whether to use the ivar or property in -dealloc is debatable, and to some degree a matter of taste. The main concern with using the property accessors in -dealloc is that it can cause problems if your class is subclassed and the accessors are overridden. Often, you don't need to worry about that because you know that your class won't be subclassed.
Setting an ivar to nil after releasing is also debatable. Many people feel that it's good style to do so, others feel like it's a waste of time. Use your best judgement. It's certainly not necessary, but rather something that some feel is a matter of good housekeeping.
Related
I have few questions to ask about the following class
#import <Cocoa/Cocoa.h>
#interface SomeObject {
NSString *title;
}
#property (retain) NSString *title;
#end
implementation SomeObject
#synthesize title;
-(id)init {
if (self=[super init])
{
self.title=[NSString stringWithFormat:#"allyouneed"];
}
return self;
}
-(void)testMethod{
self.title=[[NSString alloc] init] ;
}
-(void)dealloc {
self.title=nil;
[super dealloc];
}
In the .h file do we need to declare the title and sub when we add the property. is it not enough to add the #property (retain) NSString *title; line.
2.Do i need to autorelease both assignment to title in the init and testMethod. if So why?
Can some one explain these things to me.
1-
You don't need to declare the iVar in the header. You might also use
#synthesize myVar = _myVar;
if you want to go for a different iVar name
2-
Declaring a property "retain" means that every time you assign the property with a new object, it automatically releases the previous object and retain the new one.
Therefore, if you use a convenience method like stringwithFormat, the property will retain that object for you.
If you want to use alloc-init, for me the best way to do is:
NSString *str = [NSString alloc] init];
self.title = str;
[str release];
Besides, it is right to assign nil to the property in the dealloc because the property will release the object it has, and it calls retain on nil which doesn't do anything
1.No need to declare title in .h, declaring property is enough.
2.when you are using self.title in init, you do not have to autorelease it.But when you initialize it in testMethod, you need to autorelease it because you have declare the property as retain.And do not forget to release title in dealloc.
you don't need to add as it is done automatically (Since Xcode 4 I guess).
in init- you don't as it already returns an autoreleased object..
where as in testMethod you need to since you are allocating it..
you always have to release any object which you create using alloc , copy or new .... AMEN.. :)
Be aware it is not considered a good practice to use accessor methods in initializer methods and dealloc method. Do check out this answer: Why shouldn't I use Objective C 2.0 accessors in init/dealloc?
Also in Apple's memory management guide: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html
I have en error that I suspect could be the compiler... I'm not an expert myself, but I checked some other code with the exact same behavior with an expert and we couldn't figure it out.
I setup a property as such:
#interface aViewController ()
#property (nonatomic, strong) NSArray *listOfTitles;
#end
#implementation aViewController
#synthesize listOfTitles = _listOfTitles;
- (NSArray *)listOfTitles
{
if (!_listOfTitles)
_listOfTitles = [NSArray arrayWithObjects:#"first", #"second", #"third", #"fourth", nil];
return _listOfTitles;
}
However, the app crashes (the array would be more complex and serve to setup textLabel.text properties on UITableViewCell).
What's bothering me, it's that the NSArray always have an invalid address (0x00000001). What am I missing? Isn't this the proper way to do lazy instantiating?
Like I mentionned, I experienced the exact same thing (property instantiated with 0x00000001 ) with other classes, in other projects. That's why I'm suspecting the compiler to be the issue. But really, I'm all ears for solutions!...
The most obvious solution is to set the ivar to nil in your init function.
-(id)init{
if (self = [super init]){
_listOfTitles = nil;
}
}
The real question is why isn't this being done for you, since all ivars should be initialized to nil. I suspect it has something to do with the property being declared in the .m file. Either way it will cause no harm to nil out the ivar yourself.
1- Is these anything wrong with the way
i am deallocing the object?
2- Does my dealloc override the dealloc
for NSManagedObject?
3- Do i need to dealloc super even
though my object is an
NSManagedObject type and core data ia
responsible for it?
#interface MyClass : NSManagedObject
#property (nonatomic, retain) NSString *coreDataString;
#property (nonatomic, retain) NSNumber *coreDataNumber;
#property (nonatomic, retain) CoolObject *coolObject;
#end
.
#implementation MyClass
#dynamic coreDataString;
#dynamic coreDataNumber;
#synthesize coolObject;
- (void)dealloc
{
[self.coolObject release];
}
#end
Yes, you are not calling [super dealloc].
Yes.
Yes, you must always call [super dealloc] at the end of your dealloc method. Otherwise memory will not be freed correctly.
You should call release on the member variable directly instead of using the property. You also should still call the super dealloc. So your dealloc would look like this:
- (void)dealloc
{
[coolObject release];
coolObject = nil;
[super dealloc];
}
Otherwise, you can set the property to nil which will automatically release the local variable if necessary. The above way is preferred so you don't accidentally run a complicated function that could be overriding the property's setter.
You should always call [super dealloc] in the dealloc method. But in subclasses of NSManagedObject you should never use the dealloc method at all. use - (void)didTurnIntoFault instead.
You are overriding the parents - (void)dealloc method. When you override a parent object's method, the parent's method is never called until you explicitly call the super's method. In your case, the parent's - (void)dealloc is not called. To fix this, you must call [super dealloc] to ensure that the parent's instance variables are deallocated too.
I'm still a little confused on this.
I'm creating an object programmatically in Xcode, let's say a UILabel, which is also going to be a class wide property.
When is the proper time to release the object, in the method in which it is created, or in the dealloc method like normal IBOutlet objects?
Thanks.
This depends on whether your property is set to retain the value or not. Usually you want the accessors (generated by #synthesize) to handle the retain/release when the property is set to a new value. You specify such a property like this:
MyController.h
#interface MyController : UIViewController {
UILabel *myLabel;
}
#property (nonatomic, retain) UILabel *myLabel;
#end
You can then use #synthesize to generate the default getters and setters. The default setter for a 'retain' property will release the current value and retain the new value. However, nothing is done for you in dealloc. Meaning, that when the controller is destroyed, your reference to you label will leak since release will not be called. For this reason, you need call release on all your 'retain' properties in dealloc, like this:
MyController.m
#implementation MyController
#synthesize myLabel;
-(void) dealloc {
self.myLabel = nil;
[super dealloc];
}
#end
Notice that in this case, self.myLabel = nil is almost equivalent to calling [myLabel release] since the setter will call release on the existing value and then call retain on the new value. Since the new value is nil, calling [nil retain] has no effect. I prefer to nil instead of releasing since you are also setting the ivar to nil and avoids dangling pointers.
When you create a property like this programmatically as opposed to from Interface Builder, you don't need to mark it with IBOutlet. In the cases where you do create a control using IB, you should nil all of your IBOutlet references in viewDidUnload. This is because your control could be deallocated along with the view if it wasn't retained. Referencing it afterwards will crash the app so it's a good practice to nil them, like this:
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.myIBLabel = nil;
}
Another common mistake that happens when using properties is to omit the 'self' part. If you do not use the self.myIBLabel notation, you are bipassing the getter and setter and working with the ivar directly. This will NOT retain/release the object.
You should release it in the dealloc method, although that depends how you're creating your class property.
If you release it in the method in which you create it, and then use it in some other part of your class (which, since you're making the UILabel a class wide property, I assume you are), you will get a bad access when you try to modify it later on. Note that if you're using a retained property you need to take that into account, in which case you might release the label (because you'll have created it and assigned it to your class property, which will retain it again).
Here's a typical example:
- (void) someMethod {
UILabel *myLabel = [[UILabel alloc] initWithFrame:myFrame];
self.textLabel = myLabel;
[myLabel release];
}
- (void) dealloc {
[textLabel release];
}
In this example:
#interface something : something
{
NSString *saveString;
}
-(void)saveStringForLater:(NSString*)myString
{
//do stuff with myString
...
//then save it for later
saveString = myString;
}
-(void)someOtherTimeInFuture
{
//do stuff with saveString
...
}
So given the above, my questions are:
1) Is this safe/proper way of doing this?
2) Will I need to worry about releasing saveString?
3) Should I be copying the string instead of just saving the pointer?
Excuse my ignorance as I am fairly new to Obj-C but have a C++ and C# background.
Thanks!
This is what #properties are for. They manage getter and setter code for you, so you don't have to think about these questions.
.h
#interface MyClass : NSObject
{
NSString *myString;
}
#property (nonatomic, retain) NSString *myString;
#end
.m
#implementation MyClass
#synthesize myString;
-(void)dealloc
{
[myString release];
[super dealloc];
}
#end
With those things in place, you can now talk about self.myString and not worry about memory. When you assign to it it'll do a retain. If you assign again, it'll release the first object and retain the new one. And then it'll stick around retained until your viewcontroller unloads.
You can by all means accomplish this same end with an iVar (which is what you're doing in your code sample), but then memory management is yours to handle, and it can be a bit fiddly. Best to use the #property system to create appropriately memory-managing setter code.
You have 3 optins,
Copy - should be using if the string can change or when getting called from a code you have on control of like third party
Retain - will increase the reference count to the object and will prevent destruction of it
In both these options you have to release it when you done with it
Last you can define a property with retain,copy attribute - this will let the system worry about managing it and probably the best option in most cases