My NSMutableArray doesn't work - objective-c

sorry for my stupid question (beginner)
I got the demo program Accelerometergraph the apple site and would like to use
NSMutableArray in the values of acceleration x.
but my NSMutableArray contains only one object, there being several passage
NSMutableArray routine and should contain the same number of objects that the counter
show, how code below
if(!isPaused)
{
array = [[NSMutableArray alloc] init];
[filter addAcceleration:acceleration];
[unfiltered addX:acceleration.x y:acceleration.y z:acceleration.z];
NSNumber *number = [[NSNumber alloc] initWithDouble:acceleration.x];
[array addObject:number];
++a;
if (a == 30) // only check the # objs of mutablearray
{
sleep(2);
}
[filtered addX:filter.x y:filter.y z:filter.z];
}

It looks like you're missing a loop of some kind. The code you list above:
Makes sure something isn't paused.
Creates a new (empty) mutable array.
Adds a value to the new array.
And does some other work.
My guess is that this whole if{} block sits inside some kind of loop. You need to alloc and init the mutable array outside of the loop instead.

You create a new array each time the if block is entered, so the addObject: will only add the object to the most recently created array.
Furthermore, you are leaking the array and number objects. Each time you allocate an object, you are responsible for releasing it. Make sure you're familiar with the guidelines set out in the memory management programming guide.

Related

What is the Difference b/w addObject:dictionary and addObject:[dictionary copy] to an NSMutableArray?

I'm trying to set some values to my NSMutableDictionary inside a loop and assigning the dictionary values to an NSMutableArray each time like below,
for(int i=0;i<=lastObj;i++){
[mutableDict setValue:[valuesArray objectAtIndex:i] forKey:#"Name"];
[mutableDict setValue:[uniqueArray objectAtIndex:i] forKey:#"SSN"];
//......then
**[mutableArray addObject:mutableDict];**/*not working perfectly all values s replaced by final mutableDict values (duplicate values)*/
but
**[mutableArray addObject:[mutableDict copy]];**/* Working Correctly !!! */
}
inside loop in each iteration new values is assigned to mutableDictionary and whenever i say just addObject my mutableArray is getting all duplicate values but whenever i say addObject:[mutableDict copy], array is getting correct unique values without any duplicates, i don't know what the difference the compiler feels when i say copy, can anybody tell me the difference in this.
Thanks in advance.
[mutableArray addObject:mutableDict];
keeps on adding mutableDict to mutableArray. adding the object doesnt create a new memory location, it points to the same memory. so when u set the values of mutableDict, it gets reflected in all added objects as they refer to same memory location.
copy creates a new memory location and adds the object removing the above scenario.
to avoid this u can add
for(int i=0;i<=lastObj;i++){
NSMutableDictionary * mutableDict = [NSMutableDictionary new]; //create new memory location
[mutableDict setValue:[valuesArray objectAtIndex:i] forKey:#"Name"];
[mutableDict setValue:[uniqueArray objectAtIndex:i] forKey:#"SSN"];
[mutableArray addObject:mutableDict];
[mutableDict release]; //release
}
hope this helps u. happy coding :)
Looking at your code block, its clear you are allocating mutableDict outside your for loop. Hence When you say below statement inside the for loop, basically you are passing the same object for addition to mutalbeArray.
[mutableArray addObject:mutableDict];
addObject doesnt allocate any memory for objects, but it uses the same object passed and just sends "retain" message to increase the reference count. Since you are passing the same object within the for loop, mutalbeArray would contain the references to same object.
In case of copy say,
[mutableArray addObject:[mutableDict copy]];
the copy message sent to mutableDict returns a new copy which is then passed addObject. Hence every iteration in the forloop passes a new object(due to copy) to addObject.
Also note these following
Copy creates a new object, it should be later released, but your code is not releasing it. This will lead to memory leak.
Copy creates immutable object, hence you should probably use mutableCopy instead if you want objects added to mutableArray to be modified.

Objective C - Leak when setting an array as an object of a dictionary

I wrote a class, which acts as a filter. I pass three objects:
An NSArray, which holds objects to filter (these objects have a timestamp property)
An NSMutableArray (which will hold the section names for a tableView, the periods based on timestamps). I need this array, because I have to sort the periods.
An NSMutableDictionary, in which the keys will be the section names, the values are NSMutableArrays, which hold the items for a given period.
In the class from which I pass these objects, there is a tableView, in which I display the items.
This class has it own NSMutableArray and NSMutableDictionary, I not initialize them, only retain the corresponding return values of the filter class. In the delloc method I release them. There is a method in the filter class:
+ (void)insertItem:(id)item forPeriod:(NSString *)period toContainer:(NSMutableDictionary *)container {
if ( ![[container allKeys] containsObject:period] ) {
// the period isn't stored, create and store it
NSMutableArray *periodArray = [[NSMutableArray alloc] init];
[container setObject:periodArray forKey:period];
[periodArray release];
periodArray = nil;
}
// store the item
NSMutableArray *arrayForPeriod = [container objectForKey:period];
[arrayForPeriod addObject:item];
arrayForPeriod = nil;
}
The instruments shows me leak when I set the newly allocated array as an object of the dictionary. At this point this is definitely true, because the dictionary retains again the array, so after the release, it retain count remains 1. But I think in the caller class when I release the dictionary, the array will be released too. Am I wrong?
Yes it is considered as a leak because your var is a local variable. Then you still have an object in memory but no reference to it. Remember the init makes a retain + the retain made by the dictionary = 2 retains. Just create your array using
NSMutableArray *periodArray = [[[NSMutableArray alloc] init]
autorelease]
Is it clear ?
You could switch to ARC. Alternatively, check what the static analyser thinks of your code. It is pretty good at finding memory leaks, better than most humans.
Once you have a few hundred objects in your dictionary, you waste an awful lot of time and memory. A dictionary doesn't have an array of all keys stashed away somewhere, it has to create it every time you call your method. That's copying a few hundred pointers (cheap) and retaining them (expensive). containsObject for an array compares the object with every object in the array calling isEqual: That's expensive. It's an NSString compare each time. The array is autoreleased, and when it finally goes away, all the keys in it get released. Again expensive.
NSDictionary uses a hash table, so [objectForKey ] will immediately go to the right object. One operation instead of possibly hundreds.

One problem of NSMutableArray

the code is:
typedef struct _Package
{
char* data;
int dataLen;
}Package;
Package *pack=(Package *)malloc(sizeof(pack));
pack->dataLen = 10;
pack->data = (char *)malloc(10);
strcpy(pack->data,"hellohello");
NSMutableArray *lstPack = [[NSMutableArray alloc] init];
[lstPack addobjec:pack];
when the program goto [lstPack addobject:pack],it cann't go on.
If you know the reason,please tell me。
Thank you!
You can add to obj-c containters (including NSMutableArray) only obj-c objects. To add a c-structure to array you can wrap it to NSValue object:
[lstPack addObject:[NSValue valueWithPointer:pack]];
Later you access stored value:
Package* pack = (Package*)[[lstPack objectAtIndex:i] pointerValue];
Note also that you possibly have a typo in that line - method name is incorrect.
“… the result is that the p->data is nil …” — perhaps because of pack->dataLen = (char *)malloc(10);
I think, you wanted to do pack->data = (char *)malloc(10); instead?
Greetings
You can create a CFMutableArray instead which can handle arrays of arbitrary objects, and you can use it as you would an NSMutableArray (for the most part).
// create the array
NSMutableArray *lstPack = (NSMutableArray *) CFArrayCreateMutable(NULL, 0, NULL);
// add an item
[lstPack addObject:pack];
// get an item
Pack *anObject = (Pack *) [lstPack objectAtIndex:0];
// don't forget to release
// (because we obtained it from a function with "Create" in its name)
[lstPack release];
The parameters to CFArrayCreateMutable are:
The allocator to use for the array. Providing NULL here means to use the default allocator.
The limit on the size of the array. 0 means that there is no limit, any other integer means that the array is only created to hold exactly that many items or less.
The last parameter is a pointer to a structure containing function pointers. More info can be found here. By providing NULL here, it means that you don't want the array to do anything with the values that you give it. Ordinarily for an NSMutableArray, it would retain objects that are added to it and release objects that are removed from it¹, but a CFMutableArray created with no callbacks will not do this.
¹ The reason that your code is failing is because the NSMutableArray is trying to send retain to your Pack struct, but of course, it is not an Objective-C object, so it bombs out.

simple NSMutable array question

umm So simple question here:
I have an instance of NSMutableArray declared in my header
NSMutableArray *day19;
#property (nonatomic, retain) NSMutableArray *day19
implementation:
#synthesize day19;
In my viewDidLoad
self.day19 = [[NSMutableArray alloc] init];
In the myMethod where I want to add objects to the array I:
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
However... when i check the day19 array there is nothing in it. If I conversely add the newObject to a tempArray within the myMethod scope and then set the day19 array to the tempArray, day19 has the objects.
Super basic I know just must be a confused morning or something...
thanks for any help
Is day19 actually an instance variable? In the snippet, it's not clear when it's declared as an instance variable or just as a variable outside the scope of the class.
A couple of things:
Are you sure viewDidLoad is the right place to init your array? Confer here.
Also, at least from the code you've got posted, it looks like you're being sloppy with your retains. If your property is a retain type, you should not be writing:
self.myProperty = [[Something alloc] init]; // double retain here, bad
You should instead be writing something like:
self.myProperty = [[[Something alloc] init] autorelease]; // single, good
Also, with
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
unless you have a
[newObject release];
down the pike, you've got a memory leak.
In my viewDidLoad
self.day19 = [[NSMutableArray alloc] init];
In the myMethod where I want to add objects to the array I:
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
However... when i check the day19 array there is nothing in it. If I conversely add the newObject to a tempArray within the myMethod scope and then set the day19 array to the tempArray, day19 has the objects.
Let me guess: You checked the array with code like this:
NSLog(#"day19 contains %lu objects", [day19 count]);
Remember that a message to nil does nothing and returns nil, 0, or 0.0. That's why the output said 0 objects: You don't have an array in the first place. The most probable reason for that is that viewDidLoad hasn't been called yet, so you have not yet created the mutable array.
It's also possible that you have an array (i.e., the view has been loaded) at the time you examine the array, but you didn't have an array yet (the view hadn't been loaded yet) at the time you tried to add to the array, so your addObject: message fell on deaf ears.
Consider creating the array earlier. You probably should be creating it in init or initWithCoder:.
A third possibility is that you examined the array before you ever added to it. Make sure you log or break at both points, so you know which one happened first.
Whatever the problem is, you also need to either assign the array to the instance variable, not the property, or autorelease the array before assigning it to the property. Otherwise, you're over-retaining the array, which means you will probably leak it later on. You probably need to review the Memory Management Programming Guide for Cocoa.

Deallocating NSMutableArray of custom objects

I need help with deallocation of my NSMutableArray of custom objects. I need to retain the array and so I have added a property in .h and I release it in dealloc in .m file. When I add objects to the array, I do the following:
myarray = [[NSMutableArray alloc] init];
[myarray addObject:[[mycustomObject alloc]initWithObject:obj1]];
[myarray addObject:[[mycustomObject alloc]initWithObject:obj2]];
Now, I don't know how to release mycustomobject. If I do the following:
[myarray addObject:[[[mycustomObject alloc]initWithObject:obj1] autorelease]];
I run in to problems when I access the array later. Please advice.
I don't think you understand how memory management in Cocoa works. The array will retain the objects you add to it, and it will release them by itself when the array no longer needs them (such as when you release the array).
In other words, add the autoreleased object to the array, and don't worry about its retain count after that. If you want to remove it from the array simply remove it (using removeObjectAtIndex: or something similiar). If you think you want to release the object without removing it from the array then you are doing something wrong, since that may leave a dangling pointer in your array that will cause you to crash later.
You should really really go over the documentation again, particularly the section on Object Ownership and Disposal.
The proper way to do this is to let the array maintain ownership of the custom object:
NSMutableArray * array = [[NSMutabelArray alloc] init];
for (id obj in anArrayOfObjects) {
mycustomObject * customObj = [[mycustomObject alloc] initWithObject:obj];
[array addObject:customObj];
[customObj release];
}
If you're having difficulties accessing your array later, then you're doing something wrong with the memory management of the array.