I'm really frustrated after spending like three hours googling around to solve this problem!! It's probably an easy solution to it aswell.
I'm creating a really simple TableView app for the iPhone. It's supposed to fetch an XML-document and parse it (already fixed) and then put the data into objects called HPobject!
One HPobject represents one day of data from the XML-file. Anyhow!
Then I want the object to be stored in a NSMutableArray so I can grab it later when I'm creating the table rows. But I can't access it! My NSMutableArray is ALWAYS null! No matter what I do!
Here's my code:
//THE .h FILE
#import "TBXML.h"
#import "HPobject.h"
#interface RootViewController : UITableViewController {
NSMutableArray *listOfItems;
}
- (void)traverseElement:(TBXMLElement *)element;
//THE .m FILE
#import "RootViewController.h"
#import "HPobject.h"
#implementation RootViewController
- (void)viewDidLoad
{
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
TBXML * tbxml = [[TBXML tbxmlWithURL:[NSURL URLWithString:#"http://www.hpprov.se/istasts.php?q=xxxxxxx"]] retain];
if (tbxml.rootXMLElement)
[self traverseElement:tbxml.rootXMLElement]; //Works fine!
[tbxml release];
[super viewDidLoad];
}
- (void) traverseElement:(TBXMLElement *)element {
do {
//Lots of parsing code which all works fine and gets me the variables up next!
HPobject *currentObject = [[HPobject alloc] init];
currentObject.antalRegistrerade = numRegistrerade;
currentObject.inkomstBrutto = numBrutto;
currentObject.inkomstNetto = numNetto;
[listOfItems addObject:currentObject];
NSLog(#"Array: %#", listOfItems); //RETURNS null!
NSLog(#"Reg: %#, Net: %#, Brutt: %#", currentObject.antalRegistrerade, currentObject.inkomstNetto, currentObject.inkomstBrutto); //Returns the correct values!
NSLog(#"%d stycken!", listOfItems.count); //Returns 0!! :(
[currentObject release];
} while ((element = element->nextSibling));
}
You are defining listOfItems locally in viewDidLoad and then you try to access that in another method.
Make sure you are using an instance variable defined in your interface definition (header).
replace this line in viewDidLoad:
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
with
listOfItems = [[NSMutableArray alloc] init];
I suppose that listOfItems is an ivar. So to fix your problem change this:
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
to this
listOfItems = [[NSMutableArray alloc] init];
Take a look at the scope of your array. You have created that as a variable of another method. It will not visible in others. Make an instance var.
Related
I'm basically trying to add a new string to my NSMutableArray using this code in ViewWillAppear
NSUserDefaults *favBooksDefaults = [NSUserDefaults standardUserDefaults];
self.favBook = [favBooksDefaults stringForKey:#"favBook"];
self.favBookList = [[NSMutableArray alloc]init];
[self.favBookList addObject:favBook];
Of course, while I do this, I want to preserve ALL the previous strings that were present in the Array. Because when I add a new string for the NSUserDefaults and then to the Array, it simply substitutes the old one.
Why is that and how can I save all the objects?
Thanks in advance.
Mr Br.'s answer is correct:
In your header file declare favBookList as a property and include a book adding method:
#interface yourViewController : UIViewController {
NSMutableArray *favBookList;
}
-(void)addBook;
#property (nonatomic, retain) NSMutableArray *favBookList;
In your viewDidLoad method, initialize favBookList. Don't forget #synthesize!
-(void)viewDidLoad {
self.favBookList = [[NSMutableArray alloc] init];
[super viewDidLoad];
}
Now you are free to add a book from your user defaults at any time.
-(void)addBook{
self.favBook = [[NSUserDefaults standardUserDefaults] stringForKey:#"favBook"];
[favBookList addObject:favBook];
}
When you alloc and init a new NSMutableArray object you will have an empty array with no values in it. It doesn't substitute it as there is nothing to substitute in there. It just adds the NSSString as the first value. This of course happens EVERY time you alloc/init a new instance of NSMutableArray.
SOLUTION: Make the NSMutableArray a instance variable of your view controller. alloc/init it once (e.g. in the viewDidLoad). Every time viewWillAppear gets called you can add values without reinitializing a new NSMutableArray.
NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray];
[newArray replaceObjectAtIndex:oldObjectIndex withObject:newObject] // if you want to replace oldObject with newObject;
[newArray addObject:newObject] // if you want to add object to the array;
If i get it right you want to replace the old object with new one?
NSUserDefaults *favBooksDefaults = [NSUserDefaults standardUserDefaults];
self.favBook = [favBooksDefaults stringForKey:#"favBook"];
if ([self.favBookList indexOfObject:self.favBook] != NSNotFound) {
[self.favBookList addObject:favBook];
}
You should also init your favBookList in viewDidLoad method:
self.favBookList = [NSMutableArray array];
I have simple question. This is my header file :
#import <UIKit/UIKit.h>
#interface FirstFaceController : UIViewController
#property (nonatomic,retain) NSMutableDictionary *face1Layers;
#end
This .m, here i init my Dictionary and put where UIImageView :
#import "FirstFaceController.h"
#implementation FirstFaceController
#synthesize face1Layers;
-(void) dealloc {
[face1Layers release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.face1Layers = [NSMutableDictionary dictionary];
[self.face1Layers setObject:
[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pic.png"]]
forKey:#"pic"];
[self.view addSubview:[self.face1Layers objectForKey:#"pic"]];
if ( [[face1Layers objectForKey:#"pic"] superview] == nil ) {
//....
}
}
Then i call [[face1Layers objectForKey:#"pic"] superview] i have "EXC_BAD_ACCESS".
Why?
Try to do this:
NSMutableDictionary* tempDict = [[NSMutableDictionary alloc] init];
self.face1Layers = tempDict;
UIImageView* picView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"pic.png"]];
[self.face1Layers setObject:picView forKey:#"pic"];
[picView release];
[tempDict release];
Do not create and insert yours NSMutableDictionary and UIImageView throught a single line of code because you have leaks.
In the first case, if you do the following you have a retain count of two. face1Layers has a retain policy.
self.face1Layers = [[NSMutableDictionary alloc] init];
You can avoid this splitting the code as I explained before or send an autorelease message to the initialized object.
In the second case, when you add an object in NSDictionary or NSArray (and theirs subclasses), these classes retain added objects.
Hope it helps.
Well, I think there are a couple of things wrong here:
You never allocate the dictionary as in NSMutableDictionary alloc init
The UIImageView is allocated but never released. I would allocate before setting it as object, and then add it, and then release it
I am trying to addObject to a NSMutableArray once the user taps the Add to Favorites button I can get the data into a NSDictionary, but when I pass the NSDictionary to the Array the NSLog comes back with nil. Am I missing something?
-(IBAction) addtofavorites: (id)sender
{
NSArray *key = [NSArray arrayWithObjects:#"Title", #"Description", nil];
NSArray *objects = [NSArray arrayWithObjects:CurrentTitle, description.text, nil];
NSDictionary *fadd = [[NSDictionary alloc] initWithObjects:objects forKeys:key];
FavoritesViewController *fvc = [[FavoritesViewController alloc] init];
[fvc.favorites addObject:fadd];
[FavoritesViewController release];
}
What I would do is in your header file create an instance variable for your FavoritesViewController that you retain. Then use lazy init when the addtofavorites is pressed. Something like below
if (!detailViewController)
{
self.fvc = [[FavoritesViewController alloc] init];
}
[self.fvc.favorites addObject:fad];
Then just release the FavoritesViewController object in dealloc
- (void)dealloc {
[fvc release];
[super dealloc];
}
FavoritesViewController *fvc = [[FavoritesViewController alloc] init];
[fvc.favorites addObject:fadd];
[FavoritesViewController release];
doesn't look right. You should already have a FavoritesViewController initialized (in which can just access it and call -addObject:)...
EDIT
First, how does the current view controller (the one that has -addtofavorites: defined on it) relate to FavoritesViewController? How would the user navigate between these two view controllers?
Second, would the list of favorites persist across different runs of the app? If so, how do you plan to save/restore favorites?
Third, rather than add favorites to a view controller, you would probably do better to add them to an underlying 'model' that would be used to populate the FavoritesViewController.
Separating the 'model' from the 'view' can be very powerful, while also simplifying your code.
I am using the code below to set my two NSArray ivars:
The issue is, I keep getting a memory leak on the following lines:
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
Is this not the correct way to set ivars from an existing NSArray of items? Any help would be appreciated. I've also tried to autorelease the above two lines, but when I actually access them in another method I get an error that they've already been released.
I have included my Interface and Implementation code below:
Interface .h:
NSArray *followingFriendsArray;
NSArray *followerFriendsArray;
#property (nonatomic, retain) NSArray *followingFriendsArray;
#property (nonatomic, retain) NSArray *followerFriendsArray;
Implementation .m:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
This is how I need to access the arrays:
- (void)followersButtonTapped:(id)sender {
FollowingVC *fvc = [[FollowingVC alloc] initWithNibName:#"FollowingViewController" bundle:nil];
fvc.friends = followerFriendsArray;
[self.navigationController pushViewController:fvc animated:YES];
[fvc release];
}
I release my two ivars in the following way as per usual:
- (void)viewDidUnload {
self.followingFriendsArray = nil;
self.followerFriendsArray = nil;
[super viewDidUnload];
}
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
I mean the code works just fine, it's just that I'm concerned about said memory leaks when I run the "Leaks" performance tool.
OK
you should not use autorelease in this case, but you have to release the arrays by calling :
[followingFriendsArray release];
[followerFriendsArray release];
you can do it:
when you don't need to use them any more.
in the dealloc method in your .m file.
option 2looks like that -
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
BTW -
if you don't manipulate the arrays after creating them (add / remove objects) you should use an immutable array (NSArray).
Good Luck
Your method handlerGetFollowingInformation is assigning new values to followingFriendsArray and followerFriendsArray without releasing the previous contents. If you call this method more than once on the same instance you will leak.
CRD is right that the arrays are not released inside the handlerGeFollowingInformation method but the fix is maybe overkill. What you need to do is to use self. so that the setter method is called which does that automatically. You could should look like this:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
self.followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
self.followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
Easy fix but hard to spot and I ran into this issue over and over again especially when I started to dealloc are the properties.
-Andy
I've got a tableView in a view which is a subview to my MainViewController. When the subview is loaded, I have this in my viewDidLoad method to initialize my tableData:
NSMutableArray *array = [[NSMutableArray alloc] init];
self.listData = array;
[array release];
[super viewDidLoad];
Then I use other methods to add to this data within this view.
When I switch back to my other view, however, then bring up this view again, it initializes the data all over again, erasing my changes. How can I fix this problem?
EDIT:
I tried to initialize this array in MainViewController by doing this:
NSMutableArray *array = [[NSMutableArray alloc] init];
HistoryViewController.listData = array;
[array release];
But it says Accessing unknown 'setListData:' class method.
you should not be initializing your array in view did load
// this is clearing out all of your data
NSMutableArray *array = [[NSMutableArray alloc] init];
self.listData = array;
There is not much code, but I would suggest initializing the listData property when you initialize the ViewController.
I might suggest you review this tutorial here on UITableView, and your code above should be edited
HistoryViewController.listData = array;
should be
self.listData = array;