Does Objective-C auto generate setter and getter? - objective-c

I am calling a method from other class, as below
#property (nonatomic,strong) CalculatorModel *calculatorModel;
double result = [self.calculatorModel result:operator];
however this method doesn't received the message from the caller. Until I wrote the getter my self
- (CalculatorModel*)calculatorModel {
if (!_calculatorModel) _calculatorModel = [[CalculatorModel alloc]init ];
return _calculatorModel;
}
and it works. why, I remember once you did #property, the Objective-C will generate setter and getter automatically. Am I wrong?
Thanks
updated:

Does Objective-C auto generate setter and getter?
Well, rather the compiler, but yes, recent versions of Clang have this feature. You don't need to manually synthesize properties anymore.

You are right. However you still have to initialize the property by using [[Class alloc] init]. Like we set the property for NSMutableArray, #property (nonatomic, strong) NSMutableArray *anArray; and before you are using anArray you have to init it as _anArray = [[NSMutableArray alloc] initWithCapacity:10];
the - (CalculatorModel*)calculatorModel method is called Lazy instantiation, which will take over the [[Class alloc] init] job before calling, this will give help on both performance and memory control.

Seems like You don't need to manually synthesize properties anymore from xCode4.5.The IDE will help you do it.But terrible thing is if you open your project on xCode4.3 or xCode4.4, it will not work,lots of warning will appear,then you should add the code by yourself .

Related

Releasing synthesized properties in objective C

I'm a little confused about synthesized properties. I have an array that I want to be accessible from other classes so this is my code:
MyClass.h
#interface MyClass : CCLayer {
NSMutableArray *myArray;
}
#property (nonatomic, retain) NSMutableArray *myArray;
MyClass.m
#synthesize myArray;
-(id)init
{
myArray = [[NSMutableArray alloc] init];
}
-(void)dealloc
{
[myArray release];
myArray = nil;
}
I am a little confused now..is myArray the same as self.myArray? Do I have to release self.myArray as well? Thanks.
You declared your property as retain, it means that it will be retained automatically if you will set is using self.myArray. So, you can simply create autoreleased array in your init method and set it as
myArray = [NSMutableArray array];
self.myArray = myArray;
in this case you are not have to release it in the dealloc method or anything else. And as dasblinkenlight said you have to use #synthesize if you want to be sure that self.myArray is linked with your myArray instance.
Assuming that your #synthesize directive looks like this
#synthesize myArray;
you do not need to do anything in addition to what you are already doing: your property stores its value in the instance variable of the same name.
EDITED : Removed the alternative that suggests setting self.myArray in the dealloc method.
Yes you do, the best method is to set the property nil and release your variable.
-(void)dealloc{
self.myArray = nil;
[myArray release];
[super dealloc];
}
The code you provided is not really correct.
No, accessing a property and accessing the field itself are not the same.
My guess is that you are looking at old obj C examples where it was necessary to create the field with the property.
You also have no #synthesize directive in your code.
In current obj C code there is no need to declare a field to back the property, the field and the getter and setter will be autosynthesized (generated by the compiler) for you.
The default field generation is the name of your property with an underscore in front of it.
When you access the field directly via _myArray you will bypass any retain or release code that is contained in the generated getter/setter and have to manually manage memory in a non ARC project.
So to sum up, you dont need your field definition, and you dont need a synthesize directive.
You access your field directly with _myArray, or the property via self.myArray
They are not the same thing, one goes through generated code which obeys your property definition as to retain, assign, copy and accessing the field directly bypasses these semantics altogether.
If you define your property as retain you will need to release it in dealloc
You can use either
self.myArray = nil;
which will handle the release or
[_myArray release];
_myArray = nil;
Although someone in a previous post said setting the property to nil in dealloc might cause a problem Ive never seen it actually happen in my apps, ymmv
To answer your questions:
I am a little confused now..is myArray the same as self.myArray?
Yes, but no. Both point to the same object, the same area in memory. If you read myArray or self.myArray, they're identical in behavior minus the message send overhead for self.myArray.
However if you assign to myArray, the object will not be retained. It will only be retained if you assign to self.myArray.
Do I have to release self.myArray as well?
No.
You can also choose to either release or set the property to nil. As long as the property is #synthesize'd both examples do the same thing:
-(void) dealloc
{
[super dealloc];
[myArray release];
}
-(void) dealloc
{
[super dealloc];
self.myArray = nil;
}
See here for a discussion of the pros/cons to each approach.
From the question I think you're the developer who should really be using ARC. You'll have less to learn and fewer technical problems down the road. I can't understate how important using ARC is in these days, specifically if you don't have much ObjC experience. Read this how to enable ARC for cocos2d or just use Kobold2D to be able to work with an ARC-enabled cocos2d out of the box.

Why in Objective-C and iOS, [[NSMutableArray alloc] init] gave warning but NSMutableArray.new didn't?

I have a property for my MainView class, arr
#property NSMutableArray *arr;
In my ViewController.m, inside viewDidLoad, if I use
MainView *mainView = (MainView *) self.view;
mainView.arr = [[NSMutableArray alloc] init];
It compiled, but gave a warning of "Assigning retained object to unsafe property; object will be released after assignment". But if I change the second line above to
mainView.arr = NSMutableArray.new;
then there will be no warning. I thought alloc init is the same as new? Why does the first version give warning and actually is it dangerous or can it be made so there is no warning?
If you use [NSMutableArray new] syntax, you will see the warning, so it's not an issue that your problem went away, but rather that your nonstandard syntax of NSMutableArray.new didn't generate the warning. The problem is that your property is defaulting to an unsafe_unretained, and whenever you assign a retained object to the unsafe_unretained object, ARC will immediately release it for you. Just try adding an object to your array and then NSLog'ing it, and you'll see the EXC_BAD_ACCESS which illustrates the problem. Change your property to:
#property (strong, nonatomic) NSMutableArray *arr;
and your problem goes away.
Again, the lack of warning from your nonstandard usage of NSMutableArray.new is not an indication that there's no problem, but rather that the compiler just didn't generate the warning for you. (Frankly, I'm really surprised that the dot syntax for invoking a method worked at all. The dot notation is generally used for accessing properties, not for invoking methods.) Use the [NSMutableArray new] syntax if you really want to use new. But the preferred syntax is really [[NSMutableArray alloc] init].
Heed the warnings.
You must tell type of property. For example:
#property (retain) NSMutableArray *arr;
See property type in documentation.
I think that the reason you're getting the warning is because arr is not a strong reference. If you try "#property (strong, nonatomic) NSMutableArray *arr;", the warning will go away.
P.S. "(strong, nonatomic)" is the approach to use when employing automatic reference counting (ARC). I too am surprised that NSMutableArray.new worked. I think it's better to use "[[NSMutableArray alloc] init]". That way, Xcode will tell you if the class you are instantiating has a more appropriate, specialty initializer (e.g. "initWithFrame:").

When setting a class property inside a method, does it need to be released?

I'm very new to Objective-C. I kept on getting a runtime error when trying to set a class variable inside a method and then releasing it. I realized the only way to get rid of the runtime error is not to release it.
So if a class variable is set inside a method, the temp method variable doesn't need to be released?
My code looked something like this:
- (void)initData{
NSMutableArray *tmpData = [[NSMutableArray alloc] init];
self.data = tmpData;
[tmpData release];
}
What you've got is correct if the data property is declared with a "retain" or "copy" attribute. If data is declared with an "assign" attribute (the default), what you've got will cause a crash. The solution in that case is to use retain (or possibly copy) for data:
#property (nonatomic, retain) NSMutableArray *data;

Clarification on when to release pointers after allocating

In my last question (here), I had an issue where I was getting an EXC_BAD_ACCESS because I was releasing the variable I had just allocated:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
should have been
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
However, stack is a retained property of my class. It's declared like so:
#interface StateStack ()
#property (nonatomic, retain) NSMutableArray* stack;
#end
I was under the impression that when you assign a 'retain' variable, it automatically increments the retainCount of the object. So you are supposed to start by releasing your pointer (as here).
Why are these two cases different? Thanks!
Because you had to assign the property, not the instance variable. When you assign to the property it's going to retain the variable again and then you're not going to have the issue. Here's how your code should have been:
NSMutableArray* s = [[NSMutableArray alloc] init];
self.stack = s;
[s release];
This way you're not assigning to the variable, but using the property (that's, in fact, a method). If you did not release in this case then you'd have a memory leak in your code.
When you did stack = s you assigned directly to the instance variable and the array was never retained.
There is no such thing as a "retain variable". It's a retain property — meaning the setter method behind the property retains the new value and releases the old one. But assigning to a variable just assigns. In fact, the reason people generally recommend assigning directly to the instance variable in init is specifically so that it doesn't go through the setter, because the setter could conceivably have side effects you don't want in init (when your object isn't fully constructed yet).
Note: I'm talking about normal memory-management rules here. This is all different if you're using ARC. But I assume you would have mentioned if you were.
self.stack and stack are two completely different things. When you use stack, you are accessing an instance variable, not a property. This means that your accessor methods aren't called, which means automatic memory management isn't used. This is why you shouldn't release s in your example.
If you used self.stack instead, then you would be using a property. The compiler will treat self.stack = value exactly the same as [self setStack:value], and self.stack the same as [self stack]. Since accessors are being used, memory management will be taken care of to match the way you defined your property, and you should release a value after assigning it.
Maurício has the right answer: be sure to assign to the property to gain the benefits of #property. To clarify the point somewhat, try using code like this:
#interface StateStack : NSObject {
NSArray *_stack;
}
#property (nonatomic,retain) NSMutableArray *stack;
#end
#implementation StateStack
#synthesize stack=_stack;
#end
Now, if you try:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
You'll get an error, which will mean you tried to set the ivar rather than the property as intended. This mismatch between ivar name and property name is against Apple's recommendations, but it's a fine way to help you develop the habit of using property assignment when you intend to do so.

Retain on NSManagedObject crashes

I'm experiencing a weird problem when trying to use an NSManagedObject subclass. I've got code that looks something like this:
[self.navigationController popViewControllerAnimated:NO];
MyController *myController = [[MyController alloc] init];
myController.managedObject = managedObject;
Pretty simple right? But for some reason it crashes in the synthesized function for setting "managedObject". I tried replacing the function with something like this:
- (void) SetManagedObject:(NSManagedObjectSubClass*) obj
{
if ( managedObject )
[managedObject release];
managedObject = obj;
--> [managedObject retain];
}
And that crashes on the retain call... I'm stumped and don't know where to start debugging this.
There are several problems with your code:
If you provide a custom setter, your property is not a synthesized property (remove SetManagedObject: and use the #synthesized directive instead)
Your custom setter is releasing the object before it retains it. So managedObject might have been freed when you send the retain message (That's the crasher)
SetManagedObject: has the wrong case. Use setManagedObject: if you decide to provide a custom setter.
Don't use NS as prefix for your custom subclasses (NS is used by Apple).
I'd use a synthesized property. Remove your setter code, declare #property(retain) XYManagedObjectSubClass managedObject; in your .h file and use #synthesize in the implementation.