I am using a custom class to display some info on a table view.
The problem is that as long as I scroll the tableview memory is leaking...
I guess I have something wrong at my class.
Please have a look:
#interface Person : NSObject {
NSString *name;
NSString *surname;
NSString *address;
NSString *email;
}
#property (nonatomic, copy) NSString *name, *surname, *address, *email;
#implementation Person
#synthesize name, surname, address, email;
-(id)init {
[super init];
name = [[NSString alloc] init];
surname = [[NSString alloc] init];
address = [[NSString alloc] init];
email = [[NSString alloc] init];
return self;
}
- (void)dealloc
{
[name release];
[surname release];
[address release];
[email release];
[super dealloc];
}
#import "Person.h"
#interface Group : NSObject {
NSString *groupTitle;
NSMutableArray *persons;
}
#property (readwrite, copy) NSString *groupTitle;
- (void)addPerson:(Person *)person;
- (void)removeAll;
- (NSArray *)getPersons;
- (int)PersonsCount;
#end
#implementation Group
#synthesize groupTitle;
-(id)init {
[super init];
persons = [[NSMutableArray alloc] init];
return self;
}
-(void)addPerson:(Person *)person {
[persons addObject:person];
}
-(void)removeAll {
[persons removeAllObjects];
}
-(NSArray *) getPersons {
return [persons copy];
[persons release];
}
-(int)personsCount {
return [persons count];
}
-(void)dealloc {
[groupTitle release], groupTitle = nil;
[persons release], persons = nil;
[super dealloc];
}
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
…….
Group *groupForRow = [[Group alloc] init];
Person *personForRow = [[Person alloc] init];
personForRow = [[groupForRow getPersons] objectAtIndex:indexPath.row];
_personName = personForRow.name;
_personSurname = personForRow.surname;
_personAddress = personForRow.address;
_personEmail = personForRow.email;
[groupForRow release], groupForRow = nil;
[personForRow release], personForRow = nil;
…..
return cell
Few corrections (read the comments):
#interface Person : NSObject {
NSString *name;
NSString *surname;
NSString *address;
NSString *email;
}
// copy is OK for strings...
#property (nonatomic, copy) NSString *name, *surname, *address, *email;
#end
#implementation Person
#synthesize name, surname, address, email;
- (id)init {
if (self = [super init]) {
// There is no need to allocate the strings
// In addition, once you write 'name = [[NSStrin alloc] init];' you don't use the property.
// If you do want to use the property setter then you should write 'self.name = #"some string";'
}
return self;
}
- (void)dealloc {
[name release];
[surname release];
[address release];
[email release];
[super dealloc];
}
#end
#import "Person.h"
#interface Group : NSObject {
NSString *groupTitle;
NSMutableArray *persons;
}
// Any special reason for "readwrite" instead of "nonatomic"?
#property (readwrite, copy) NSString *groupTitle;
// This property is more important than the string:
#property (nonatomic, retain) NSMutableArray *persons;
- (void)addPerson:(Person *)person;
- (void)removeAll;
- (NSArray *)getPersons;
- (int)PersonsCount;
#end
#implementation Group
#synthesize groupTitle, persons;
- (id)init {
if (self = [super init]) {
// Use the autoreleased array instance ([NSMutableArray array]) and set it to the property setter that will retain the object:
self.persons = [NSMutableArray array];
}
return self;
}
- (void)addPerson:(Person *)person {
// I prefer using properties (the "self." in the beginning) instead of the members directly...
[self.persons addObject:person];
}
- (void)removeAll {
[self.persons removeAllObjects];
}
// I think that this getter is unnecessary - use the property instead...
- (NSArray *) getPersons {
// There is no need to copy
return [persons copy];
// Don't you have a warning for this line? It is never executed
[persons release];
}
- (int)personsCount {
return [self.persons count];
}
- (void)dealloc {
[groupTitle release], groupTitle = nil;// The "groupTitle = nil" is unnecessary.
[persons release], persons = nil;// The "persons = nil" is unnecessary.
[super dealloc];
}
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
…….
Group *groupForRow = [[Group alloc] init];// Do you REALLY have to allocate this object each "cellForRowAtIndexPath"??
Person *personForRow = [[Person alloc] init];// Get rid of the "= [[Person alloc] init]" - this is a leak (because of the next line)
personForRow = [[groupForRow getPersons] objectAtIndex:indexPath.row];// If you will use the property persons instead of the "getPersons" (that copies the array) then you will get rid of another leak
// What are these?
_personName = personForRow.name;
_personSurname = personForRow.surname;
_personAddress = personForRow.address;
_personEmail = personForRow.email;
// The " = nil" is unnecessary here...
[groupForRow release], groupForRow = nil;// If you won't allocate the group then you won't need this line...
[personForRow release], personForRow = nil;// NSZombie - you release object that you don't owe (do you have crashes, that you don't know why they are happen?)
…..
return cell;
}
There is a lot wrong here, please delve a little into objective-C to get a grasp of the use of #property and #synthesize to get correctly functioning getter/setter methods.
As for your memory leak when scrolling, it is caused by the allocs in cellForRowAtIndexPath which are not balanced by either a release or an autorelease.
This:
Group *groupForRow = [[[Group alloc] init] autorelease];
Person *personForRow = [[[Person alloc] init] autorelease];
should fix most of your leaks. Browse around on SO for more info.
Related
I have this Class in my project :
#interface VideoItem : NSObject <NSCoding> {
NSString *name;
NSString *artist;
int seconds;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *imgUrl;
#property (nonatomic, retain) NSString *artist;
#end
And this is how i create this object:
VideoItem *item = [[VideoItem alloc] init];
item.name = name;
item.imgUrl = imgLink;
item.artist = artist;
And this is the dealloc:
- (void)dealloc{
[name release];
[imgUrl release];
[artist release];
[super dealloc];
}
And i want to know if this dealoc is ok with the NON-ARC? did i need to do something else because this NSString are with Property?
Edit
And if the VideoItem object was create with:
VideoItem *item = [[VideoItem alloc] init];
item.name = [NSString alloc]initWithFormat#"%#",name];
item.imgUrl = [NSString alloc]initWithFormat#"%#",imgLink];
item.artist = [NSString alloc]initWithFormat#"%#",artist];
Did in this case the dealloc is still ok? or i need to change something?
Everything looks ok, you are releasing all the #properties of your object. I would probably as well point them to nil, just to make sure, that if one of those properties is called, it will be nilled and not have a garbage value, like so:
- (void)dealloc{
[name release], name = nil;
[imgUrl release], imgUrl = nil;
[artist release], artist = nil;
[super dealloc];
}
Another thing, no related, it would be cleaner, if you would create your own init, so you can pass the properties values, when you actually create the object, like so:
-initWithName:(NSString *)name withImgURL:(NSString *)imgURL withArtist:(NSString *)artist;
Your edit:
item.name = [NSString alloc]initWithFormat#"%#",name];
item.imgUrl = [NSString alloc]initWithFormat#"%#",imgLink];
item.artist = [NSString alloc]initWithFormat#"%#",artist];
Only based on this, it will create a leak, so you should be careful. To fix this:
item.name = [[NSString alloc]initWithFormat#"%#",name] autorelease];
item.imgUrl = [[NSString alloc]initWithFormat#"%#",imgLink] autorelease];
item.artist = [[NSString alloc]initWithFormat#"%#",artist] autorelease];
If you don't have ARC enabled than your destructor is correct. You are releasing all the properties that are retained and calling super, which is all you need.
I have a little app that have by default youtube as homepage. You can change it in a little menu, but it doesn't work and I don't know why.
Here's the code
viewController
.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController{
IBOutlet UIWebView *webView;
}
#property (retain, nonatomic) NSArray *array;
#property (retain, nonatomic) NSString *string1;
-(NSString *) dataFilePath;
- (IBAction)settings:(id)sender;
- (IBAction)home:(id)sender;
#end
.m
#import "ViewController.h"
#import "settings.h"
#implementation ViewController
#synthesize array;
#synthesize string1;
- (void)viewDidLoad
{
[super viewDidLoad];
if ([string1 isEqual:#"youtube"]) {
NSMutableArray *Array = [[NSMutableArray alloc] init];
[Array addObject:#"http://www.youtube.com"];
[Array writeToFile:[self dataFilePath] atomically:YES];
}
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
array = [[NSArray alloc] initWithContentsOfFile:filePath];
}
NSString *string = [NSString stringWithString:[array objectAtIndex:0]];
[webView loadRequest:[[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:string]]];
}
-(NSString *) dataFilePath
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"url.plist"];
string1 = #"youtube";
}
- (IBAction)settings:(id)sender {
settings *NView = [[settings alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:NView animated:YES];
}
- (IBAction)home:(id)sender {
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
array = [[NSArray alloc] initWithContentsOfFile:filePath];
}
NSString *string = [NSString stringWithString:[array objectAtIndex:0]];
NSLog(#"%#\n",string);
[webView loadRequest:[[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:string]]];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
Settings //here's the menu where I can change the homepage
.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface settings : UIViewController{
ViewController *viewCont;
IBOutlet UITextField *field;
}
-(IBAction)back:(id)sender;
- (IBAction)setHP:(id)sender;
#end
.m
#import "settings.h"
#import "ViewController.h"
#implementation settings
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib
}
- (void)viewDidUnload
{
field = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(IBAction)back:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)setHP:(id)sender {
NSMutableArray *Array = [[NSMutableArray alloc] init];
[Array addObject:field.text];
[Array writeToFile:[viewCont dataFilePath] atomically:YES];
[viewCont.string1 initWithString:#"other" ];
NSLog(#"%#\n", viewCont.string1);// HERE XCODE SAYS string1 = null!!! WHY?
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
So anyone knows what am I doing wrong? Please help me, I have searched around the web for 4 days and I didn't find anything!
I don't understand well your problem but i notice that you are not initializing viewCont in the setHP: action.
try to add this line:
ViewController *viewCont=[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
just before
[viewCont.string1 initWithString:#"other" ];
I am getting value from JSON it gives exception var is not CFString.
below is the link from which i am getting data
http://www.krsconnect.no/community/api.html?method=categories&appid=620&mainonly=true
NSString *test = aBook.catId;
Book Class
#interface Book : NSObject {
NSString *catId;
NSString *name;
}
#property(nonatomic,retain)NSString*catId;
#property(nonatomic,retain) NSString *name;
#end
#import "Book.h"
#implementation Book
#synthesize catId,name;
-(id)init{
self=[super init];
}
- (id)initWithDictionary:(NSDictionary*) dict {
self.catId = [dict valueForKey:#"categoryId"];
self.name = [dict valueForKey:#"name"];
return self;
}
- (void)dealloc {
[catId release];
[name release];
[super dealloc];
}
#end
Its an integer maybe. Use this.
NSString* test = [NSString stringWithFormat:#"%d",aBook.catId];
I think this question should help you
Replace multiple characters in a string in Objective-C?
CFStringRef aCFString = (CFStringRef)aNSString;
works perfectly and transparently. Likewise:
NSString *aNSString = (NSString *)aCFString;
When using a property of type NSMutableDictionary outside of the class I cannot add objects.
This is the class.h file
#interface cSummary : NSObject
{
#public
NSMutableDictionary* PaymentMethodSalesTotals;
}
#property (nonatomic, retain) NSMutableDictionary* PaymentMethodSalesTotals;
#end
The class.m file is like this
#import "cSummary.h"
#implementation cSummary
#synthesize PaymentMethodSalesTotals;
#pragma mark -
#pragma mark Initialisation
-(id)init
{
return [super init];
PaymentMethodSalesTotals = [[ NSMutableDictionary alloc] init];
[PaymentMethodSalesTotals setObject:[NSNumber numberWithFloat:0.0f] forKey:[NSNumber numberWithInt:10]];
[PaymentMethodSalesTotals setObject:[NSNumber numberWithFloat:0.0f] forKey:[NSNumber numberWithInt:20]];
[PaymentMethodSalesTotals setObject:[NSNumber numberWithFloat:0.0f] forKey:[NSNumber numberWithInt:30]];
}
#pragma mark -
#pragma mark Memory management
- (void)dealloc
{
if (PaymentMethodSalesTotals != nil)
[PaymentMethodSalesTotals release];
[super dealloc];
}
#end
Then this is used in another class like this
cSummary* oSummary = [[cSummary alloc] init];
NSNumber* numPrice = [NSNumber numberWithFloat:150.0f];
[oSummary.PaymentMethodSalesTotals setObject:numPrice forKey:[NSNumber numberWithInt:10]];
If I view this in debug the PaymentMethodSalesTotals collection still has no values in it?
In init you return first so the dictionary isn't allocated/instantiated. Move the return to the end of the method.
-(id)init
{
return [super init]; //!!!!!!!!!!!!
PaymentMethodSalesTotals = [[ NSMutableDictionary alloc] init];
....
}
this my problem i have a class X that inherits UITableViewController class and a class Y that inherits the X class, when i try to override a method in the Y class the method in the X class is invoked... and i can't find references to understand what's happening... can anyone help me?
Thanks in advance!
Code!
mluListBuilder.h
#import <UIKit/UIKit.h>
#interface mluListBuilder : UITableViewController {
NSString *sListTitle;
NSString *sEntityName;
NSArray *aEntityProperties;
NSMutableArray *maListRecords;
NSManagedObjectContext *mocList;
NSFetchRequest *frListRecords;
NSEntityDescription *edListRecords;
NSArray *aOrderByProperties;
NSArray *aToolBarItems;
NSArray *aToolBarItemsActions;
}
#property (nonatomic, retain) NSString *sListTitle;
#property (nonatomic, retain) NSString *sEntityName;
#property (nonatomic, retain) NSArray *aEntityProperties;
#property (nonatomic, retain) NSMutableArray *maListRecords;
#property (nonatomic, retain) NSManagedObjectContext *mocList;
#property (nonatomic, retain) NSFetchRequest *frListRecords;
#property (nonatomic, retain) NSEntityDescription *edListRecords;
#property (nonatomic, retain) NSArray *aOrderByProperties;
#property (nonatomic, retain) NSArray *aToolBarItems;
#property (nonatomic, retain) NSArray *aToolBarItemsActions;
- (id) initWithStyle: (UITableViewStyle) style
listTitle: (NSString *) psListTitle
entityName: (NSString *) psEntityName
entityProperties: (NSArray *) paEntityProperties
orderListByProperties: (NSArray *) paOrderByProperties
toolBarItems: (NSArray *) paToolBarItems
toolBarItemsActions: (NSArray *) paToolBarItemsActions;
- (void)newRecord;
- (void)deleteRecord;
#end
mluListBuilder.m
#import "mluListBuilder.h"
#implementation mluListBuilder
#synthesize sListTitle,
sEntityName,
aEntityProperties,
maListRecords,
mocList,
frListRecords,
edListRecords,
aOrderByProperties,
aToolBarItems,
aToolBarItemsActions;
- (id) initWithStyle: (UITableViewStyle) style
listTitle: (NSString *) psListTitle
entityName: (NSString *) psEntityName
entityProperties: (NSArray *) paEntityProperties
orderListByProperties: (NSArray *) paOrderByProperties
toolBarItems: (NSArray *) paToolBarItems
toolBarItemsActions: (NSArray *) paToolBarItemsActions
{
sListTitle = psListTitle;
sEntityName = psEntityName;
aEntityProperties = paEntityProperties;
aOrderByProperties = paOrderByProperties;
aToolBarItems = paToolBarItems;
aToolBarItemsActions = paToolBarItemsActions;
if (self = [super initWithStyle:style]) {
}
return self;
}
- (void)viewDidLoad {
self.title = NSLocalizedString(sListTitle, nil);
if ([aToolBarItems count] > 0) {
NSMutableArray *maToolBarItems = [[NSMutableArray alloc] init];
self.navigationController.toolbarHidden = NO;
for (int i = 0; i < [aToolBarItems count]; i++) {
UIBarButtonItem * bbiToolBarItem = [[UIBarButtonItem alloc]
initWithTitle:NSLocalizedString([aToolBarItems objectAtIndex:i], nil)
style:UIBarButtonItemStyleBordered
target:self
action:NSSelectorFromString([aToolBarItemsActions objectAtIndex:i])
];
[maToolBarItems addObject:bbiToolBarItem];
}
self.toolbarItems = maToolBarItems;
} else {
self.navigationController.toolbarHidden = YES;
}
if (mocList != nil) {
frListRecords = [[NSFetchRequest alloc] init];
NSSortDescriptor *sdListRecords = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
[frListRecords setSortDescriptors:[[NSArray alloc] initWithObjects:sdListRecords, nil]];
edListRecords = [NSEntityDescription entityForName:sEntityName inManagedObjectContext:mocList];
[frListRecords setEntity:edListRecords];
NSError *errFetchRequest;
maListRecords = [[mocList executeFetchRequest:frListRecords error:&errFetchRequest] mutableCopy];
}
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
NSError *errFetchRequest;
maListRecords = [[mocList executeFetchRequest:frListRecords error:&errFetchRequest] mutableCopy];
[self.tableView reloadData];
if (self.navigationController.toolbarHidden == YES) {
if ([aToolBarItems count] > 0) {
self.navigationController.toolbarHidden = NO;
}
}
}
- (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;
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [maListRecords count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
for (UIView *vwExisting in cell.contentView.subviews) {
[vwExisting removeFromSuperview];
}
NSEntityDescription *edCurrentRecord = [maListRecords objectAtIndex:indexPath.row];
UILabel *lblCell = [[UILabel alloc] initWithFrame:CGRectMake(5.0, 5.0, 280, 20.0)];
[lblCell setText:edCurrentRecord.name];
[cell.contentView addSubview:lblCell];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
// [self.navigationController pushViewController:anotherViewController];
// [anotherViewController release];
}
- (void)dealloc {
[super dealloc];
}
- (void)newRecord {
NSLog(#"%#", [self class]);
}
- (void)deleteRecord {
}
#end
mluLawyerCaseSituationsList.h
#import <Foundation/Foundation.h>
#import "mluListBuilder.h";
#interface mluLawyerCaseSituationsList : mluListBuilder {
}
- (void)newRecord;
#end
mluLawyerCaseSituationsList.m
#import "mluLawyerCaseSituationsList.h"
#implementation mluLawyerCaseSituationsList
- (void)newRecord {
NSLog(#"%#", [self class]);
}
#end
Calling the mluLawyerCaseSituationsList
mluLawyerCaseSituationsList *vcCaseSituations = [[mluListBuilder alloc]
initWithStyle:UITableViewStylePlain
listTitle:#"titCaseSituations"
entityName:#"case_situations"
entityProperties:[[NSArray alloc] initWithObjects:#"name", nil]
orderListByProperties:[[NSArray alloc] initWithObjects:#"name", nil]
toolBarItems:[[NSArray alloc] initWithObjects:#"btNew", nil]
toolBarItemsActions:[[NSArray alloc] initWithObjects:#"newRecord", nil]
];
Output... :(
2009-12-17 17:30:02.726 mluLawyer[2862:20b] mluListBuilder
Hope it helps...
I’ve been looking through your code only briefly, but it seems obvious (from code and from the output) that you allocate an instance of class X (mluListBuilder).
Of course, you cannot expect to have a method of class Y (mluLawyerCaseSituationsList), performed when Y is derived from X and the object is of class X.
So, you have:
#interface X : UITableViewController
- (void) method;
#end
#interface Y : X
- (void) method;
#end
You are calling -method, but it is being invoked on X, not Y? Only way that can happen is if you have an instance of X instead of Y (or if someone is playing very silly buggers with the runtime -- unlikely).
Add NSLog(#"%#", [self class]); to the method implementations and see what the class of the instance really is!
You don't give us much information in your question, but the following is how it should work:
Class_X.h:
#interface Class_X : UITableViewController
{
}
- (void)someMethod;
#end
Class_X.m:
#import "Class_X.h"
#implementation Class_X
- (void)someMethod
{
NSLog(#"method in Class_X was called");
}
#end
Class_Y.h:
#import "Class_X.h"
#interface Class_Y : Class_X
{
}
- (void)someMethod;
#end
Class_Y.m:
#import "Class_Y.h"
#implementation Class_Y
- (void)someMethod
{
NSLog(#"method in Class_Y was called");
}
#end
Elsewhere:
#import "Class_Y.h"
...
Class_X * x_instance = [[Class_X alloc] init];
Class_Y * y_instance = [[Class_Y alloc] init];
[x_instance someMethod];
[y_instance someMethod];
[Class_Y release];
[Class_X release];
Output:
method in Class_X was called
method in Class_Y was called