I want to create an object called Note . Then I want to assign some values to it's fields and display them in the console to verify that all of this works properly.
Note.h
#import <Foundation/Foundation.h>
#interface Note : NSObject
{
NSNumber *position;
NSString *syllable;
}
#property(nonatomic, retain)NSNumber *position;
#property(nonatomic, retain)NSString *syllable;
#end
Note.m
#import "Note.h"
#implementation Note
#dynamic position;
#dynamic syllable;
#end
After this , in another class I want to assign some values to the fields .
-(void) configNote:(Note*)not
{
not = [Note alloc];
[not setPosition:[NSNumber numberWithInt:2]];
[not setSyllable:#"Twin-"];
}
.....
Note *note;
[self configNote:note];
NSLog(#" pos : %d syl : %# ",[[note position] integerValue],[note syllable]);
I tried to use #synthesize instead of #dynamic but still nothing changes . The reason of the error is : -[Note setPosition:]: unrecognized selector sent to instance 0x733d060
init your note and use custom init method to initialize ivars and change dynamic to synthesize
and for better use this init to initialize your varibales
- (id)initWithPosition:(NSNumber*)pos andSyllable:(NSString*)syl {
self = [super init];
if (self) {
self.position = pos;
self.syllable= syl;
}
return self;
}
Since your question is quite basic and fundamental you might want to check out this Tutorial on cocoadevcentral. It's very well done and teaches you some of the basics when dealing with objects.
Your problem is that you are passing the Note object pointer to configNote: by value rather than by reference. Inside of configNote: when you set not to a newly allocated Note object, you are actually setting the local variable not to that value. What your NSLog call outside of your configNote: object actually receives is original note value prior to the call to configObject:.
To get what I believe you desire, either more the Note object allocation outside of the configObject: method, or pass the Note object pointer to configObject: by reference.
If you are using ARC, try "strong" instead of "retain".
Related
When you have one object as a property of another object in Objective-C, does it automatically initialize when you use #synthesize?
does it automatically initialize when you use #synthesize?
Yes, it is initialized to nil (no actual object is allocated, however - this is pointer initialization in the C sense of the word, the init method is not called).
By the way, you don't even have to #synthesize to achieve this behavior - every instance variable, even those which don't have a corresponding #property, are automatically initialized either to nil (in case of objects), NULL (in case of other pointers) or 0 (in case of integers and floating-point numbers) by the Objective-C runtime.
Let's try it:
#interface TypicalObject : NSObject
#property (nonatomic) NSNumber *numberProperty;
#end
#implementation TypicalObject
#synthesize numberProperty;
#end
...
TypicalObject *object = [[TypicalObject alloc] init];
NSLog(#"object.numberProperty = %#", object.numberProperty);
The log statement yields:
object.numberProperty = (null)
So, no, properties do not auto-instantiate. All object instance variables begin as nil, however.
No. The #synthesize does not know how to initialize it. Simple -init?
You can allocate and initialize it in the -init… of the referring object.
You still have to init. Try using lazy initialization:
-(MyPropertyClass*)propertyName {
if(!propertyIvarName) {
_propertyIvarName = [[MyPropertyClass alloc] init];
}
return propertyIvarName;
}
or init the property in viewdidload
I have a singleton that I'd like to use to manage the onscreen animation of my views. Here's my.
#import <Foundation/Foundation.h>
#interface OAI_AnimationManager : NSObject {
NSMutableDictionary* sectionData;
}
#property (nonatomic, retain) NSMutableDictionary* sectionData;
+(OAI_AnimationManager* )sharedAnimationManager;
- (void) checkToggleStatus : (UIView* ) thisSection;
#end
.m file
#import "OAI_AnimationManager.h"
#implementation OAI_AnimationManager
#synthesize sectionData;
+(OAI_AnimationManager *)sharedAnimationManager {
static OAI_AnimationManager* sharedAnimationManager;
#synchronized(self) {
if (!sharedAnimationManager)
sharedAnimationManager = [[OAI_AnimationManager alloc] init];
return sharedAnimationManager;
}
}
- (void) checkToggleStatus : (UIView* ) thisSection {
//get the section data dictionary
NSLog(#"%#", sectionData);
}
#end
You'll see in the .h file I added a NSMutableDictionary and am using #property/#synthesize for it's getter and setter.
In my ViewController I instantiate the animation manager as well as a series of subclasses of UIView called Section. With each one I store the data (x/y w/h, title, etc.) in a dictionary and pass that to the dictionary delcared in animation manager. In the Section class I also instantiate animation manager and add a UITapGestureRecognizer which calls a method, which passes along which section was tapped to a method (checkToggleStatus) in animation manager.
As you can I see in the method I am just logging sectionData. Problem is I am getting null for the value.
Maybe my understanding of singletons is wrong. My assumption was the class would only be instantiated once, if it was already instantiated then that existing object would be returned.
I do need all the other Section classes data as if one animates others animate in response and I can get around it by passing the tapped Section to the animation manager and doing [[Section superview] subviews] and then looping and getting the data from each that way but it seems redundant since that data is available in the ViewController when they are created.
Am I doing something wrong in trying to transfer that data? Is there a better solution? I am open to suggestions and criticisms.
Thanks
h file
#interface OAI_AnimationManager : NSObject
#property (nonatomic, retain) NSMutableDictionary* sectionData;
+(OAI_AnimationManager* )sharedAnimationManager;
- (void) checkToggleStatus : (UIView* ) thisSection;
#end
m file
static OAI_AnimationManager* _sharedAnimationManager;
#implementation OAI_AnimationManager
#synthesize sectionData = _sectionData;
+(OAI_AnimationManager *)sharedAnimationManager {
#synchronized(self) {
if (!_sharedAnimationManager) {
_sharedAnimationManager = [[OAI_AnimationManager alloc] init];
}
}
return _sharedAnimationManager;
}
- (void) checkToggleStatus : (UIView* ) thisSection {
//get the section data dictionary
NSLog(#"%#", _sectionData);
}
#end
Notice I moved your sectionData variable from the header and moved it to the implementation file. A while back, they changed it to where you can synthesize properties and specify their instance variable names along side it... hence:
sectionData = _sectionData;
I also added and underscore to the instance variable... this is a universal convention for private variables and it also will throw a compile error now if you try to type just sectionData as you did in the return statement of checkToggleStatus:. Now you either have to type self.sectionData or _sectionData.
You didn't include the code that creates an instance of your dictionary but I bet you didn't set it as self.sectionData = [[NSDictionary alloc] init] which means it would not retain the value and you would get null the next time you called it. Classic memory management mistake... I know it well because I learned the hard way hehehe
I am using ARC.
This is my .h file
...
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, copy) NSString *title;
...
This is my .m file
....
#synthesize coordinate, title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
coordinate = c;
[self setTitle:t];
}
return self;
}
....
Is setting coordinate this way, the right way to do it? Given that I declare it as readonly, it seems like it is the only way to do it. What if I just use the default (i.e. readwrite), in this case, should I use the setter method [self setCoordinate] instead?
I could set the title by doing title = t as well. Compare to using the setter method, the result is the same, but what is the difference ?
Thanks! Wish I could accept all of your answers.
You're actually supposed to set ivars directly in an initializer method all the time. This is true whether or not you have a readonly or readwrite property. The documentation here even says so.
The reasoning behind this has to do with inheritance. If someone were to subclass your class and overwrite the setters for your properties such that they bypass the ivars you created (or do some other wacky thing), then suddenly your original implementation of your initializer method now no longer does what it is written to do. In particular, your initializer could end up creating an object with a weird state due to the subclass overriding your accessors. In the pre-ARC days, you could also end up with tricky (or just straight-up broken) memory situations when this sort of thing happens. The take-away message is: you should write initializers so that they will always create an object with a known valid state.
So (assuming you're using ARC) your initializer should actually be:
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
coordinate = c;
title = [t copy];
}
return self;
}
Personally, I prefer to synthesize ivars with a starting underscore to clarify when I'm using the property and when I'm accessing the ivar directly (LLVM 4.0 now does this to automatically synthesized properties as well).
#synthesize coordinate = _coordinate;
#synthesize title = _title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
_coordinate = c;
_title = [t copy];
}
return self;
}
1: As your code is now, yes, that is the right way to do it. If you weren't using ARC (assuming you are currently), you'd also want to retain the value to assert ownership. This will be done automatically under ARC. Keep in mind that that is not the only way of doing it; you could redeclare the property as readwrite in the class extension in the implementation file. This is a common practice which allows you to have the benefits of a readwrite property while having the property still be readonly to users of the class. Ex.
//MyClass.h
#interface MyClass : NSObject
#property (nonatomic, strong, readonly) NSNumber* number;
- (void) initWithNumber:(NSNumber*)number;
#end
//MyClass.m
#interface MyClass ()
#property (nonatomic, strong, readwrite) NSNumber* number;
#end
#implementation MyClass
//this changes the instance variable backing the property to _number.
#synthesize number = _number;
- (void) initWithNumber:(NSNumber*)number{
self = [super init];
if (self) {
self.number = number;
}
return self;
}
#end
At the end of the day, I'd say it's a good habit to use setters whenever you can to keep things KVO compliant and so that you always know when values change. For instance, if you have a custom UIView with a property that is reflected in its appearance, chances are you'd want to redisplay yourself when it changes. The easiest way to do this is to implement the setter yourself and call setNeedsDisplay after setting the value. You couldn't do that if you set the instance value backing the property directly; the user of the class would have to remember to call setneedsDisplay every time they set it, manually.
2: One goes through the setter method, giving you a way to know when a value is going to be set, while one sets a value to the instance variable backing the property. The setter method will always handle memory management in the way it was told to, while it's up to you to do things such as copying values for a copy setter if you assign directly to an instance variable, so that you maintain some consistent scheme. Going through setters sometimes, and not others can lead to some nasty bugs if you don't be careful. Never going through setters makes it hard to know when values change, making it near impossible to weed out invalid values. For instance, if you had an int property you wanted to limit to values in some range and someone passed in a value under the minimum limit, you'd probably want to set the property to the lowest possible value in the range. You can't do that without the value going through the setter first.
Yes, it is fine to set it like that. If you prefer to use a property all the time you can override the property to be read/write rather than read-only in a class extension. In Foo.m:
#interface Foo ()
#property (nonatomic) CLLocationCoordinate2D coordinate;
#end
#implementation Foo {
// ...
self.coordinate = c;
}
Setting the coordinate that way is correct, and is the only way to do it if you have declared the property readonly.
Setting the title using title = t is different than setting the title using [self setTitle:t]. If you directly assign to the instance variable, you will just retain the NSString instance that was passed as argument t. But if you using the accessor method, the accessor will ask the string to copy itself (because you declared the property copy). If the string you were given as argument t is actually an NSMutableString, then you will get an immutable copy of it. If the string you were given as argument t is already an immutable string, it will just return itself when asked for a copy.
self.coordinate = c;
is essentially compiled to be the same as calling
[self setCoordinate:c];
The difference between coordinate = c and [self setCoordinate:c]; is that the first is just setting a variable directly where as the second is calling a method.
The reason to be wary is that methods could potentially have side effects depending on how the implementation is written e.g. (stupid example)
- (void)setCoordinate:(CLLocationCoordinate2D)coordinate;
{
_coordinate = coordinate;
[self doSomethingCrazy];
}
I'm beginner in Objective C and Cocos2D
I read Features of use #property and #synthesize (cocos2d)
The comments were references to bugs in the memory. What are these bugs?
In my code I use:
//interface
{
CC_bla_bla *a;
}
#property(nonatomic, retain) CC_bla_bla *a;
//implementation
#synthesize a;
self.a=[CC_bla_bla load_value:123123]
//dealloc
[self.a release]
self.a = nil;
Within a class, I always use self.a for all manipulations. Is that bad?
And in what sense to use the "instance variable" a?
Properties are most commonly used for getting things to and from other view controllers. You can use properties just in a certain view controller but you have to be cautious.
Since you do:
#property(nonatomic, retain) CC_bla_bla *a;
That has a retain count of 1 which like you did, you must release it in the dealloc. But say you do a = [[CC alloc], etc.... Then it will have a retain count of two.
Hopefully you understand this. You will realize on your own when it is time to use properties.
Properties are just there to associate some "metadata" to your variables which will be used when you access to this one via the object. The #synthesize directive will generate the getter and the setter of the variable using the properties config.
For example:
self.a = [CC_bla_bla load_value:123123]; // The object is retained because of the property
// This is equivalent to the previous line
[self setA:[CC_bla_bla load_value:123123]];
// ------
// By the same way
self.a;
// is equivalent to
[self a];
// ------
// method generated by your property
- (void)setA:(CC_bla_bla *)newA
{
[newA retain];
[a release];
a = newA;
}
But if you use directly the variable without passing by the object you don't use the properties value. For example:
a = [CC_bla_bla load_value:123123]; // The object is not retained so you may have unexcepted behaviors
// A good solution
a = [[CC_bla_bla load_value:123123] retain];
I hope it'll help you to clarify some points. For further reading you can watch this tutorial.
I think you are doing right with your code.
call your property always with self. is good.
But be ware, your code is fine only if the [CC_bla_bla loadvalue:] is not retain the created objects. If your loadvalue function have retained the created object and a property would retain it again, then it should be released twice.
I'm not sure I understood how alloc and retain work.
Recently I discovered that the NSString properties were not retained and I had to add [myString copy] when I set them. Which makes me wonder if I misunderstood the whole way of using retain/alloc
Please, may someone tell me if I'm doing it correctly? I read a lot and had a look on open source projects, this let me thing that I may have been wrong since the beginning.
Here is my way of doing it:
/**** VIEW.h *****/
#import "MyClass.h"
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
#property (nonatomic, retain) MyClass *myObject;
- (void)defineObject;
#end
.
/**** VIEW.m *****/
#import "VIEW.h"
#implementation MyViewController
#dynamic myObject;
- (void)viewDidLoad
{
[super viewDidLoad];
[self defineObject];
NSLog(#"My object's name is: %#", myObject.name);
}
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
.
/**** MyClass.h *****/
#interface MyClass : NSObject {
//not sure if this line is still necessary
NSString *name;
}
#property (nonatomic, retain) NSString *name;
- (id)initPersonalised;
- (void)setName:(NSString *)name;
- (NSString *)name;
#end
.
/**** MyClass.m *****/
#import "MyClass.h"
#implementation MyClass
#dynamic name;
(id)initPersonalised{
self = [super init];
name = #"Undefined";
}
- (void)setName:(NSString *)name{
self.name = [name copy];
}
- (NSString *)name{
return [self.name copy];
}
#end
I hope you can bring a bit of light, after months of programming this way, I'm less and less sure of doing it well.
This is indeed a topic that every Objective C programmer stumbles upon. There are a few things one needs to know:
Instance variable vs. property access
Within MyViewController,
myObject = xxx;
and
self.myObject = xxx;
are two different things. The first directly assigns to the instance variable and does neither release to old referenced insance nor retain the newly assigned instance. The latter one uses the property setter and thus releases the old and retains the new value.
Deallocation
Even when you have declared an implemented a property that takes care of retaining and releases the values, it won't take care of deallocation when your object (MyViewController in your case) is released. So you must explicitly release it in dealloc:
-(void) dealloc {
[myObject release];
[super dealloc];
}
Now to your code:
The snippet:
myObject = [[MyClass alloc] initPersonalised];
is perfectly okay. When you create an object, you use the pair of alloc and initXXX. The always create an instance with the reference count set to 1. So by directly assigning it to the instance variable, you create a clean constellation. I don't see no other way of creating the instance.
In MyClass you could use #synthesize name instead of #dynamic. Then the compiler would implement name and setName: automatically and you wouldn't need to do it yourself.
Finally, your missing dealloc.
Update:
If you use:
self.myObject = [[MyClass alloc] initPersonalised];
then you have a memory leak because initPesonalised sets the reference count to 1 and the setter of myObject increases it to two. If you want to use the setter, then I has to be:
MyClass* mo = [[MyClass alloc] initPersonalised];
self.myObject = [[MyClass alloc] initPersonalised];
[mo release];
It would be different if you weren't using initXXX to create a new instance. The class NSString for example has many methods called stringXXX, which create a new instance (or return a shared one) that has (conceptually) a reference count of 1 that will later automatically decreased by one. Then you better use the setter:
self.name = [NSString stringWithFormat: #"instance %d", cnt];
If you want to use copy instead of retain for your string property (which is good practice), then you can simply declare your property like this:
#property (nonatomic, copy) NSString *name;
When you then use #synthesize to implement the getter and setter, the compiler will generate them using copy instead of retain.
And NSString *name; is necessary even if you use #property and/or #synthesize to implement the property.
Alloc and init are methods that always go hand-in-hand. alloc allocates space for your object, and init initializes your object to some value. When you call alloc, you are responsible for freeing that object later. If you call copy, you are also responsible for releasing that object later. It's considered good practice to always initialize your objects right after you allocate them.
Now, to answer the questions I found in your code.
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
So is that line necessary? That depends. Does it make sense that your object has a MyClass as a property? This is a question only you can answer based on your design. I recommend you to study Object-Oriented Programming in more depth.
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
Not necessarily. You are just providing a pointer to an object of the specified kind. The moment you set your property, depending on the property modifiers, your class will know what to do with MyObject.
In that way, there's no need to call [yourObject copy]. In this way your properties will be copied instead of being retained. Just don't forget to release it later in your -dealloc method, like you would with retain properties.
All in all, this is what I recommend you to study a bit more:
Object-Oriented Programming (not related to your issue, but I can tell you are not comfortable using it. Objective-C is heavily object oriented, so you want to understand OOP).
iOS Memory Management.
You can have a look at the Memory Management Guide. It will help you to better understand the alloc &Â retain concepts; hope this helps you.