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.
Related
I have made a very simple custom object pictureData.
Here is the .h file
#import <Foundation/Foundation.h>
#interface pictureData : NSObject {
NSString *fileName;
NSString *photographer;
NSString *title;
NSString *license;
}
#property (nonatomic, retain) NSString *fileName;
#property (nonatomic, retain) NSString *photographer;
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *license;
+(pictureData*)picDataWith:(NSDictionary*)dictionary;
#end
The .m file
#import "pictureData.h"
#implementation pictureData
#synthesize fileName;
#synthesize photographer;
#synthesize title;
#synthesize license;
+ (pictureData*)picDataWith:(NSDictionary *)dictionary {
pictureData *tmp = [[[pictureData alloc] init] autorelease];
tmp.fileName = [dictionary objectForKey:#"fileName"];
tmp.photographer = [dictionary objectForKey:#"photographer"];
tmp.title = [dictionary objectForKey:#"title"];
tmp.license = [dictionary objectForKey:#"license"];
return tmp;
}
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
}
#end
I then set up these objects in an array, like so:
NSString *path = [[NSBundle mainBundle] pathForResource:#"pictureLicenses" ofType:#"plist"];
NSArray *tmpDataSource = [NSArray arrayWithContentsOfFile:path];
NSMutableArray *tmp = [[NSMutableArray alloc] init];
self.dataSource = tmp;
[tmp release];
for (NSDictionary *dict in tmpDataSource) {
pictureData *pic = [pictureData picDataWith:dict];
NSLog(#"%#", pic.title);
[self.dataSource addObject:pic];
}
Everything works smashingly. I have a table view which loads the proper picture images, and information, no problem. Upon running Instruments for leaks, I see that my pictureData object is leaks with every allocation.
I would assume that with having my object autoreleased I would not have to worry about manually allocating and deallocating them.
Perhaps is my issue that I use autorelease, which the autoReleasePool keeps a retain count of +1 and then when I add a pictureData object to my array, that also retains it? Thank you all for your time!
edit: Don't forget to call super! Thank you Sam!
Change dealloc to:
-(void)dealloc {
[fileName release];
[photographer release];
[title release];
[license release];
[super dealloc];
}
(call [super dealloc])
In your function, change the return value to include autorelease, like
+ (pictureData*)picDataWith:(NSDictionary *)dictionary
{
...
...
return [tmp autorelease];
}
When you add pictureData object to dataSource, you increase the retain count, so you should autorelease it while returning.
Hope it helps.
I have 3 classes
First -> MainViewController:
#interface MainViewController : UIViewController {
UtilityBadah *utility;
}
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
- (IBAction)option;
#end
#implementation MainViewController
#synthesize managedObjectContext = _managedObjectContext;
(IBAction)option{
UtilityBadah *util = [[UtilityBadah alloc] initWithContext:_managedObjectContext];
OptionController *ovc = [[OptionController alloc] init];
ovc.util = util;
ovc.managedObjectContext = _managedObjectContext;
[self.navigationController pushViewController:ovc animated:YES];
[util release];
[ovc release];
}
#end
Second -> UtilityBadah:
#interface UtilityBadah : NSObject {
NSManagedObjectContext *managedObjectContext;
NSString *kitab;
NSString *lagu;
NSString *font;
NSString *sizefont;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSString *kitab;
#property (nonatomic, retain) NSString *lagu;
#property (nonatomic, retain) NSString *font;
#property (nonatomic, retain) NSString *sizefont;
(id) initWithContext: (NSManagedObjectContext *) context;
#end
#implementation UtilityBadah
#synthesize managedObjectContext;
#synthesize kitab;
#synthesize lagu;
#synthesize font;
#synthesize sizefont;
-(id) initWithContext: (NSManagedObjectContext *) context {
NSError *err;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *enDesc = [NSEntityDescription entityForName:#"OptionDB" inManagedObjectContext:context];
[request setEntity:enDesc];
NSArray *arrData = [context executeFetchRequest:request error:&err];
for (OptionDB *data in arrData) {
lagu = data.lagu;
kitab = data.kitab;
font = data.font;
sizefont = data.sizefont;
}
return self;
}
Thrid -> OptionController:
#interface OptionController : UIViewController{
NSManagedObjectContext *managedObjectContext;
UtilityBadah *util;
}
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) UtilityBadah *util;
#end
(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
bla..bla..
NSLog(#"value is %#",self.util.kitab);
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
}
i wonder why this piece of code:
NSLog(#"value is %#",self.util.kitab);
cause an error "Receiced signa: "EXC_BAD_ACCESS" ?
i wonder ther somthing wrong the way i passed the UtilityBadah object from MainViewController to my OptionController.
Many thanks for any answer.
P.S what is wrong with my xcode 4.2 error information, why it always show "Program received signal: "EXC BAD ACCESS"? cant it be informative?
i think your init method is wrong, try assigning self to [super init] at the start, and doing all your set up after checking that self != nil. this is the basic form of an init:
- (id)init
{
self = [super init];
if (self)
//do setup
return self;
}
also, you are using a subclass of NSObject and associating a managed object context to it, you should look into core data in more detail, you should be using NSManagedObjects
The property name in the OptionController is util not utility
If you want to access the utility property in the UtilityBadah class you will have to do:
self.util.utility
In the UtilityBadah class, initWithContext method, change the for loop as following
for (OptionDB *data in arrData) {
self.lagu = data.lagu;
self.kitab = data.kitab;
self.font = data.font;
self.sizefont = data.sizefont;
}
In your case, the value is not retained since you have assigned without accessing through the property.
You need to allocate those objects first. Here's how your initWithContext method should look like:
-(id) initWithContext: (NSManagedObjectContext *) context {
self = [super init];
if (self) {
NSError *err;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *enDesc = [NSEntityDescription entityForName:#"OptionDB" inManagedObjectContext:context];
[request setEntity:enDesc];
NSArray *arrData = [context executeFetchRequest:request error:&err];
for (OptionDB *data in arrData) {
self.lagu = [NSString stringWithString:data.lagu];
self.kitab = [NSString stringWithString:data.kitab];
self.font = [NSString stringWithString:data.font];
self.sizefont = [NSString stringWithString:data.sizefont];
}
}
return self;
}
I am trying to build a Grouped Sectioned View. I want to set an array as an object in the dictionary but I came across the empty array Issues.
Is this Even possible????? Is There a trick ????
#import "RootViewController.h"
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Get the specific Node for this row.
Nodes *nodes = (Nodes *)[nodesMArray objectAtIndex:indexPath.row];
// Create the Details View Controller and initialize it.
nodesDetailView *viewController = [[nodesDetailView alloc] initWithStyle:UITableViewStyleGrouped ];
[[self navigationController] pushViewController:viewController animated:YES];
// Set the title of the view to the nodes name
viewController.title = [nodes computer_name];
//Information
//Network Data
viewController.ipaddress= [nodes ipaddress];
viewController.subnet_mask= [nodes subnet_mask];
viewController.gateway= [nodes gateway];
viewController.domain_name= [nodes domain_name];
}
#import "nodesDetailViewController. h
#interface nodesDetailView : UITableViewController{
//Network Data
NSString *ipaddress;
NSString *subnet_mask;
NSString *gateway;
NSString *domain_name;
//Grouped
NSMutableArray *Keys;
NSMutableDictionary *Contents;
}
#property (nonatomic, retain) NSMutableArray *Keys;
#property (nonatomic, retain) NSMutableDictionary *Contents;
#property (nonatomic, retain) NSString *ipaddress;
#property (nonatomic, retain) NSString *subnet_mask;
#property (nonatomic, retain) NSString *gateway;
#property (nonatomic, retain) NSString *domain_name;
#end
#import "nodesDetailViewController. m
#synthesize .......
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
NSMutableArray *keys = [[NSMutableArray alloc] init];
NSMutableDictionary *contents = [[NSMutableDictionary alloc] init];
NSString *network = #"Network Data";
NSString *product = #"Product Details";
//IS THIS POSSIBLE ??????? Because I get An Empty array
[contents setObject:[NSArray arrayWithObjects: ipaddress,subnet_mask, gateway, domain_name, nil] forKey:network];
return self;
}
Thank You In Advance.
All of those strings that you are adding to the array haven't even been allocated/initialized yet. That's why the array is empty. You can't just go: NSString *emptyString; and then go: [myArray addObject:emptyString];. Your strings are all empty.
Check the values u are passing from the table view. They maybe nil. I just used this much of data and i m getting correct NSLog.
NSMutableDictionary *contents = [[NSMutableDictionary alloc] init];
NSString *my = #"kk";
NSString *my1 = #"polko";
[contents setObject:[NSArray arrayWithObjects: my1,my, nil] forKey:#"o"];
NSLog(#"%#" , contents);
For Those Who are wondering: Problem Solved My code was fine. the problem was :
it was in the wrong place.
The Code Supposed to be in - (void)viewDidLoad and not in - (id)initWithStyle:
I want to thank everybody who took the time to look in to it.
I have no idea why i put the code there to begin with.
Thanx Again
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;
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.