Data is not persisting in multiple instances of the same object (iOS) - iphone

I'm having issues with data persisting inside of multiple instances of objects I'm creating.
I have a class "IconViewController" that extends UIViewController that I pass information to, such as the name of the image it should be using:
//IconViewController.h
#interface AppIconViewController : UIViewController
{
NSString *imageName;
}
#property (nonatomic, retain) NSString *imageName;
- (void) doSomething;
//IconViewController.m
#implementation AppIconViewController
#synthesize imageName;
NSNumber *iconWidth;
- (void)loadView
{
[super loadView];
UIImageView *iconImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
iconWidth = [NSNumber numberWithFloat:iconImage.bounds.size.width];
[iconImage release];
NSLog(#"iconWidth: %f", [iconWidth floatValue]);
}
- (void) doSomething
{
NSLog(#"iconWidth: %f", [iconWidth floatValue]);
}
In another view controller, I'm instantiating several instances of these IconViewControllers and passing different sized images to them:
AppIconViewController *appIcon1 = [[AppIconViewController alloc] initWithNibName:nil bundle:nil];
appIcon1.imageName = #"Image65PXWide.png";
[self.view addSubview:appIcon1.view];
AppIconViewController *appIcon2 = [[AppIconViewController alloc] initWithNibName:nil bundle:nil];
appIcon2.imageName = #"Image105PXWide.png";
[self.view addSubview:appIcon2.view];
Okay, the weirdness is that when I'm creating these, I'm getting logs back that are accurate...appIcon1 logs "iconWidth: 65.0" and appIcon2 logs "iconWidth: 105.0". But when I call:
[appIcon1 doSomething];
...my log is "iconWidth:105.0".
Why is the data in the first instance reflecting the data in the second instance? What am I missing?
EDIT:
I know that if I declare iconWidth in the header and synthesize it as a property, that it will work. So what I'm wondering is how to make a private version of it persist. Because I tried retaining the NSNumber with:
iconWidth = [[NSNumber numberWithFloat:iconImage.bounds.size.width] retain];
...and it still doesn't work. Does it have to be synthesized and public?
EDIT #2:
Okay, so I figured out that once I declare iconWidth in my header, it works just fine, and I don't have to synthesize it so it keeps it private. Not sure why exactly it won't work if declared in the implementation file - does anyone have any insight into why and if there's any purpose in declaring variables at the top of an implementation but not in the header? Just curious now more than anything.

Synthesizing doesn't make anything private. It just generates getter/setter methods according to declared properties.
By placing iconWidth in the implementation, outside of any methods, it's essentially a class-level variable. So it gets overwritten by the last thing that writes to it. You already have imageName declared in the interface, so why not just put iconWidth there as well (instance variables are private by default)?

In your method doSomething, you are assuming iconWidth is set up properly.
However, iconWidth is created as an autorelease object in loadView method, so when loadView finishes, the main loop will release iconWidth and you are getting random values.
To fix this you have to retain iconWidth so you can use it in other methods
iconWidth = [[NSNumber numberWithFloat:iconImage.bounds.size.width] retain];
As a general rule, method that doesn't start with init will return autorelease object, so you have to be careful how you instantiate an object and whether you need to call retain on it.

Related

message sent to deallocated instance ! cant find error

alright I am looking for this error since 2 hours and I just cant figure it out please help me.
I have the following situation I have 2 viewcontroller.
one presents the other one as modalview like that.
SearchViewController *searchViewController = [[SearchViewController alloc]init];
[searchViewController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
searchViewController.delegate = self;
searchViewController.senderTag = [sender tag];
[self presentModalViewController:searchViewController animated:YES];
[searchViewController release];
in my searchviewcontroller I do this in the .h file
BSKmlResult *selectedAirport;
#property (nonatomic, retain) BSKmlResult *selectedAirport;
in the .m file i synthesize it and then set it like that
selectedAirport = [self.airportList objectAtIndex:indexPath.row];
and then release it here
- (void)dealloc {
[selectedAirport release];
[super dealloc];
}
in the delegate methode of my SearchViewController which is implemented in the first
viewcontroller where I also present the SearchViewController
i have the following
if (controller.selectedAirport) {
if (departureAirport) {
[departureAirport release];
}
departureAirport = [controller.selectedAirport copy];
}
[self dismissModalViewControllerAnimated:YES];
I narrowed down where the error happens it is in the dealloc of my SearchViewController
[selectedAirport release];
but I cant figure out where my mistake is
please help
selectedAirport = [self.airportList objectAtIndex:indexPath.row];
You arent retaining selectedAirport here.
Change it to
self.selectedAirport = [self.airportList objectAtIndex:indexPath.row];
Since you couldnt find it out, probably you dont know this...
If you dont access member variables by self.memberVariable, you are not accessing its property. Thus, it was not getting retained.
Ofcourse you can also retain it by saying
selectedAirport = [[self.airportList objectAtIndex:indexPath.row] retain];
But whats the use of your property then...
You need to use self. to run it through the synthesized method, to get the retain.
self.selectedAirport = [self.airportList objectAtIndex:indexPath.row];
I know this post is quite old but just wanted to add something useful to it. In the above case the member variable name and property name are identical so you may still by mistake set the value of member variable instead accessing it using property that will call retain implicitly. Hence the best way to make sure you always use self.selectedAirport is to name the member variable something different than your property.
For example, in .h file you can have below implementation:
NSString *_selectedAirport;
then encapsulate it inside a property like below
#property(nonatomic,retain) NSString *selectedAirport;
and in .m implementation file synthesize it like below:
#synthesize selectedAirport = _selectedAirport;
By doing above, if you try to access it like below
selectedAirport = [self.airportList objectAtIndex:indexPath.row];
then it would result in an error and you will be prompted to use self.selectedAirport.
Also in this case your dealloc method can have either
self.selectedAirport = nil;
or
[_selectedAirport release];

Objective C: Proper way to init an NSArray that is a #property

I have a property in my class, which is an NSArray. I am retaining the property.
My question is, what is the proper way to add objects to that array without leaking and making the retain count too high?
This is what I am using:
.h:
NSArray *foodLocations;
#property (nonatomic, retain) NSArray *foodLocations;
// I make sure to synthesize and release the property in my dealloc.
.m
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *tempFood = [[NSArray alloc] initWithArray:[self returnOtherArray]];
self.foodLocations = tempFood;
[tempFood release];
}
Is this the correct way to do it?
Yes this is correct and my preferred way of doing it as it renders the code more readable.
You are essentially allocating a temporary array and then assigning it to your property with a retain attribute, so it is safe to dealloc it as your property now "owns" it. Just remember that you still need to release it in your dealloc method.
You could also initialise the array and assign it to the property in the view controllers init method, depending on whether you need the property to be available to you before the view actually loads (i.e. in case you want to read the value of the property before pushing the view controller etc...)
you will typically want to declare the property copy in this case.
in most cases, immutable collection accessors should be copy, not retain. a lot of people get this wrong, and end up writing a lot of copying manually and sharing objects which should not be shared, thinking they are doing themselves good by cutting a corner.
copying in this form (the collection) is shallow. the objects in the array are not copied, just the array's allocation.
a good implementation of an immutable collection can simply implement copy by retaining self. if the argument is mutable, you want a copy anyhow (in the majority of cases).
your program is then simplified to a declaration of:
// note: copy, not retain. honor this if you implement the accessors.
#property (nonatomic, copy) NSArray * foodLocations;
and then the setter:
self.foodLocations = [self returnOtherArray];
of course, you must still init, dealloc, and handle thread-safety appropriately.
good luck
That looks fine. You don't actually need the tempFood variable, you can just do:
self.foodLocations = [[NSArray alloc] initWithArray:[self returnOtherArray]];
[self.foodLocations release];
or:
self.foodLocations = [[[NSArray alloc] initWithArray:[self returnOtherArray]] autorelease];
Or:
#synthesize foodLocations=_foodLocations;
then in code
_foodLocations = [[NSArray alloc] initWithArray:someOtherArray];
This avoids the autorelease required by
self.foodLocations = [[[NSArray alloc] initWithArray:someOtherArray] autorelease];
Yes, that is correct. Also good to keep in mind is what #synthesize is, in effect, doing for you. A synthesized (& retained) setter is functionally equivalent to the following code:
- (void)setVar:(id)_var {
[_var retain];
[var release];
var = _var;
[var retain];
[_var release];
}
So, basically, every time you call self.var = foo, it releases the previously stored value and retains the new one. You handle the reference counting in your code, and the setter handles its own.

where do I instantiate my class so I can access it throughout my app?

I've been working through some objective-c/ iOS dev books and I've hit a stumbling block. I get the feeling that I'm missing something dumb here, so I'm sure you guys can help, because you're all so damn smart :-).
I've got a very simple app that consists of 1 button and 1 label. Pushing the button puts a message in the label. I've created a class that includes a method to create said message. Here is the problem:
#import "classTestViewController.h"
#implementation classTestViewController
#synthesize myLabel;
- (void)viewDidLoad
{
}
-(IBAction) pressGo:(id)sender{
MyClass * classTester = [[MyClass alloc] init];
classTester.count = 15;
NSString *newText = [classTester makeString ];
myLabel.text = newText;
}
- (void)dealloc
{
[classTester release];
[myLabel release];
[super dealloc];
}
The output of this app, in my label, is "Yay 15". So you can see the problem, the only way I can get this to work is to instantiate the class right there, in the "pressGo" method. This isn't desirable because another method can't access or change the class variable count. Also I get a warning that local declaration of classTester hides instance variable. If I move the class instantiation to the viewDidLoad method, which seems right, the other methods can't access it anymore.
#import "classTestViewController.h"
#implementation classTestViewController
#synthesize myLabel;
- (void)viewDidLoad
{
MyClass * classTester = [[MyClass alloc] init];
}
-(IBAction) pressGo:(id)sender{
classTester.count = 15;
NSString *newText = [classTester makeString ];
myLabel.text = newText;
}
- (void)dealloc
{
[classTester release];
[myLabel release];
[super dealloc];
}
The output of that is nada. If I try to access just one variable, classTester.count, for example, even after setting it, I get a 0 value. I also get the override warning here as well.
So my question is, how can i get access to that class instance throughout my app and not just in one method? I'm using a view based application.
Declare classTester in your interface file with:
#class MyClass
#interface classTestViewController : UIViewController
{
MyClass *classTester;
}
// Any other custom stuff here
#end
Then instantiate it in your viewDidLoad method with:
classTester = [[MyClass alloc] init];
And you should be able to access the ivar from any method within this class. If you want it to be accessible to your entire app, #Waqas link will point you in the right direction.
You need to create a singleton class which instantiate once and is available inside whole project
Have a look
http://projectcocoa.com/2009/10/26/objective-c-singleton-class-template/

Memory management - how best to initialise an instance declared in the header

I've read a few posts on this, but there's still one thing that's not clear for me. I know this might be rather a n00b question, but I've actually got rather far into development without quite grasping this fundamental issue. A symptom of being self taught I guess.
You declare a variable in your header, like so:
#interface SomeClass : NSObject {
NSMutableArray *anArray;
}
#property (nonatomic, retain) NSMutableArray *anArray;
end
And then in your main file you synthesise it and set it to an initial value:
#implementation SomeClass
#synthesize anArray
- (SomeClass *)init{
if (self = [super init]) {
self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
}
[return self];
And release it when your Class deallocs:
- (void)dealloc {
[anArray release];
[super dealloc];
}
Now, when I run instruments, the line
self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
is identified as a memory leak. Is it a memory leak because when you define the variable anArray in the header it allocates memory? (Because I thought it was a null pointer.) Therefore when you want to initialise it, and you call [[NSMutableArray alloc] initWithCapacity:10], you are reallocating the memory, and losing the pointer to the original allocation?
So instead, I use the convenience class method:
#implementation SomeClass
#synthesize anArray
- (SomeClass *)init{
if (self = [super init]) {
self.anArray = [NSMutableArray arrayWithCapacity:10];
}
[return self];
This is no longer identified as a memory leak in instruments. And since it's a convenience method, anArray is autoreleased. However, if I am to assume that the instance declaration in the header allocates memory, which would explain the previous issue, then should I still release anArray? Does setting the initial values in this way retain it perhaps?
I understand the difference between
NSMutableArray *anArray = [[NSMutableArray alloc] initWithCapacity:10];
and
NSMutableArray *anArray = [NSMutableArray arrayWithCapactiy:10];
but what I'm not sure I understand is when you've declared NSMutableArray *anArray in your header, which of the two approaches you should use and why. And whether or not if you use the second approach, you should still release anArray when you call dealloc.
I might add that I've found the following posts/links useful:
Suggest the best way of initialization of array ( or other objects )
What is the cost of using autorelease in Cocoa?
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
What is the difference between class and instance methods?
alloc'ing an object starts it off with a reference count of 1.
Setting a property that has the 'retain' attribute also increases the reference count.
So, that means this is usually bad:
#property (nonatomic, retain) Object * variable;
...
self.variable = [[Object alloc] init];
Because variable now has a reference count of 2.
When setting a object's member variable, just do this:
variable = [[Object alloc] init];
You should also realize that this works
self.anArray = [NSMutableArray arrayWithCapacity:10];
Because "arrayWithCapacity" (and other similar factor methods) autoreleases the object it returns, so after you set the property, it essentially has a reference count of 1.
It's not the instance that allocates the memory. You're right to assume that in Objective-C (at least on all Apple-based operating systems), newly initialized classes have all their ivars set to 0 (or nil or NULL as appropriate).
The problem you're seeing is that you're using the property, not the ivar in your initialization. Since you declared your property as retain, using the property accessor to set it automatically retains it.
So, when you initialize you either have to take ownership and set the ivar directly, or do like you're doing and use the property accessor to set the property and then relinquish ownership in the init method (by either releasing an object you own or, as you did in your second instance, using the convenience constructor so that you never owned the returned instance).
So just remember, if you ever use the property accessors, even within the class itself, you will get the features you set on the property (e.g., nonatomic, retain, etc.). You use the property accessors whenever you do one of the following:
// in these cases the property takes ownership through the
// retain keyword, so you must not take ownership yourself
self.anArray = something;
[self setAnArray:something];
[self setValue:something forKey:#"anArray"];
You would access your ivar directly like:
anArray = something; // in this case you must take ownership

iPhone basic memory management

Is this proper memory management? What I'm wondering is if I am supposed to release after the alloc in -viewDidLoad.
SomeViewController.h
#import <UIKit/UIKit.h>
#interface SomeViewController : UIViewController {
UIButton *someButton;
NSString *someString;
}
#property (nonatomic, retain) IBOutlet UIButton *someButton;
#property (nonatomic, copy) NSString *someString;
#end
SomeViewController.m
#import "SomeViewController.h"
#implementation SomeViewController
#synthesize someButton, someString;
- (void)viewDidLoad {
[super viewDidLoad];
someButton = [[UIButton alloc] init];
someString = [[NSString alloc] init];
}
- (void)viewDidUnload {
self.someButton = nil;
self.someString = nil;
}
- (void)dealloc {
[someButton release], self.someButton = nil;
[someString release], self.someString = nil;
[super dealloc];
}
#end
Thanks
Edit: one more thing. If I place a UIButton in IB, do I still need to alloc it?
It's quite a long story which you may find by googling around, and someone may enter here, but to keep it short, here's a few tweaks:
- (void)viewDidLoad {
[super viewDidLoad];
self.someButton = [[[UIButton alloc] init] autorelease];
self.someString = [[[NSString alloc] init] autorelease];
}
I.e. use the setters (self.something = ...;) and always either release or autorelease any alloc you do. (The logical distinction would be who "owns" the objects; with these tweaks the function gives up ownership and the class gets it.)
edit: no, if you create a button in IB, the button will just be there, allocated and initialized with your styles.
When you call init on an object, the retain count goes to 1. You have two different setter attributes: one is "retain" for your UIButton, and the other is "copy" for your NSString. When you call
self.someButton = someUIButtonObject;
someUIButtonObject gets a retain message and so its retain count goes up to 1. In the case of your original code, calling release in dealloc will release one reference to someUIButtonObject, but it will still have a retain count of 1 and will thus be leaked.
The other case with your NSString has a different problem but still leaks memory. Here your call to [[NSString alloc] init] results in a new string object, and then calling
self.someString = someNSStringObject;
results in the creation of a brand new object which copies the content of someNSStringObject. In this case, someNSStringObject and the setter's copied object each have a retain count of one. Here, you leak the string you alloc init-ed because you no longer have a reference to it and it goes out of scope with a retain count of one.
A quick side note: I don't know what your actual code looks like, but don't forget that NSStrings are immutable (so just calling [[NSString alloc] init] is pretty useless) and UIButton needs a frame (try [[UIButton alloc] initWithFrame:(CGRect)frame];).
Basically you need to match each call to retain, copy, or alloc with a call to release (or autorelease). It is appropriate so use
self.someButton = [[[UIButton alloc] init] autorelease];
Which will release the object, though at some unknown time in the future. Don't use autorelease if your memory is very tight and you need memory ASAP. In that case you would do:
UIButton* tempButton = [[UIButton alloc] init];
self.someButton = tempButton;
[tempButton release];
which guarantees that you don't have large objects waiting around in your autorelease pool.
Also, always use the getters/setters to access these properties (self.someButton as opposed to someButton). That way you don't accidentally assign someButton to a new pointer and leak the old one.
When you create a button in IB, the XIB holds a reference to the button (+1 retain count). If you create an IBOutlet so you can access the button programmatically, you get another retain on the object, so if you have an IBOutlet to someButton, someButton has a retain count of 2 as soon as the XIB is loaded. You do not need to alloc the object, that is done automatically when the XIB is loaded into memory. Also, you are only responsible for releasing one reference to the button (your IBOutlet reference). In general, it is a good practice to release your reference as soon as you know you no longer need it. For example, if you know you need a button and have to do initial customization and nothing else, then you would probably do something like this:
-(void)viewDidLoad {
// Do some customization of someButton
[someButton release];
}
Otherwise you would probably release someButton in viewDidUnload since you know at that point you won't need the reference to the button anymore.
If your button is set in IB, you do not need to allocate it in the code (IB does it for you).
Basically, each object you created using alloc or new, should have a release somewhere in your code. If it's an interface variable, you should release them in the dealloc function.