NSMutableArray vs NSArray - objective-c

i have created a script, witch load the XML from server parse it an save it to NSMutableArray
[kategorienArray addObject:catName];
catName ist a String, if i NSLog the Array everything works fine.
After that i have created a tebleview, and reload Data
[kategorienAuswahl reloadData];
KategorienAuswahl is my TableView
and now a get the Problems
if i Use a "normal" array
NSArray *array = [[NSArray alloc] initWithObjects:#"iPhone", #"iPod", #"iPad",nil];
self.listData = array;
[array release];
the will be displayed, but if i use
cell.textLabel.text = [kategorienArray objectAtIndex:row];
i get EXC_BAD_ACCESS
instead it works fine with
cell.textLabel.text = [listData objectAtIndex:row];
I Add nwo
kategorienArray = [[NSMutableArray alloc] init];
kategorienArray = [NSMutableArray arrayWithCapacity:10];
but now i get no data in my Tableview

You might not have initialized your kategorienArray.
Do you have a kategorienArray = [[NSMutableArray alloc] init]; in your code? You should have done this before adding objects to it and then accessing them.
Also, make sure your array is retained at the point where it's created, so that the system doesn't reclaim its memory before you access its items. The way I use to make sure things are going right is to declare the mutable array as a property. In your viewcontroller's .h file put
#property (nonatomic, retain) NSMutableArray *kategorienArray;
and in your .m file put
#synthesize kategorienArray;
at the top and then
self.kategorienArray = [NSMutableArray array];
in viewDidLoad or somewhere, before adding items to it.

The problem may be that 'kategorienArray' has been (auto)released.
Is 'kategorienArray' an ivar ?
Check out if when you created the array you correctly retained it (particularly if you created it with a class method).

Related

Confusion about modifying NSMutableArray contents after using addObject:

So, when I modify things inside of an NSMutableArray I don't get the result I expect. I think the best way to frame this question is with an example. The following code prints "george" (as expected):
NSMutableArray *originalArray = [[NSMutableArray alloc] initWithObjects:#"sally",#"george", nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
[secondArray addObject:originalArray[1]];
secondArray[0] = #"priscilla";
NSLog(#"%#",originalArray[1]);
But this code prints "priscilla":
TestClass *test1 = [[TestClass alloc] init];
test1.clientName = #"sally";
TestClass *test2 = [[TestClass alloc] init];
test2.clientName = #"george";
NSMutableArray *originalArray = [[NSMutableArray alloc] initWithObjects:test1,test2, nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
[secondArray addObject:originalArray[1]];
TestClass *objectTakenFromSecondArray = secondArray[0];
objectTakenFromSecondArray.clientName = #"priscilla";
NSLog(#"%#", ((TestClass *)originalArray[1]).clientName);
I thought that addObject: always copied the object before adding it to the array receiving the addObject: message. Is this not the case?
Thanks!
p.s. here is the interface and implementation for TestClass in case it is pertinent:
#interface TestClass : NSObject
#property (strong,nonatomic) NSString *clientName;
#end
#implementation TestClass
#synthesize clientName = _clientName
#end
I thought that addObject: always copied the object before adding it to the array receiving the addObject: message. Is this not the case?
addObject: does not copy the object. NSArray does not require that its contents even be copyable (not everything is). That probably explains the confusion. If you want to copy it, you need to do so yourself.
You pretty much answered your own question. When you create an NSMutableArray and add an object to it, you are just creating a pointer to that object, wherever it is stored. If you add the same object to another NSMutableArray, that too contains a pointer to the same thing. You might not need the analogy, but for anyone else confused - the NSMutableArray is like a postman with an address to post to, and the object is the house at that address. Two postmen (or two arrays) can have an address for the same house, but there is only one house still. (That is, unless someone explicitly 'copies' the house).
So in your second to last line of code, where you change that .clientName property, you are changing the property of the original *test2 object.
Worth noting in this case, that if you remove that second array, you don't remove the objects it contains necessarily. So in your case, removing that second NSMutableArray from memory does not mean that all of its objects also disappear from memory - unless everything else that points to those objects also is removed. The array does not contain pointers to unique copy of those objects - it just points to the originals.

unable to store an image in an NSMutableArray

I am trying to save an image in an NSMutable array and it is not working
here is what I am doing
[imagesList addObject:[UIImage imageNamed:#"b.png"]];
after executing this line I noticed that the number of objects remains 0
any reason ?
Thanks
I repeate this code in several areas :
Globally I declare :
NSMutableArray *imagesList;
NSUserDefaults *imagesHistory;
in my viewdidload method I write:
imagesHistory=[NSUserDefaults standardUserDefaults]; //imagesHistory is created globallt as NSUserDefault imagesHistory
[imagesHistory setObject:imagesList forKey:#"images history"];
UIImage *image;
image=[UIImage imageNamed:#"b.png"];
[imagesList addObject:image];
imagesHistory=[NSUserDefaults standardUserDefaults];
[imagesHistory setObject:imagesList forKey:#"images history"];
and in the didFinishLaunchingWithOptions I write : (even though I don t need to do it when I am adding strings ...)
imagesList = [[NSMutableArray alloc] init];
Regardless of whether it is a global variable or not, you still need to call alloc and init SOMEWHERE for the object. If you intend to use it throughout your app, then appDidFinishLaunchingWithOptions is a decent place to add this call:
imagesList = [[NSMutableArray alloc] init];
Is your empty array being retained? If you're not using Automatic Reference Counting, there's a good chance you're initializing the array with the following
imagesList = [[NSMutableArray alloc] init];
but it's not being retained. You'll want to retain the empty array so it gets appended to further on in your code.
imagesList = [[[NSMutableArray alloc] init] retain];
Just don't forget to release the array when you're all done with it, in viewDidUnload or wherever is appropriate.
You're allocating/initing imagesList AFTER you try to add an object. You need to alloc/init imageList before you add anything to it.
To make sure it's there, try something like this:
if (!imagelist) imageList = [[NSMutableArray alloc] init];
If it exists, and you're still having this problem, it's possible that you're allocating/initing a new NSMutableArray and assigning it to imageList after you've added the object. This means the old array would be discarded and you'd be left with a new array with zero items.
try UIImageView *image;
image=[UIImage imageNamed:#"b.png"];
also, in #property(nonatomic,retain) use 'strong' instead of 'retain'

Where do I create global variables for an iOS app?

Here is my code:
I want to be able to create a global NSMutableArray that can store Budget* objects that can then be written to a .pList file... I'm only learning what pLists are, and I am a bit hazy about how to implement them...
Where am I going wrong here?
- (IBAction)btnCreateBudget:(id)sender
{
Budget *budget = [[Budget alloc] init];
budget.name = self.txtFldBudgetName.text;
budget.amount = [self.txtFldBudgetAmount.text intValue];
// Write the data to the pList
NSMutableArray *anArray = [[NSMutableArray alloc] init]; // I want this to be a global variable for the entire app. Where do I put this?
[anArray addObject:budget];
[anArray writeToFile:[self dataFilePath] atomically:YES];
/* As you can see, below is where I test the code. Unfortunately,
every time I run this, I get only 1 element in the array. I'm assuming
that this is because everytime the button is pressed, I create a brand new
NSMutableArray *anArray. I want that to be global for the entire app. */
int i = 0;
for (Budget * b in anArray)
{
i++;
}
NSLog(#"There are %d items in anArray",i);
}
-(NSString *) dataFilePath
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"BudgetData.plist"];
}
edit: I'd like to add that I am creating the anArray array so that it can be accessible by other views. I understand that this can be done with NSNotification? or Should I do this the appDelegate classes? The end goal is to have the anArray object populate a UITableView that is in a separate View.
Just put the declaration outside the method instead of inside it.
NSMutableArray *anArray = nil;
- (IBAction)btnCreateBudget:(id)sender
{
...
if ( anArray == nil )
anArray = [[NSMutableArray alloc] init];
...
}
If it's only used inside the one file, make it "static" instead to prevent name collisions with other files:
static NSMutableArray *anArray = nil;
If it's only used inside the one method, make it "static" and put it inside that method:
- (IBAction)btnCreateBudget:(id)sender
{
static NSMutableArray *anArray = nil;
...
if ( anArray == nil )
anArray = [[NSMutableArray alloc] init];
...
}
Note that people usually use some kind of naming convention for global variables, like "gArray", to easily differentiate them from local variables, instance variables, or method parameters.
Global variable is not necessary in this case. You can do something like this:
Read old data to mutable array (initWithContentsOfFile:).
Add new record to the array.
Save the array to same file.
But the second problem in your code is that if your Budget class is not a property list type (NSString, NSData, NSArray, or NSDictionary objects) writeToFile: will not save it sucessfully.
You need to make sure that your Budget class invokes NSCoder and then the NSCoder initWithCoder: and NSCoder decodeWithCoder: methods. Otherwise, writeToFile: will not work for you NSObject class.
But I digress. The answer to the original question should be the following.
In your .h file you need to do the following.
#interface WhateverClassName : UIViewController
{
NSMutableArray *anArray;
}
#property(nonatomic, retain) NSMutableArray *anArray;
#end
Then, you need to make sure you #synthesize the NSMutableArray so that you don't get any freaky warnings. This is done just after the #implementation line in your .m file.
Then, within the function that you want it to be allocated into memory, simply do the following.
anArray = [[NSMutableArray alloc] initWithObjects:nil];
This is now a global variable. It is global in the sense that it can be used from any function and is not limited to use in one function.
If you would like to have data accessible to the entire application or context ("global"), you can use a singleton. However, do this with care and make sure it is actually necessary and appropriate. I would suggest doing plenty of reading up on it prior to any implementation of a singleton. Carter Allen has a good basic implementation here.
According to "The end goal is to have the anArray object populate a UITableView that is in a separate View" you wouldn't need to write anything to a file, database or singleton. Just set the object. Like stated by Sebastien Peek.
If you wish for offline data storage, look into sqlite, json, plist , etc

NSMutableArray becomes empty when I call any IBAction

Please help me i have a NSMutableArray which contains data until viewDidLoad is finished.
When I click any button I try to get the data in it and it just disappears.
If you created your array with a variant of [NSMutableArray array] it will be autoreleased. Assuming myArray is a property of your class, you should use
myArray = [[NSMutableArray] alloc] init]; //or initWithCapacity, etc.
If you still use reference counting, you need to add [myArray retain]; unless it is already retained in the #property declaration and release it in viewDidUnload:.

How to append two NSMutableArray's in Iphone sdk or append an NSArray With NSMutableArray?

I need to append two NSMUtableArray's can any one suggest me how it possible?
My code is:
NSMutableArray *array1 = [appDelegate getTextList:1];
NSArray *array2 = [appDelegate getTextList:2];
[array1 addObjectsFromArray:array2];//I am getting exception here.
Anyone's help will be much appreciated.
Thanks all,
Lakshmi.
What's probably happening, is that your [appDelegate getTestList:1] is not actually returning a NSMutableArray, but a NSArray. Just typecasting the array as mutable by holding a pointer to it like that will not work in that case, instead use:
NSMutableArray *array1 = [[appDelegate getTextList:1] mutableCopy];
NSArray *array2 = [appDelegate getTextList:2];
[array1 addObjectsFromArray:array2];
Or you could store the 'textList' variable that you have in your appDelegate as an NSMutableArray in the first place. I am assuming that you have an NSArray of NSArrays (or their mutable versions). Eg.
// In the class interface
NSMutableArray *textLists;
// In the function in which you add lists to the array
NSMutableArray *newTextList;
[self populateArray:newTextList]; // Or something like that
[textLists addObject:newTextList];
Note: that you will probably have a different workflow, but I hope that you get the idea of storing the actual lists as NSMutableArrays.
Another Note: the second method WILL modify in place the NSMutableArray that [appDelegate getTextList:1]; returns
Try this:
NSMutableArray *result =
[[appDelegate getTextList:1] mutableCopy]
addObjectsFromArray:[appDelegate getTextList:2]];
You're getting the exception because you're trying to send mutating messages to an immutable array.