I hope someone can tell me why I'm wrong. Here is a snippet of my code:
TimeLogAppDelegate *appDelegate = (TimeLogAppDelegate *)[[UIApplication sharedApplication] delegate];
PickFromListViewController * pl = [[PickFromListViewController alloc] initWithNibName:#"PickList" bundle:nil];
pickList = pl;
[pickList setSearchItems:[appDelegate tableListMutableArray:type ] :NSLocalizedString(type,nil)];
pickList.callingViewController = self;
[pl release];
pickList.responseSelector = [[type lowercaseString] stringByAppendingString: #"Selected:"];
pickList.includeNone = YES;
pickList.includeNew = YES;
[self.navigationController pushViewController:pickList animated:YES];
As you can see, I am releasing pl half-way through, just to create the problem. 'pickList' is obviously a PickFromListViewController and is declared in the Header. I set it up as a property (#property (nonatomic, retain) PickFromListViewController *pickList;) and I #synthesize it.
My problem is:
after pl is release I get a BAD ACCESS error accessing pickList indicating that the pointer is no longer available, but I thought the fact that pickList is synthesized, it would be retained until I release it at dealloc?
Can someone tell me why I am wrong?
Many thanks
Setting up your pickList property as (nonatomic, retain) only applies if you access the property via a property accessor, as follows:
self.pickList = P1;
or
[self setPickList:P1];
If you simply assign a value to the member variable:
pickList = P1;
You are bypassing the property accessor methods, so no retain message is sent.
Related
Let say i have an class named as MyTestClass.h.
Class structure is look like
#interface MyTestClass : NSObject {
NSString *testString;
}
#property (nonatomic, retain)NSString * testString;
#end
.m file
#implementation MyTestClass
#synthesize testString;
-(id) init{
[self setTestString:#""];
return self;
}
-(void)dealloc{
[self.testString release];
testString = nil;
[super dealloc];
}
#end
Now i created an object of MyTestClass and assigned testString twice
MyTestClass * myTestClass = [[MyTestClass alloc] init];
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
Now i think, two times my testStrings memory is leaked!! (one through init() and another one through my first setTestString method)
Am i correct? or will #property (nonatomic, retain) handle/release previous allocated memory?
or ,in this kind of cases ,will i need to override the setTestString() in MyTestClass.m like below code
-(void)setTestString:(NSString *)tempString{
[testString release];
testString = nil;
testString = [tempString retain];
}
Any help on this question is appreciated.
Thanks.
Any help on this question is appreciated.
I'll take this as a licence to make sone observations not necessarily directly related to your question.
Firstly, if you declare a retain property (as you have done) and synthesize it, the automatically generated getters and setters handle memory management correctly for you.
If you manually create setter (which you are allowed to do even with an #synthesize existing), you have to do the memory management yourself. Use either of trojanfoe's examples.
The setter in your question contains a bug in that if testString == tempString i.e. you assign the value of the property to itself, you could end up with assigning a dangling pointer to the property because you effectively release tempString and then retain it.
This is an implementation detail that you an safely ignore, but string literals e.g. #"blah" are compiled into the executable and will never be deallocated no matter how many times they are released. So, with your example, even if the setter did not do correct memory management, there will be no leak.
By the way, the normal pattern for an init method is
-(id) init
{
self = [super init];
if (self != nil)
{
// init stuff
}
return self;
}
or logical equivalent.
You should get into the habit of using it because you need to call the super class's init method and it is allowed to change the value of self, even to nil.
Also, while it is very good practice normally to set the object reference to nil after releasing it, in both cases when you do it, it is unnecessary. the first time, the variable is about to go out of scope and the second time you immediately assign it from some other object.
It's not a leak. Synthesized variable are correctly handled.
A synthesized method is implemented in this way (for a retain keyword)
#property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;
- (void)setString:(NSString*)newString
{
if (newString != _string) {
[_string release];
_string = [newString retain];
}
}
Of course this is a leak:
- (void)aMethod //of my class with string property
{
NSString *aString = [[NSString alloc] initWithString:#"hello"];
self.string = aString; //retain count of 2
self.string = #"hello2"; //retain count of 1 for aString
//now I don't release aString.... leak
}
If you use the auto-generated setter (in your case, setTestString:, which is also called by self.testString = ...;), the previous value of a retain property is released before being set. So no, there is no leak in the code you posted above.
The synthesized setter method should do the right thing. Here's an example of it's implementation:
- (void)setTestString:(NSString *)tempString
{
[tempString retain];
[testString release];
testString = tempString;
}
or:
- (void)setTestString:(NSString *)tempString
{
if (tempString != testString)
{
[testString release];
[tempString retain];
testString = tempString;
}
}
the dealloc is only called when the instance is destructed.
if you do :
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
in the same block, you're juste calling twice the setter. there is no memory leak.
When you use #synthesize on a property that specifies retain, the setter that's generated will handle the retain/release correctly for multiple assignments. As long as you use self. rather than going directly to the backing variable and do a final release in dealloc you should be fine.
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];
I've go a situatiion in Objective-C where I'm trying to access an object's variable through another object. The classes (simplified):
A.h
#interface A : NSObject {
NSMutableArray *someStuff;
}
#property (nonatomic, retain) NSMutableArray *someStuff;
#end
A.m
#implementation A
#synthesize someStuff;
// blah, blah, blah
Then, because I'm doing an iPhone app, there is an app delegate that contains a variable of this object type:
AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate> {
A *aPtr;
}
#property (nonatomic, retain) A *aPtr;
#end
AppDelegate.m
#implementation AppDelegate
#synthesize aPtr;
// blah, blah, blah
Then, in another class (in this a view controller), I'm trying to access 'someStuff' in this manner:
AViewController.m
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
So, the problem is that this blows up in fine fashion. I think I'm too much of a Java junkie to understand why this won't work. Can anyone elighten me?
Many thanks,
Craig
You need to initialize this in this way
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSMutableArray *someArray = appDelegate.someArray;
This will resolve your problem.....
Craig,
appDelegate.aPtr will return null. as it is not initialized yet, and when you try to access some member of a null object,(in java NULLPointerException).Its behavior is as expected.(this blows up in fine fashion).
Thanks,
Ravin is correct. The class definition defines the iVars and properties for a class so you have defined an iVar aPtr that references an object of type A. However, you have not allocated and initialized this object.
An example using the default initialization would be `aPtr = [[A alloc] init]'.
This all sounds suspicious since in ObjC you are allowed to send messages to nil without a problem and properties are just diguised methods. For example you can
view = nil;
view.hidden = NO;
and it doesn't blow up, it just does nothing.
So since appDelegate.aPtr.someStuff is just
[[appDelegate aPtr] someStuff];
and [appDelegate aPtr] does nothing and returns nil so it should be safe to call [[appDelegate aPtr] someStuff] without a problem but also without any results.
So while it is a problem with using objects that hadn't been initialized (which most often should be done in a designated constructor of the appropriate object), since you don't get results that you expect, in my undestanding of "sending message to nil" in ObjC it shouldn't blow up. If it is then either I am missing the point or something other causes the problem and not this call.
EDIT
just checked: if not initialized at all it works as I explained: ObjC allows messages to be sent to nil:
A *aPtr = appDelegate.aPtr;
NSMutableArray *someArray = aPtr.someStuff;
NSLog(#"%#", someArray);
or
NSMutableArray *someArray = appDelegate.aPtr.someStuff;
NSLog(#"%#", someArray);
both don't break and print null.
If you initialize A properly but not initialize someStuff in A it still doesn't break but print null. The problem might be that you initialize aPtr to a different class than A, in which case you get unrecognized selector exception (you should be able to see it in the error log) and program crash.
i have the following code in .h:
#property (nonatomic, retain) NSArray *arrayData;
And in the .m in method initWithNibName:
self.arrayData = [NSArray arrayWithObjects:#"Usuario:",#"Password:",nil];
is it right in order to call
[self.arrayData release]
safely in order to release the object?
No, it is not correct to call release on your property. The problem with it is, that you release your property, it will get deallocated, but you didn't set your pointer to nil, so somebody might send a message to your property and get a crash.
What you can do is the following:
self.arrayData = nil; ( which will release the previous saved instance, and set the property to nil)
[arrayData release]; arrayData = nil; (here you are accessing your ivar instead of your property; setting your ivar to nil is a precaution)
[self->arrayData release]; self->arrayData = nil (this is exactly the same as #2)
Hope this helps.
You need to call:
[arrayData release]
Calling [self.arrayData release]; will not have the effect you want it to in either case.
If you're wondering why this is, check this question out: difference between [self.property release] and [property release]
A)
it is a bad idea to do this in your initializer (e.g., initWithNibName:bundle:)
self.arrayData = [NSArray arrayWithObjects:#"Usuario:",#"Password:",nil];
use this instead:
arrayData = [[NSArray alloc] initWithObjects:#"Usuario:",#"Password:",nil];
you should not call these accessors (properties) in initializers or dealloc.
B)
is it right in order to call
[self.arrayData release]
no. in many cases (assuming you implement some of the properties you've declared), you may not be returned the the ivar. you may receive a copy, a placeholder object, or a subclass may have chosen to re-implement the accessors (as some examples). in these cases, it's easy to over-release or over-retain (resulting in evil stuff, like leaks and crashes).
this is typical:
self.arrayData = nil;
unless you are in dealloc of the object which declared the ivar:
- (void)dealloc {
[arrayData release], arrayData = nil;
[super dealloc];
}
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.