Whats the correct way to release a #property / IBOulet for UIViewController - objective-c

I've read many different things about correct memory management for cocoa/objective-c
For instance ive read that any IBOutlets need to be set to 'nil' but something like an NSArray dosnt?
I would also like to know, is it important to call the super method before or after i release/nil everything
To put this memory issue to bed, can some please reply with the 100% correct way you would create a retained property and release it. If your not 100% sure please dont answer.
Here is what im currently doing but something is obviously wrong as i get the very frustrating EXEC_BAD_ACCESS!?! Almost like im releasing something twice?
header.h
#interface MyViewController : UIViewController {
UILabel *aLabel;
NSArray *aArray;
}
#property (nonatomic, retain) IBOutlet UILabel *aLabel;
#property (nonatomic, retain) NSArray *aArray;
method.m
#implementation MyViewController
#synthesize aLabel, aArray;
- (void)dealloc
{
[aLabel release], aLabel = nil;
[aArray release];
[super dealloc];
}
- (void)viewDidUnload
{
self.aLabel = nil; //Not sure about this bad boy???
[super viewDidUnload];
}
#end

In dealloc you have released the aLabel.Means it is not in memory.Again you are write this line ---aLabel=nil;Remove this line.So that it can't gives the Exec_badaccess.This means eventhough you don't have pointer stilll you are trying to access the pointer.

Related

Deallocating nonatomic copy setter

I am trying to create non-atomic copy accessors, and I read everywhere that the object should be released at the end. So, if you could help me understand whether I am doing it properly, I would appreciate it. Will the following be correct?
#interface ClassA: NSObject
{
NSString* stringA;
}
#property (nonatomic, copy) NSString* stringA;
#implementation ClassA
#synthesize stringA;
-(void) setStringA: (NSString*) stringInput {
if(stringA != stringInput) {
[stringA release];
stringA = [stringInput copy];
}
}
-(void) dealloc {
[stringA release];
[super dealloc];
}
I am looking for a confirmation whether I need to deallocate stringA in the dealloc method at the end and whether I did it correctly.
Many thanks.
You need to release it, yes. (You don't deallocate things. You release your ownership of them and they may be deallocated as a result.)
Your code is correct.
The rules are that you must release any object you receive from a method whose name begins with "alloc" or "new" or contains "copy". You also must release any object that you retain. Since you call -copy on stringInput, you are responsible for eventually releasing the object you receive from that.
#Ken Thomases is right; your code is correct. A few things, though:
You don't really need to declare the ivar, or synthesize the property, or write your own setter; all this is done for you. So your code (while correct) could be simplified to:
#interface ClassA: NSObject
#property (nonatomic, copy) NSString* stringA;
#end
#implementation ClassA
-(void) dealloc {
[_stringA release];
[super dealloc];
}
#end
Second, if you're using ARC (which I recommend), the code can be simplified even further (by removing the dealloc override completely).
#interface ClassA: NSObject
#property (nonatomic, copy) NSString* stringA;
#end
#implementation ClassA
#end
In this case stringA is released by your class on dealloc, but you don't have to write code to do that; ARC does it for you.

How to initialize the NSArray in ARC?

I tried initializing the array :
In .h file
#property (nonatomic, retain) NSArray *accounts;
In .m file :
#synthesize accounts;
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *arrList = [acAccountStore accountsWithAccountType:accountType];
// This returns array
self.accounts = [NSArray arrayWithArray:arrList]; // I tried debug after
// this and it gives me data in debugger.
// Note array List have 3 data in it.
}
Now On button click i call a method:
- (IBAction) ButtonClicked :(id) sender {
NSLog(#" data : %#",[self.accounts objectAtIndex:0]); // Breaks at this point.
// When i tried with debug it gives me (no Objective-C description available)
}
Is the initialization of array correct Or If the code is not right please let me know.
Main concern is when i do debug in viewDidLoad, the self.accounts show me proper values. But after doing the click event its empty and throws EXEC_BAD_ACCESS error.
Thanks for help in advance
hm looks fine. A couple of questions then:
Where are you calling the self.accounts = [NSArray arrayWithArray:arrList];
I assume that the array is being setup before your button is being pressed?
There's no real reason that arc should be clearing out the variable. Have you set a strong reference to it or a weak one? If you're using self. on a variable, you should have :
#property (nonatomic, strong) NSArray *accounts;
or similar to that in the .h file and then
#synthesize accounts;
in the .m file.
If you've got weak instead of strong then ARC may possibly clear the memory but it still shouldn't.
Update:
Create a property for your account store as well. I had this exact issue recently and this fixed it.
#property (nonatomic, strong) ACAccountStore *accountStore;
Original Answer
Because you're using ARC, you need to change your property declaration from
#property (nonatomic, retain) NSArray *accounts;
to:
#property (nonatomic, strong) NSArray *accounts;
With the latest LLVM compiler, you don't need to synthesize properties either. So you can remove #synthesize accounts.
You should always use defensive coding as well, so in your - buttonClicked: method, you should do:
- (IBAction)buttonClicked:(id)sender {
if (self.accounts) {
NSLog(#"data: %#", [self.accounts objectAtIndex:0]);
}
}
This makes sure that the pointer to the array is valid.
You can also check to make sure an item in an array exists before trying to read it by doing:
- (IBAction)buttonClicked:(id)sender {
if (self.accounts.count > 0)
NSLog(#"data: %#", [self.accounts objectAtIndex:0]);
}
}

Strange ARC issue not releasing ivar in UIView subclass [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is object not dealloc'ed when using ARC + NSZombieEnabled
I've got a very strange issue I'm seeing at the moment in a project. Put simply I have ViewA which owns ViewB (strong property). ViewA creates its ViewB in its initialiser. Both objects are subclasses of UIView.
I have overridden dealloc in both and put a log line and a break point to see if they get hit. It seems that ViewA's dealloc is being hit but not ViewB's. However if I put in a self.viewB = nil in the dealloc of ViewA then it is hit.
So basically it's something like this:
#interface ViewA : UIView
#property (nonatomic, strong) ViewB *viewB;
#end
#implementation ViewA
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.viewB = [[ViewB alloc] initWithFrame:self.bounds];
[self addSubview:self.viewB];
}
return self;
}
- (void)dealloc {
//self.viewB = nil; ///< Toggling this commented/uncommented changes if ViewB's dealloc gets called.
NSLog(#"ViewA dealloc");
}
#end
What I can't understand is why nil-ing viewB out makes a difference. If something else is holding onto viewB then it should make absolutely no difference if I nil it out or not here. And it shouldn't make a difference to the number of releases that ARC adds in either.
I can't seem to reproduce it in a minimal test case as yet, but I'm working on it. And I can't post the actual code I'm seeing this in unfortunately. I don't see that being an issue though because it's more the point that nil-ing it out shouldn't make a difference that I am confused by.
Can anyone see anything I am overlooking or give advice about where to look for debugging this problem?
Update:
I've found the problem. It appears that it's only a problem when NSZombieEnabled is set to YES. Well that is entirely mad and has to be a bug surely. Zombies should not affect how this works as far as I know. The objects should still go through the dealloc method. And what's more, it's just mad that it works if I nil out viewB in ViewA's dealloc.
I've found that this appears to be a bug in the iOS implementation of zombies. Consider the following code:
#import <Foundation/Foundation.h>
#interface ClassB : NSObject
#end
#implementation ClassB
- (id)init {
if ((self = [super init])) {
}
return self;
}
- (void)dealloc {
NSLog(#"ClassB dealloc");
}
#end
#interface ClassA : NSObject
#property (nonatomic, strong) ClassB *b;
#end
#implementation ClassA
#synthesize b;
- (id)init {
if ((self = [super init])) {
b = [[ClassB alloc] init];
}
return self;
}
- (void)dealloc {
NSLog(#"ClassA dealloc");
}
#end
int main() {
ClassA *a = [[ClassA alloc] init];
return 0;
}
That should output:
ClassA dealloc
ClassB dealloc
But with NSZombieEnabled set to YES, it outputs:
ClassA dealloc
As far as I can tell, this is a bug. It seems to only happen with iOS (both simulator and device) and does not happen when built and run for Mac OS X. I've filed a radar with Apple.
Edit: It turns out this has already been answered here - Why is object not dealloc'ed when using ARC + NSZombieEnabled . Managed to find it after I found out what the real problem was. It's nothing to do with ARC by the way.

In Obj-c (xCode) how do I display this string to the text field?

I am trying to make a practice application that takes two entered words (word1, word2) and puts them together to make a compound word. I am very new to this and would like to know the correct way to display these two variables under the action "buttonPressed."
Here's the header file...
#import <UIKit/UIKit.h>
#interface Word_CombinerViewController : UIViewController {
UITextField *word1;
UITextField *word2;
UITextField *display;
UIButton *mashButton;
}
#property (nonatomic, retain) IBOutlet UITextField *word1;
#property (nonatomic, retain) IBOutlet UITextField *word2;
#property (nonatomic, retain) IBOutlet UITextField *display;
#property (nonatomic, retain) IBOutlet UIButton *mashButton;
-(IBAction)textFieldDoneEditing:(id)sender;
-(IBAction)backgroundTap:(id)sender;
-(IBAction)buttonPressed:(id)sender;
#end
And here's the implementation file (.m)...
#import "Word_CombinerViewController.h"
#implementation Word_CombinerViewController
#synthesize word1;
#synthesize word2;
#synthesize display;
#synthesize mashButton;
-(IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
-(IBAction)backgroundTap:(id)sender {
[word1 resignFirstResponder];
[word2 resignFirstResponder];
}
-(IBAction)buttonPressed:(id)sender {
NSString *newText = [NSString: #word1, #word2]
display.text = newText;
[newText release]
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[word1 release];
[word2 release];
[display release];
[mashButton release];
[super dealloc];
}
#end
I know this code is probably full of errors, but everyone has gotta start somewhere, right?
Any feedback would be greatly appreciated, thank you!
NSString *newText = [NSString: #word1, #word2]
This code doesn't make any sense. The first part of a message is the receiver, and it won't have any colons in it. The second part is the message itself, i.e. the method name along with any necessary parameters. What you're looking for is:
NSString *newText = [NSString stringWithFormat:#"%#%#", word1, word2];
The -stringWithFormat: method uses a format string (very much like printf()) and a variable number of parameters to fill in the placeholders in the format string.
Also, when you create a string (or any object) using a "convenience method" like this, you shouldn't release it. You didn't retain or alloc or copy it, so it's not your responsibility to release it. You'll want to remove that line from your -buttonPressed method.
Try this:
-(IBAction)buttonPressed:(id)sender {
NSString *newText = [word1.text stringByAppendingString:word2.text]
display.text = newText;
}

Automatic iVars with #synthesize

I understand that starting with iOS 4, there is now the ability to not declare iVars at all, and allow the compiler to automatically create them for you when you synthesize the property. However, I cannot find any documentation from Apple on this feature.
Also, is there any documentation on best practices or Apple recommended guidelines on using iVars and properties? I have always use properties like this:
.h file
#interface myClass {
NSIndexPath *_indexPath
}
#property(nonatomic, retain) NSIndexPath *indexPath
#end
.m file
#implementation myClass
#synthesize indexPath = _indexPath;
- (void)dealloc {
[_indexPath release];
}
#end
I use the _indexPath instead of indexPath as my iVar name to make sure that I don't ever use indexPath when I need to use self.indexPath. But now that iOS supports automatic properties, I don't need to worry about that. However, if I leave out the iVar declaration, how should I handle releasing it in my dealloc? I was taught to use iVars directly when releasing in dealloc, rather than using the property methods. If I don't have an iVar at design-time, can I just call the property method instead?
I've went through many different ways of dealing with this. My current method is to use the property access in dealloc. The reasons not to are too contrived (in my mind) to not do it, except in cases where I know the property has odd behavior.
#interface Class
#property (nonatomic, retain) id prop;
#end
#implementation Class
#synthesize prop;
- (void)dealloc;
{
self.prop = nil;
//[prop release], prop=nil; works as well, even without doing an explicit iVar
[super dealloc];
}
#end
In constrast, I do the following:
#interface SomeViewController : UIViewController
#property (nonatomic, copy) NSString *someString;
#end
and then
#implementation SomeViewController
#synthesize someString;
- (void)dealloc
{
[someString release], someString = nil;
self.someString = nil; // Needed?
[super dealloc];
}
#end
Note: At some point Apple will enable synthesize-by-default which will no longer require the #synthesize directive.
You can directly access instance variables using -> symbol instead of dot . (which will invoke ivar's corresponding accessor method):
.h
#interface myClass {
}
#property(nonatomic, retain) NSIndexPath *indexPath
#end
.m
#implementation myClass
- (void)dealloc {
[self->indexPath release];
self->indexPath = nil; // optional, if you need it
[super dealloc];
}
#end
Thus you will directly access iVar and not it's corresponding accessor method, obtaining additional benefit - performance.